@gtkx/config 2.0.0-beta.1 → 2.0.0-beta.11

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 (70) hide show
  1. package/README.md +11 -166
  2. package/dist/config-dependencies.d.ts +11 -0
  3. package/dist/config-dependencies.d.ts.map +1 -0
  4. package/dist/config-dependencies.js +84 -0
  5. package/dist/config-dependencies.js.map +1 -0
  6. package/dist/config-error.d.ts +2 -2
  7. package/dist/config-error.d.ts.map +1 -1
  8. package/dist/config-error.js +6 -3
  9. package/dist/config-error.js.map +1 -1
  10. package/dist/config-reloader.d.ts +8 -0
  11. package/dist/config-reloader.d.ts.map +1 -0
  12. package/dist/config-reloader.js +38 -0
  13. package/dist/config-reloader.js.map +1 -0
  14. package/dist/config-source.d.ts +7 -0
  15. package/dist/config-source.d.ts.map +1 -0
  16. package/dist/config-source.js +17 -0
  17. package/dist/config-source.js.map +1 -0
  18. package/dist/config.d.ts +42 -38
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/config.js +21 -15
  21. package/dist/config.js.map +1 -1
  22. package/dist/deploy.d.ts +28 -22
  23. package/dist/deploy.d.ts.map +1 -1
  24. package/dist/deploy.js +29 -5
  25. package/dist/deploy.js.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/internal.d.ts +6 -1
  31. package/dist/internal.d.ts.map +1 -1
  32. package/dist/internal.js +6 -1
  33. package/dist/internal.js.map +1 -1
  34. package/dist/loader.d.ts +2 -2
  35. package/dist/loader.d.ts.map +1 -1
  36. package/dist/loader.js +66 -15
  37. package/dist/loader.js.map +1 -1
  38. package/dist/node-version.d.ts +5 -0
  39. package/dist/node-version.d.ts.map +1 -0
  40. package/dist/node-version.js +13 -0
  41. package/dist/node-version.js.map +1 -0
  42. package/dist/static-dependencies.d.ts +3 -0
  43. package/dist/static-dependencies.d.ts.map +1 -0
  44. package/dist/static-dependencies.js +350 -0
  45. package/dist/static-dependencies.js.map +1 -0
  46. package/dist/virtual.d.ts.map +1 -1
  47. package/dist/virtual.js +0 -2
  48. package/dist/virtual.js.map +1 -1
  49. package/dist/vite-plugin.d.ts.map +1 -1
  50. package/dist/vite-plugin.js +14 -5
  51. package/dist/vite-plugin.js.map +1 -1
  52. package/dist/vite-root.d.ts +9 -0
  53. package/dist/vite-root.d.ts.map +1 -0
  54. package/dist/vite-root.js +3 -0
  55. package/dist/vite-root.js.map +1 -0
  56. package/package.json +23 -6
  57. package/src/config-dependencies.ts +116 -0
  58. package/src/config-error.ts +9 -4
  59. package/src/config-reloader.ts +54 -0
  60. package/src/config-source.ts +25 -0
  61. package/src/config.ts +27 -19
  62. package/src/deploy.ts +61 -8
  63. package/src/index.ts +1 -0
  64. package/src/internal.ts +6 -0
  65. package/src/loader.ts +92 -28
  66. package/src/node-version.ts +17 -0
  67. package/src/static-dependencies.ts +464 -0
  68. package/src/virtual.ts +0 -2
  69. package/src/vite-plugin.ts +16 -8
  70. package/src/vite-root.ts +8 -0
package/README.md CHANGED
@@ -1,174 +1,19 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/gtkx-org/gtkx/main/logo.svg" alt="GTKX" width="100" />
3
- </p>
1
+ # @gtkx/config
4
2
 
5
- <h1 align="center">GTKX</h1>
3
+ Typed application configuration for GTKX.
6
4
 
7
- <p align="center">
8
- The React framework for Linux, built on GTK.<br />
9
- Write native GTK4 desktop applications with React and TypeScript.
10
- Real GTK widgets, the GNOME stack, and standard web tooling.
11
- </p>
5
+ Use `defineConfig` in `gtkx.config.ts` to declare the application ID, native libraries, resources, and deployment settings. The CLI loads this configuration for development, code generation, and builds.
12
6
 
13
- <p align="center">
14
- <a href="https://www.npmjs.com/package/create-gtkx"><img src="https://img.shields.io/npm/v/create-gtkx?color=cb3837&logo=npm&label=create-gtkx" alt="npm version" /></a>
15
- <a href="https://www.npmjs.com/package/create-gtkx"><img src="https://img.shields.io/npm/dm/create-gtkx?color=cb3837&logo=npm&label=downloads" alt="npm downloads" /></a>
16
- <img src="https://img.shields.io/badge/node-%E2%89%A526.7-339933?logo=node.js&logoColor=white" alt="Node >= 26.7" />
17
- <a href="https://github.com/gtkx-org/gtkx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MPL--2.0-blue.svg" alt="License: MPL-2.0" /></a>
18
- <a href="https://github.com/gtkx-org/gtkx/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/gtkx-org/gtkx/ci.yml?branch=main&logo=github&label=CI" alt="CI status" /></a>
19
- <img src="https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white" alt="TypeScript" />
20
- </p>
7
+ ```ts
8
+ import { defineConfig } from "@gtkx/config";
21
9
 
22
- <p align="center">
23
- <a href="https://gtkx.dev">Homepage</a> &middot;
24
- <a href="https://gtkx.dev/guide/getting-started">Documentation</a> &middot;
25
- <a href="https://github.com/gtkx-org/gtkx/tree/main/examples">Examples</a> &middot;
26
- <a href="https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md">Contributing</a>
27
- </p>
28
-
29
- ---
30
-
31
- <p align="center">
32
- <img src="https://raw.githubusercontent.com/gtkx-org/gtkx/main/examples/tutorial/assets/screenshot.png" alt="The Tasks app: an Adwaita window with a sidebar of smart views and colored lists on the left, and a boxed task list on the right." />
33
- </p>
34
-
35
- <p align="center">
36
- <em>The Tasks app you build in the <a href="https://gtkx.dev/tutorial/">tutorial</a>.</em>
37
- </p>
38
-
39
- ## Demo
40
-
41
- The intrinsic elements in this snippet render GTK4 widgets, and ordinary React hooks and events drive them:
42
-
43
- ```tsx
44
- import * as Gtk from "@gtkx/gi/gtk";
45
- import { GtkApplication, GtkApplicationWindow, GtkBox, GtkButton, GtkLabel } from "@gtkx/jsx/gtk";
46
- import { createRoot, quit } from "@gtkx/react";
47
- import { useState } from "react";
48
-
49
- const Counter = () => {
50
- const [count, setCount] = useState(0);
51
-
52
- return (
53
- <GtkApplicationWindow
54
- title="Hello GTKX"
55
- defaultWidth={400}
56
- defaultHeight={300}
57
- onCloseRequest={quit}
58
- >
59
- <GtkBox
60
- orientation={Gtk.Orientation.VERTICAL}
61
- spacing={20}
62
- marginTop={40}
63
- marginBottom={40}
64
- marginStart={40}
65
- marginEnd={40}
66
- valign={Gtk.Align.CENTER}
67
- halign={Gtk.Align.CENTER}
68
- >
69
- <GtkLabel cssClasses={["title-1"]}>Welcome to GTKX!</GtkLabel>
70
- <GtkLabel cssClasses={["title-2"]}>{`Count: ${count}`}</GtkLabel>
71
- <GtkButton
72
- label="Increment"
73
- onClicked={() => setCount((c) => c + 1)}
74
- cssClasses={["suggested-action", "pill"]}
75
- />
76
- </GtkBox>
77
- </GtkApplicationWindow>
78
- );
79
- };
80
-
81
- const App = () => (
82
- <GtkApplication>
83
- <Counter />
84
- </GtkApplication>
85
- );
86
-
87
- createRoot().render(<App />);
88
- ```
89
-
90
- This is the [`hello-world`](https://github.com/gtkx-org/gtkx/tree/main/examples/hello-world) example, with `app.tsx` and `index.tsx` combined into a single snippet. `@gtkx/gi` and `@gtkx/jsx` are per-project bindings generated by the CLI, not packages you install from npm.
91
-
92
- ## Why GTKX
93
-
94
- ### A declarative layer for the GNOME stack
95
-
96
- GTK4 is mature, and GtkBuilder XML can lay out a static interface, but nothing re-renders that interface when your application state changes, and nothing hot-reloads it as you work. GTKX adds that missing layer, and the tooling around it, on top of the stack you already know:
97
-
98
- - a React reconciler that exposes every GObject as a JSX element,
99
- - a CLI for scaffolding, development, and production builds,
100
- - a dev server with Fast Refresh that patches your running UI in place,
101
- - CSS-in-JS styling, React Hook Form-powered Adwaita controls, gettext-backed react-i18next localization, React Spring animations, React Navigation stack, tab, drawer, and split view navigators, and high-level list, grid, and dialog components,
102
- - a Testing Library-style API for querying and driving your widgets in tests,
103
- - and a Model Context Protocol (MCP) server that exposes your live app to AI agents.
104
-
105
- ### The full GNOME API surface
106
-
107
- React Native and similar frameworks hide the native toolkit so one API can run everywhere. GTKX exposes it: GTK4, Adwaita, and any other GObject-Introspection library on your system. Linux-only by design.
108
-
109
- ### Why Node.js, and why generated bindings
110
-
111
- GTKX runs on Node.js, which puts native modules, the npm ecosystem, and the tooling built for Node.js APIs within reach. GJS is GNOME's own runtime, built on SpiderMonkey rather than V8; node-gtk runs on Node.js but is lightly maintained, on the older nan/V8 ABI rather than N-API, and still centered on GTK3. The [Why GTKX guide](https://gtkx.dev/guide/why-gtkx) covers what running on Node.js means day to day.
112
-
113
- GTKX generates the TypeScript types and the native FFI calls from the same GObject-Introspection data, so the types cannot drift from the calls they back. Codegen covers the whole GTK4 and Adwaita surface.
114
-
115
- At runtime, the native Rust core calls straight into the system GTK4, Adwaita, and GLib libraries through libffi, without loading libgirepository at all.
116
-
117
- ## Quick start
118
-
119
- GTKX is Linux-only and needs Node.js 26.7 or later. See [Requirements](#requirements).
120
-
121
- Scaffold a new app with the `create-gtkx` initializer:
122
-
123
- ```sh
124
- npm create gtkx
10
+ export default defineConfig({
11
+ applicationId: "com.example.MyApp",
12
+ });
125
13
  ```
126
14
 
127
- The same command works with other package managers: `pnpm create gtkx` or `yarn create gtkx`.
128
-
129
- Then run your new app:
130
-
131
- ```sh
132
- cd my-app
133
- npm run dev
134
- ```
135
-
136
- To go further, follow the [tutorial](https://gtkx.dev/tutorial/).
137
-
138
- ## Documentation
139
-
140
- The documentation at **[gtkx.dev](https://gtkx.dev)** includes a step-by-step tutorial that builds a complete GNOME app, from scaffolding to packaging and shipping, plus guides and a full API reference.
141
-
142
- **[Read the docs &rarr;](https://gtkx.dev/guide/why-gtkx)**
143
-
144
- ## Requirements
145
-
146
- GTKX is Linux-only. You need:
147
-
148
- - Linux with the GTK4 (4.20 or later), Adwaita (1.8 or later), and GLib development libraries
149
- - Node.js 26.7 or later
150
-
151
- The `@gtkx/native` addon ships prebuilt for x64 and arm64 glibc Linux; other targets need to build it from the GTKX repository, which requires a Rust toolchain.
152
-
153
- ## Examples
154
-
155
- Explore the [example apps](https://github.com/gtkx-org/gtkx/tree/main/examples):
156
-
157
- - [`hello-world`](https://github.com/gtkx-org/gtkx/tree/main/examples/hello-world): the counter above.
158
- - [`gtk-demo`](https://github.com/gtkx-org/gtkx/tree/main/examples/gtk-demo): a React port of the official GTK4 widget showcase, covering lists, dialogs, gestures, CSS, and OpenGL.
159
- - [`browser`](https://github.com/gtkx-org/gtkx/tree/main/examples/browser): a WebKitWebView-based web browser.
160
- - [`animations`](https://github.com/gtkx-org/gtkx/tree/main/examples/animations): a tour of `@gtkx/animated`, React Spring animations driven by the GTK frame clock.
161
- - [`navigation`](https://github.com/gtkx-org/gtkx/tree/main/examples/navigation): a tour of `@gtkx/navigation`, React Navigation's stack, tab, and drawer navigators rendered with libadwaita.
162
- - [`tutorial`](https://github.com/gtkx-org/gtkx/tree/main/examples/tutorial): the Tasks app the documentation builds.
163
-
164
- ## Status
165
-
166
- GTKX is stable and ready for production use.
167
-
168
- ## Contributing
169
-
170
- Contributions are welcome. See [CONTRIBUTING.md](https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md), the [Code of Conduct](https://github.com/gtkx-org/gtkx/blob/main/CODE_OF_CONDUCT.md), and the [security policy](https://github.com/gtkx-org/gtkx/blob/main/SECURITY.md). Building the repo needs Node.js 26.7 or later, pnpm, and a Rust toolchain.
15
+ [Guide](https://gtkx.dev/v2/guide/configuration-and-codegen) · [API reference](https://gtkx.dev/v2/reference/@gtkx/config/) · [GTKX](https://gtkx.dev)
171
16
 
172
- ## License
17
+ GTKX runs on Linux with Node.js and system native libraries. See [Getting Started](https://gtkx.dev/v2/guide/getting-started) for supported versions and installation. This README describes the 2.0 beta.
173
18
 
174
- GTKX is licensed under [MPL-2.0](https://github.com/gtkx-org/gtkx/blob/main/LICENSE).
19
+ [MPL-2.0](https://github.com/gtkx-org/gtkx/blob/main/LICENSE).
@@ -0,0 +1,11 @@
1
+ import { type TransformOptions, type TransformResult } from "jiti";
2
+ type CapturedConfig<T> = {
3
+ dependencies: string[];
4
+ value: T;
5
+ };
6
+ declare const transformConfigModule: (options: TransformOptions) => TransformResult;
7
+ declare const setConfigDependencies: (value: object, dependencies: Iterable<string>) => void;
8
+ declare const configDependenciesFor: (value: unknown) => string[];
9
+ declare const captureConfigDependencies: <T>(operation: () => Promise<T>) => Promise<CapturedConfig<T>>;
10
+ export { captureConfigDependencies, configDependenciesFor, setConfigDependencies, transformConfigModule, };
11
+ //# sourceMappingURL=config-dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-dependencies.d.ts","sourceRoot":"","sources":["../src/config-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,MAAM,CAAC;AAO1F,KAAK,cAAc,CAAC,CAAC,IAAI;IAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAyD9D,QAAA,MAAM,qBAAqB,GAAI,SAAS,gBAAgB,KAAG,eAY1D,CAAC;AAEF,QAAA,MAAM,qBAAqB,GAAI,OAAO,MAAM,EAAE,cAAc,QAAQ,CAAC,MAAM,CAAC,KAAG,IAI9E,CAAC;AAEF,QAAA,MAAM,qBAAqB,GAAI,OAAO,OAAO,KAAG,MAAM,EACqC,CAAC;AAE5F,QAAA,MAAM,yBAAyB,GAAU,CAAC,EAAE,WAAW,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAqBlG,CAAC;AAEF,OAAO,EACH,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,GACxB,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { createJiti } from "jiti";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { createRequire, registerHooks } from "node:module";
4
+ import { extname, sep } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ const captureStorage = new AsyncLocalStorage();
7
+ const dependenciesByValue = new WeakMap();
8
+ const CACHE_BUSTED_EXTENSIONS = new Set([".cjs", ".js", ".json", ".mjs"]);
9
+ const isTrackedPath = (path) => !path.includes(`${sep}node_modules${sep}`);
10
+ const addPath = (path) => {
11
+ if (isTrackedPath(path)) {
12
+ captureStorage.getStore()?.dependencies.add(path);
13
+ }
14
+ };
15
+ const addUrl = (url) => {
16
+ if (url.startsWith("file:")) {
17
+ addPath(fileURLToPath(url));
18
+ }
19
+ };
20
+ const cacheBustedUrl = (url) => {
21
+ const state = captureStorage.getStore();
22
+ if (state === undefined || !url.startsWith("file:")) {
23
+ return url;
24
+ }
25
+ const path = fileURLToPath(url);
26
+ if (!isTrackedPath(path) || !CACHE_BUSTED_EXTENSIONS.has(extname(path))) {
27
+ return url;
28
+ }
29
+ const parsed = new URL(url);
30
+ parsed.searchParams.set("gtkx-config-load", state.cacheKey);
31
+ return parsed.href;
32
+ };
33
+ const registerResolutionHook = () => registerHooks({
34
+ resolve(specifier, context, nextResolve) {
35
+ const result = nextResolve(specifier, context);
36
+ addUrl(result.url);
37
+ return { ...result, url: cacheBustedUrl(result.url) };
38
+ },
39
+ });
40
+ const clearNativeModuleCache = (dependencies) => {
41
+ const cache = createRequire(import.meta.url).cache;
42
+ for (const path of dependencies) {
43
+ Reflect.deleteProperty(cache, path);
44
+ }
45
+ };
46
+ const transformConfigModule = (options) => {
47
+ const state = captureStorage.getStore();
48
+ if (state === undefined) {
49
+ throw new Error("Configuration transformation started outside a dependency capture");
50
+ }
51
+ if (options.filename !== undefined) {
52
+ addPath(options.filename);
53
+ }
54
+ return { code: state.transformer.transform(options) };
55
+ };
56
+ const setConfigDependencies = (value, dependencies) => {
57
+ const paths = [...new Set(dependencies)];
58
+ dependenciesByValue.set(value, paths);
59
+ clearNativeModuleCache(paths);
60
+ };
61
+ const configDependenciesFor = (value) => typeof value === "object" && value !== null ? dependenciesByValue.get(value) ?? [] : [];
62
+ const captureConfigDependencies = async (operation) => {
63
+ const state = {
64
+ cacheKey: process.hrtime.bigint().toString(),
65
+ dependencies: new Set(),
66
+ transformer: createJiti(import.meta.url, { fsCache: false, moduleCache: false }),
67
+ };
68
+ const hook = registerResolutionHook();
69
+ try {
70
+ const value = await captureStorage.run(state, operation);
71
+ return { dependencies: [...state.dependencies], value };
72
+ }
73
+ catch (error) {
74
+ if (typeof error === "object" && error !== null) {
75
+ setConfigDependencies(error, state.dependencies);
76
+ }
77
+ throw error;
78
+ }
79
+ finally {
80
+ hook.deregister();
81
+ }
82
+ };
83
+ export { captureConfigDependencies, configDependenciesFor, setConfigDependencies, transformConfigModule, };
84
+ //# sourceMappingURL=config-dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-dependencies.js","sourceRoot":"","sources":["../src/config-dependencies.ts"],"names":[],"mappings":"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","sourcesContent":["import { createJiti, type Jiti, type TransformOptions, type TransformResult } from \"jiti\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { createRequire, registerHooks } from \"node:module\";\nimport { extname, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\ntype CaptureState = { cacheKey: string; dependencies: Set<string>; transformer: Jiti };\ntype CapturedConfig<T> = { dependencies: string[]; value: T };\n\nconst captureStorage: AsyncLocalStorage<CaptureState> = new AsyncLocalStorage();\nconst dependenciesByValue: WeakMap<object, string[]> = new WeakMap();\nconst CACHE_BUSTED_EXTENSIONS: ReadonlySet<string> = new Set([\".cjs\", \".js\", \".json\", \".mjs\"]);\n\nconst isTrackedPath = (path: string): boolean => !path.includes(`${sep}node_modules${sep}`);\n\nconst addPath = (path: string): void => {\n if (isTrackedPath(path)) {\n captureStorage.getStore()?.dependencies.add(path);\n }\n};\n\nconst addUrl = (url: string): void => {\n if (url.startsWith(\"file:\")) {\n addPath(fileURLToPath(url));\n }\n};\n\nconst cacheBustedUrl = (url: string): string => {\n const state = captureStorage.getStore();\n\n if (state === undefined || !url.startsWith(\"file:\")) {\n return url;\n }\n\n const path = fileURLToPath(url);\n\n if (!isTrackedPath(path) || !CACHE_BUSTED_EXTENSIONS.has(extname(path))) {\n return url;\n }\n\n const parsed = new URL(url);\n parsed.searchParams.set(\"gtkx-config-load\", state.cacheKey);\n\n return parsed.href;\n};\n\nconst registerResolutionHook = (): ReturnType<typeof registerHooks> =>\n registerHooks({\n resolve(specifier, context, nextResolve) {\n const result = nextResolve(specifier, context);\n addUrl(result.url);\n\n return { ...result, url: cacheBustedUrl(result.url) };\n },\n });\n\nconst clearNativeModuleCache = (dependencies: Iterable<string>): void => {\n const cache = createRequire(import.meta.url).cache;\n\n for (const path of dependencies) {\n Reflect.deleteProperty(cache, path);\n }\n};\n\nconst transformConfigModule = (options: TransformOptions): TransformResult => {\n const state = captureStorage.getStore();\n\n if (state === undefined) {\n throw new Error(\"Configuration transformation started outside a dependency capture\");\n }\n\n if (options.filename !== undefined) {\n addPath(options.filename);\n }\n\n return { code: state.transformer.transform(options) };\n};\n\nconst setConfigDependencies = (value: object, dependencies: Iterable<string>): void => {\n const paths = [...new Set(dependencies)];\n dependenciesByValue.set(value, paths);\n clearNativeModuleCache(paths);\n};\n\nconst configDependenciesFor = (value: unknown): string[] =>\n typeof value === \"object\" && value !== null ? dependenciesByValue.get(value) ?? [] : [];\n\nconst captureConfigDependencies = async <T>(operation: () => Promise<T>): Promise<CapturedConfig<T>> => {\n const state: CaptureState = {\n cacheKey: process.hrtime.bigint().toString(),\n dependencies: new Set(),\n transformer: createJiti(import.meta.url, { fsCache: false, moduleCache: false }),\n };\n const hook = registerResolutionHook();\n\n try {\n const value = await captureStorage.run(state, operation);\n\n return { dependencies: [...state.dependencies], value };\n } catch (error) {\n if (typeof error === \"object\" && error !== null) {\n setConfigDependencies(error, state.dependencies);\n }\n\n throw error;\n } finally {\n hook.deregister();\n }\n};\n\nexport {\n captureConfigDependencies,\n configDependenciesFor,\n setConfigDependencies,\n transformConfigModule,\n};\n"]}
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  declare const isRecord: (value: unknown) => value is Record<string, unknown>;
3
- declare const missingConfigFileError: (cwd: string) => Error;
4
- declare const configError: (error: z.ZodError) => Error;
3
+ declare const missingConfigFileError: (cwd: string, configFile?: string) => Error;
4
+ declare const configError: (error: z.ZodError, configFile?: string) => Error;
5
5
  export { isRecord, missingConfigFileError, configError };
6
6
  //# sourceMappingURL=config-error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-error.d.ts","sourceRoot":"","sources":["../src/config-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACM,CAAC;AAEzE,QAAA,MAAM,sBAAsB,GAAI,KAAK,MAAM,KAAG,KACyB,CAAC;AAExE,QAAA,MAAM,WAAW,GAAI,OAAO,CAAC,CAAC,QAAQ,KAAG,KAAiE,CAAC;AAE3G,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"config-error.d.ts","sourceRoot":"","sources":["../src/config-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACM,CAAC;AAIzE,QAAA,MAAM,sBAAsB,GAAI,KAAK,MAAM,EAAE,aAAa,MAAM,KAAG,KAGW,CAAC;AAE/E,QAAA,MAAM,WAAW,GAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,mBAAgC,KAAG,KACJ,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,WAAW,EAAE,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import { z } from "zod";
2
- const CONFIG_PREFIX = "gtkx.config.ts:";
2
+ const DEFAULT_CONFIG_FILE = "gtkx.config.*";
3
3
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4
- const missingConfigFileError = (cwd) => new Error(`${CONFIG_PREFIX} no configuration file found in ${cwd}`);
5
- const configError = (error) => new Error(`${CONFIG_PREFIX}\n${z.prettifyError(error)}`);
4
+ const configPrefix = (configFile) => `${configFile}:`;
5
+ const missingConfigFileError = (cwd, configFile) => new Error(configFile === undefined
6
+ ? `${configPrefix(DEFAULT_CONFIG_FILE)} no configuration file found in ${cwd}`
7
+ : `${configPrefix(configFile)} no configuration file found in ${cwd}`);
8
+ const configError = (error, configFile = DEFAULT_CONFIG_FILE) => new Error(`${configPrefix(configFile)}\n${z.prettifyError(error)}`);
6
9
  export { isRecord, missingConfigFileError, configError };
7
10
  //# sourceMappingURL=config-error.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-error.js","sourceRoot":"","sources":["../src/config-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAExC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CAClE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEzE,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAAS,EAAE,CAClD,IAAI,KAAK,CAAC,GAAG,aAAa,mCAAmC,GAAG,EAAE,CAAC,CAAC;AAExE,MAAM,WAAW,GAAG,CAAC,KAAiB,EAAS,EAAE,CAAC,IAAI,KAAK,CAAC,GAAG,aAAa,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAE3G,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,WAAW,EAAE,CAAC","sourcesContent":["import { z } from \"zod\";\n\nconst CONFIG_PREFIX = \"gtkx.config.ts:\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst missingConfigFileError = (cwd: string): Error =>\n new Error(`${CONFIG_PREFIX} no configuration file found in ${cwd}`);\n\nconst configError = (error: z.ZodError): Error => new Error(`${CONFIG_PREFIX}\\n${z.prettifyError(error)}`);\n\nexport { isRecord, missingConfigFileError, configError };\n"]}
1
+ {"version":3,"file":"config-error.js","sourceRoot":"","sources":["../src/config-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAE5C,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CAClE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEzE,MAAM,YAAY,GAAG,CAAC,UAAkB,EAAU,EAAE,CAAC,GAAG,UAAU,GAAG,CAAC;AAEtE,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAAE,UAAmB,EAAS,EAAE,CACvE,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;IAC9B,CAAC,CAAC,GAAG,YAAY,CAAC,mBAAmB,CAAC,mCAAmC,GAAG,EAAE;IAC9E,CAAC,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAC;AAE/E,MAAM,WAAW,GAAG,CAAC,KAAiB,EAAE,UAAU,GAAG,mBAAmB,EAAS,EAAE,CAC/E,IAAI,KAAK,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,WAAW,EAAE,CAAC","sourcesContent":["import { z } from \"zod\";\n\nconst DEFAULT_CONFIG_FILE = \"gtkx.config.*\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst configPrefix = (configFile: string): string => `${configFile}:`;\n\nconst missingConfigFileError = (cwd: string, configFile?: string): Error =>\n new Error(configFile === undefined\n ? `${configPrefix(DEFAULT_CONFIG_FILE)} no configuration file found in ${cwd}`\n : `${configPrefix(configFile)} no configuration file found in ${cwd}`);\n\nconst configError = (error: z.ZodError, configFile = DEFAULT_CONFIG_FILE): Error =>\n new Error(`${configPrefix(configFile)}\\n${z.prettifyError(error)}`);\n\nexport { isRecord, missingConfigFileError, configError };\n"]}
@@ -0,0 +1,8 @@
1
+ import { type LoadConfigOptions, type LoadedConfig } from "./loader.ts";
2
+ type ConfigReloader = {
3
+ reload: () => Promise<LoadedConfig>;
4
+ resolvePaths: () => string[];
5
+ };
6
+ declare const createConfigReloader: (cwd: string, options?: LoadConfigOptions, initialDependencies?: string[]) => Promise<ConfigReloader>;
7
+ export { createConfigReloader };
8
+ //# sourceMappingURL=config-reloader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-reloader.d.ts","sourceRoot":"","sources":["../src/config-reloader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAGpF,KAAK,cAAc,GAAG;IAClB,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IACpC,YAAY,EAAE,MAAM,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,QAAA,MAAM,oBAAoB,GACtB,KAAK,MAAM,EACX,UAAS,iBAAsB,EAC/B,sBAAqB,MAAM,EAAO,KACnC,OAAO,CAAC,cAAc,CAqCxB,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { relative, resolve } from "node:path";
2
+ import { configDependenciesFor } from "./config-dependencies.js";
3
+ import { loadConfig } from "./loader.js";
4
+ import { resolveConfigDependencies } from "./static-dependencies.js";
5
+ const createConfigReloader = async (cwd, options = {}, initialDependencies = []) => {
6
+ let selectedConfigFile;
7
+ let knownDependencies = initialDependencies;
8
+ if (options.configFile === undefined) {
9
+ const loaded = await loadConfig(cwd, options);
10
+ selectedConfigFile = loaded.configFile;
11
+ knownDependencies = [...knownDependencies, ...configDependenciesFor(loaded)];
12
+ }
13
+ else {
14
+ selectedConfigFile = resolve(cwd, options.configFile);
15
+ }
16
+ const selectedConfigName = relative(cwd, selectedConfigFile);
17
+ const resolvePaths = () => [
18
+ ...new Set([selectedConfigFile, ...knownDependencies]
19
+ .flatMap((path) => resolveConfigDependencies(path, selectedConfigName, cwd))),
20
+ ];
21
+ return {
22
+ resolvePaths,
23
+ reload: async () => {
24
+ let loaded;
25
+ try {
26
+ loaded = await loadConfig(cwd, { ...options, configFile: selectedConfigFile });
27
+ }
28
+ catch (error) {
29
+ knownDependencies = [...new Set([...knownDependencies, ...configDependenciesFor(error)])];
30
+ throw error;
31
+ }
32
+ knownDependencies = configDependenciesFor(loaded);
33
+ return loaded;
34
+ },
35
+ };
36
+ };
37
+ export { createConfigReloader };
38
+ //# sourceMappingURL=config-reloader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-reloader.js","sourceRoot":"","sources":["../src/config-reloader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAA6C,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAOrE,MAAM,oBAAoB,GAAG,KAAK,EAC9B,GAAW,EACX,UAA6B,EAAE,EAC/B,sBAAgC,EAAE,EACX,EAAE;IACzB,IAAI,kBAA0B,CAAC;IAC/B,IAAI,iBAAiB,GAAG,mBAAmB,CAAC;IAE5C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC9C,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC;QACvC,iBAAiB,GAAG,CAAC,GAAG,iBAAiB,EAAE,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC;IACjF,CAAC;SAAM,CAAC;QACJ,kBAAkB,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,kBAAkB,GAAG,QAAQ,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,GAAa,EAAE,CAAC;QACjC,GAAG,IAAI,GAAG,CACN,CAAC,kBAAkB,EAAE,GAAG,iBAAiB,CAAC;aACrC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,yBAAyB,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC,CACnF;KACJ,CAAC;IAEF,OAAO;QACH,YAAY;QACZ,MAAM,EAAE,KAAK,IAAI,EAAE;YACf,IAAI,MAAoB,CAAC;YAEzB,IAAI,CAAC;gBACD,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACnF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,iBAAiB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,iBAAiB,EAAE,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1F,MAAM,KAAK,CAAC;YAChB,CAAC;YAED,iBAAiB,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAElD,OAAO,MAAM,CAAC;QAClB,CAAC;KACJ,CAAC;AACN,CAAC,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC","sourcesContent":["import { relative, resolve } from \"node:path\";\nimport { configDependenciesFor } from \"./config-dependencies.ts\";\nimport { loadConfig, type LoadConfigOptions, type LoadedConfig } from \"./loader.ts\";\nimport { resolveConfigDependencies } from \"./static-dependencies.ts\";\n\ntype ConfigReloader = {\n reload: () => Promise<LoadedConfig>;\n resolvePaths: () => string[];\n};\n\nconst createConfigReloader = async (\n cwd: string,\n options: LoadConfigOptions = {},\n initialDependencies: string[] = [],\n): Promise<ConfigReloader> => {\n let selectedConfigFile: string;\n let knownDependencies = initialDependencies;\n\n if (options.configFile === undefined) {\n const loaded = await loadConfig(cwd, options);\n selectedConfigFile = loaded.configFile;\n knownDependencies = [...knownDependencies, ...configDependenciesFor(loaded)];\n } else {\n selectedConfigFile = resolve(cwd, options.configFile);\n }\n\n const selectedConfigName = relative(cwd, selectedConfigFile);\n const resolvePaths = (): string[] => [\n ...new Set(\n [selectedConfigFile, ...knownDependencies]\n .flatMap((path) => resolveConfigDependencies(path, selectedConfigName, cwd)),\n ),\n ];\n\n return {\n resolvePaths,\n reload: async () => {\n let loaded: LoadedConfig;\n\n try {\n loaded = await loadConfig(cwd, { ...options, configFile: selectedConfigFile });\n } catch (error) {\n knownDependencies = [...new Set([...knownDependencies, ...configDependenciesFor(error)])];\n throw error;\n }\n\n knownDependencies = configDependenciesFor(loaded);\n\n return loaded;\n },\n };\n};\n\nexport { createConfigReloader };\n"]}
@@ -0,0 +1,7 @@
1
+ type ConfigResolutionOptions = {
2
+ configFile?: string | undefined;
3
+ cwd?: string | undefined;
4
+ };
5
+ declare const localConfigSourcePath: (source: string, options: ConfigResolutionOptions) => string | undefined;
6
+ export { localConfigSourcePath, type ConfigResolutionOptions };
7
+ //# sourceMappingURL=config-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-source.d.ts","sourceRoot":"","sources":["../src/config-source.ts"],"names":[],"mappings":"AAEA,KAAK,uBAAuB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAU7F,QAAA,MAAM,qBAAqB,GAAI,QAAQ,MAAM,EAAE,SAAS,uBAAuB,KAAG,MAAM,GAAG,SAU1F,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { basename, extname, isAbsolute, resolve } from "node:path";
2
+ const isLocalConfigSource = (source) => source.startsWith(".") || isAbsolute(source);
3
+ const isDirectoryConfigSource = (source) => {
4
+ const extension = extname(source);
5
+ return extension.length === 0 || extension === basename(source);
6
+ };
7
+ const localConfigSourcePath = (source, options) => {
8
+ if (source === "." || !isLocalConfigSource(source)) {
9
+ return undefined;
10
+ }
11
+ const cwd = options.cwd ?? process.cwd();
12
+ return isDirectoryConfigSource(source)
13
+ ? resolve(cwd, source, options.configFile ?? "gtkx.config")
14
+ : resolve(cwd, source);
15
+ };
16
+ export { localConfigSourcePath };
17
+ //# sourceMappingURL=config-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-source.js","sourceRoot":"","sources":["../src/config-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAInE,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAEtG,MAAM,uBAAuB,GAAG,CAAC,MAAc,EAAW,EAAE;IACxD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAElC,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC;AACpE,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,MAAc,EAAE,OAAgC,EAAsB,EAAE;IACnG,IAAI,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEzC,OAAO,uBAAuB,CAAC,MAAM,CAAC;QAClC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC;QAC3D,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAgC,CAAC","sourcesContent":["import { basename, extname, isAbsolute, resolve } from \"node:path\";\n\ntype ConfigResolutionOptions = { configFile?: string | undefined; cwd?: string | undefined };\n\nconst isLocalConfigSource = (source: string): boolean => source.startsWith(\".\") || isAbsolute(source);\n\nconst isDirectoryConfigSource = (source: string): boolean => {\n const extension = extname(source);\n\n return extension.length === 0 || extension === basename(source);\n};\n\nconst localConfigSourcePath = (source: string, options: ConfigResolutionOptions): string | undefined => {\n if (source === \".\" || !isLocalConfigSource(source)) {\n return undefined;\n }\n\n const cwd = options.cwd ?? process.cwd();\n\n return isDirectoryConfigSource(source)\n ? resolve(cwd, source, options.configFile ?? \"gtkx.config\")\n : resolve(cwd, source);\n};\n\nexport { localConfigSourcePath, type ConfigResolutionOptions };\n"]}
package/dist/config.d.ts CHANGED
@@ -16,13 +16,11 @@ type ResolvedReactCompilerOptions = ReactCompilerOptions & {
16
16
  target: "19";
17
17
  };
18
18
  /**
19
- * User-facing configuration for a GTKX project, as authored in `gtkx.config.ts`: the GIR libraries
20
- * to bind and where to find them, the GApplication id, per-element configuration, the React
21
- * Compiler, codegen, and user event signal settings, and the `agents` and `mcp` blocks controlling
22
- * what coding agents are given.
19
+ * GTKX project configuration authored in `gtkx.config.ts` and validated when loaded.
23
20
  */
24
21
  type Config = z.infer<typeof configSchema>;
25
22
  type ModuleExport = z.infer<typeof moduleExportSchema>;
23
+ type ElementPropsExport = z.infer<typeof elementPropsSchema>;
26
24
  type McpSettings = {
27
25
  tools: string[];
28
26
  isReadOnly: boolean;
@@ -51,7 +49,16 @@ declare const PANIC_THRESHOLDS: readonly ["none", "critical_errors", "all_errors
51
49
  declare const moduleExportSchema: z.ZodObject<{
52
50
  module: z.ZodString;
53
51
  export: z.ZodString;
54
- }, z.core.$strip>;
52
+ }, z.core.$strict>;
53
+ declare const elementPropsSchema: z.ZodObject<{
54
+ module: z.ZodString;
55
+ export: z.ZodString;
56
+ composition: z.ZodOptional<z.ZodEnum<{
57
+ intersection: "intersection";
58
+ factory: "factory";
59
+ }>>;
60
+ constructOnly: z.ZodOptional<z.ZodArray<z.ZodString>>;
61
+ }, z.core.$strict>;
55
62
  /** Schema every `gtkx.config.ts` is validated against, and the source of the {@link Config} type. */
56
63
  declare const configSchema: z.ZodObject<{
57
64
  libraries: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -69,7 +76,7 @@ declare const configSchema: z.ZodObject<{
69
76
  critical_errors: "critical_errors";
70
77
  all_errors: "all_errors";
71
78
  }>>;
72
- }, z.core.$strip>]>>;
79
+ }, z.core.$strict>]>>;
73
80
  codegen: z.ZodOptional<z.ZodBoolean>;
74
81
  userEventSignals: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
75
82
  elements: z.ZodOptional<z.ZodObject<{
@@ -78,15 +85,21 @@ declare const configSchema: z.ZodObject<{
78
85
  component: z.ZodOptional<z.ZodObject<{
79
86
  module: z.ZodString;
80
87
  export: z.ZodString;
81
- }, z.core.$strip>>;
88
+ }, z.core.$strict>>;
82
89
  props: z.ZodOptional<z.ZodObject<{
83
90
  module: z.ZodString;
84
91
  export: z.ZodString;
85
- }, z.core.$strip>>;
92
+ composition: z.ZodOptional<z.ZodEnum<{
93
+ intersection: "intersection";
94
+ factory: "factory";
95
+ }>>;
96
+ constructOnly: z.ZodOptional<z.ZodArray<z.ZodString>>;
97
+ }, z.core.$strict>>;
86
98
  isLazy: z.ZodOptional<z.ZodBoolean>;
99
+ acceptedChildTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
87
100
  omittedProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
88
- }, z.core.$strip>>>;
89
- }, z.core.$strip>>;
101
+ }, z.core.$strict>>>;
102
+ }, z.core.$strict>>;
90
103
  applicationIcon: z.ZodOptional<z.ZodString>;
91
104
  deploy: z.ZodOptional<z.ZodObject<{
92
105
  targets: z.ZodOptional<z.ZodArray<z.ZodEnum<{
@@ -95,6 +108,10 @@ declare const configSchema: z.ZodObject<{
95
108
  flatpak: "flatpak";
96
109
  rpm: "rpm";
97
110
  }>>>;
111
+ architectures: z.ZodOptional<z.ZodArray<z.ZodEnum<{
112
+ arm64: "arm64";
113
+ x64: "x64";
114
+ }>>>;
98
115
  outDir: z.ZodOptional<z.ZodString>;
99
116
  name: z.ZodOptional<z.ZodString>;
100
117
  genericName: z.ZodOptional<z.ZodString>;
@@ -162,6 +179,8 @@ declare const configSchema: z.ZodObject<{
162
179
  url: z.ZodOptional<z.ZodURL>;
163
180
  }, z.core.$strict>>>;
164
181
  execArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
182
+ launcherEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
183
+ nodeFlags: z.ZodOptional<z.ZodArray<z.ZodString>>;
165
184
  fileAssociations: z.ZodOptional<z.ZodArray<z.ZodObject<{
166
185
  extension: z.ZodString;
167
186
  mimeType: z.ZodString;
@@ -174,11 +193,9 @@ declare const configSchema: z.ZodObject<{
174
193
  icon: z.ZodOptional<z.ZodString>;
175
194
  }, z.core.$strict>>>;
176
195
  desktopEntry: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
196
+ metainfoExtra: z.ZodOptional<z.ZodArray<z.ZodString>>;
177
197
  isDbusActivatable: z.ZodOptional<z.ZodBoolean>;
178
- extraFiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
179
- source: z.ZodString;
180
- mode: z.ZodOptional<z.ZodString>;
181
- }, z.core.$strict>]>>>;
198
+ extraFiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodType<import("./deploy.ts").DeployExtraFileOptions, unknown, z.core.$ZodTypeInternals<import("./deploy.ts").DeployExtraFileOptions, unknown>>]>>>;
182
199
  minimumLibraryVersions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
183
200
  depends: z.ZodOptional<z.ZodObject<{
184
201
  deb: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -220,17 +237,7 @@ declare const configSchema: z.ZodObject<{
220
237
  preRemove: z.ZodOptional<z.ZodString>;
221
238
  postRemove: z.ZodOptional<z.ZodString>;
222
239
  }, z.core.$strict>>;
223
- node: z.ZodOptional<z.ZodObject<{
224
- source: z.ZodOptional<z.ZodEnum<{
225
- path: "path";
226
- download: "download";
227
- host: "host";
228
- }>>;
229
- version: z.ZodOptional<z.ZodString>;
230
- path: z.ZodOptional<z.ZodString>;
231
- shouldStrip: z.ZodOptional<z.ZodBoolean>;
232
- shouldUseCompileCache: z.ZodOptional<z.ZodBoolean>;
233
- }, z.core.$strict>>;
240
+ node: z.ZodOptional<z.ZodType<import("./deploy.ts").DeployNodeOptions, unknown, z.core.$ZodTypeInternals<import("./deploy.ts").DeployNodeOptions, unknown>>>;
234
241
  signing: z.ZodOptional<z.ZodObject<{
235
242
  appimage: z.ZodOptional<z.ZodObject<{
236
243
  gpgKeyId: z.ZodString;
@@ -260,11 +267,7 @@ declare const configSchema: z.ZodObject<{
260
267
  }, z.core.$strict>>;
261
268
  appimage: z.ZodOptional<z.ZodObject<{
262
269
  fileName: z.ZodOptional<z.ZodString>;
263
- compression: z.ZodOptional<z.ZodEnum<{
264
- gzip: "gzip";
265
- xz: "xz";
266
- zstd: "zstd";
267
- }>>;
270
+ compression: z.ZodOptional<z.ZodLiteral<"zstd">>;
268
271
  updateInformation: z.ZodOptional<z.ZodString>;
269
272
  runtimeFile: z.ZodOptional<z.ZodString>;
270
273
  }, z.core.$strict>>;
@@ -274,9 +277,9 @@ declare const configSchema: z.ZodObject<{
274
277
  priority: z.ZodOptional<z.ZodString>;
275
278
  compression: z.ZodOptional<z.ZodEnum<{
276
279
  gzip: "gzip";
280
+ none: "none";
277
281
  xz: "xz";
278
282
  zstd: "zstd";
279
- none: "none";
280
283
  }>>;
281
284
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
282
285
  }, z.core.$strict>>;
@@ -328,22 +331,22 @@ declare const configSchema: z.ZodObject<{
328
331
  agents: z.ZodOptional<z.ZodObject<{
329
332
  rules: z.ZodOptional<z.ZodBoolean>;
330
333
  reference: z.ZodOptional<z.ZodBoolean>;
331
- }, z.core.$strip>>;
334
+ }, z.core.$strict>>;
332
335
  mcp: z.ZodOptional<z.ZodObject<{
333
336
  tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
334
337
  readOnly: z.ZodOptional<z.ZodBoolean>;
335
- }, z.core.$strip>>;
338
+ }, z.core.$strict>>;
336
339
  deprecations: z.ZodOptional<z.ZodObject<{
337
340
  silence: z.ZodOptional<z.ZodArray<z.ZodNever>>;
338
- }, z.core.$strip>>;
339
- }, z.core.$strip>;
341
+ }, z.core.$strict>>;
342
+ }, z.core.$strict>;
340
343
  /**
341
344
  * Returns the given configuration unchanged, typed as {@link Config}, so `gtkx.config.ts` gets
342
345
  * autocompletion and type checking.
343
346
  */
344
347
  declare const defineConfig: DefineConfig<Config>;
345
348
  declare const isValidApplicationId: (applicationId: string) => boolean;
346
- declare const validateConfig: (config: unknown) => void;
349
+ declare const validateConfig: (config: unknown, configFile?: string) => void;
347
350
  declare const graduatedFutureKeys: (config: unknown) => string[];
348
351
  /**
349
352
  * Deep-merges a configuration over a base. `override` wins over `base` on conflicting scalar and object keys, while
@@ -352,11 +355,12 @@ declare const graduatedFutureKeys: (config: unknown) => string[];
352
355
  declare const mergeConfig: (base: Config, override: Config) => Config;
353
356
  declare const resolveLazyElements: (elements: Config["elements"]) => string[];
354
357
  declare const resolveElementComponents: (elements: Config["elements"]) => Record<string, ModuleExport>;
355
- declare const resolveElementProps: (elements: Config["elements"]) => Record<string, ModuleExport>;
358
+ declare const resolveElementProps: (elements: Config["elements"]) => Record<string, ElementPropsExport>;
359
+ declare const resolveAcceptedChildTypes: (elements: Config["elements"]) => Record<string, string[]>;
356
360
  declare const resolveOmittedProps: (elements: Config["elements"]) => Record<string, string[]>;
357
361
  declare const isAgentRulesEnabled: (config: Config) => boolean;
358
362
  declare const isAgentReferenceEnabled: (config: Config) => boolean;
359
363
  declare const resolveMcpSettings: (config: Config) => McpSettings;
360
364
  declare const resolveConfig: (config: Config, root?: string) => ResolvedConfig;
361
- export { APPLICATION_ID_MAX_LENGTH, defineConfig, isAgentReferenceEnabled, isAgentRulesEnabled, isValidApplicationId, graduatedFutureKeys, validateConfig, mergeConfig, resolveLazyElements, resolveElementComponents, resolveElementProps, resolveMcpSettings, resolveOmittedProps, resolveConfig, type McpSettings, type ResolvedReactCompilerOptions, type Config, type ResolvedConfig, };
365
+ export { APPLICATION_ID_MAX_LENGTH, defineConfig, isAgentReferenceEnabled, isAgentRulesEnabled, isValidApplicationId, graduatedFutureKeys, validateConfig, mergeConfig, resolveLazyElements, resolveElementComponents, resolveElementProps, resolveAcceptedChildTypes, resolveMcpSettings, resolveOmittedProps, resolveConfig, type McpSettings, type ResolvedReactCompilerOptions, type Config, type ResolvedConfig, };
362
366
  //# sourceMappingURL=config.d.ts.map