@mak-98/dirvi-app 0.11.0-beta.5 → 0.11.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,10 +11,18 @@ export type InitRuntime = {
11
11
  readonly finish: () => Initialization;
12
12
  };
13
13
  /**
14
- * Creates a fresh startup configuration session.
14
+ * Creates an isolated startup configuration session.
15
15
  *
16
- * Each runtime owns its own mutable configuration while registration is open.
17
- * The mutable state is not exposed directly to the config script.
16
+ * The returned API is exposed to `init.mjs` while the script is evaluated.
17
+ * Registration calls validate their runtime inputs, and option updates validate
18
+ * the merged configuration. The session keeps its mutable state private.
19
+ *
20
+ * Call `finish()` after evaluating `init.mjs` to seal the session and obtain
21
+ * the validated initialization. A successful call can happen only once; later
22
+ * API calls and calls to `finish()` throw an error.
23
+ *
24
+ * @returns A fresh initialization runtime with a public registration API and
25
+ * a function for sealing the session.
18
26
  */
19
27
  export declare function createInitRuntime(): InitRuntime;
20
28
  //# sourceMappingURL=init-runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init-runtime.d.ts","sourceRoot":"","sources":["../../src/application/init-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,cAAc,CAAC;CACvC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAiI/C"}
1
+ {"version":3,"file":"init-runtime.d.ts","sourceRoot":"","sources":["../../src/application/init-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,cAAc,CAAC;CACvC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CA+G/C"}
@@ -1,101 +1,101 @@
1
1
  import { ConfigSchema, defaultConfig, merge } from '../domain/config.js';
2
+ import { AppPackageReference } from '../domain/app-pack-ref.js';
2
3
  /**
3
- * Creates a fresh startup configuration session.
4
+ * Creates an isolated startup configuration session.
4
5
  *
5
- * Each runtime owns its own mutable configuration while registration is open.
6
- * The mutable state is not exposed directly to the config script.
6
+ * The returned API is exposed to `init.mjs` while the script is evaluated.
7
+ * Registration calls validate their runtime inputs, and option updates validate
8
+ * the merged configuration. The session keeps its mutable state private.
9
+ *
10
+ * Call `finish()` after evaluating `init.mjs` to seal the session and obtain
11
+ * the validated initialization. A successful call can happen only once; later
12
+ * API calls and calls to `finish()` throw an error.
13
+ *
14
+ * @returns A fresh initialization runtime with a public registration API and
15
+ * a function for sealing the session.
7
16
  */
8
17
  export function createInitRuntime() {
9
18
  let config = defaultConfig;
10
19
  let initialAppId;
11
- const apps = new Map();
20
+ const registeredApps = new Map();
12
21
  const exCommands = new Map();
13
22
  let finished = false;
23
+ const checkFinished = () => {
24
+ if (finished) {
25
+ throw new Error('Initialization has finished. Make all initializations while init.mjs is evaluated.');
26
+ }
27
+ };
28
+ const checkNonEmptyString = (value, label) => {
29
+ if (typeof value !== 'string') {
30
+ throw new Error(`${label} must be a string.`);
31
+ }
32
+ if (value.trim().length === 0) {
33
+ throw new Error(`${label} must not be empty.`);
34
+ }
35
+ };
14
36
  return {
15
37
  api: {
16
38
  options: {
17
39
  set: (patch) => {
18
- // init.mjs is a startup script. It must not modify startup options
19
- // after the host has finished evaluating and consuming it.
20
- if (finished) {
21
- throw new Error('Initialization has finished. Configure dirvi while init.mjs is being evaluated.');
22
- }
40
+ checkFinished();
23
41
  // Validate the complete result, not merely the patch. This preserves
24
42
  // domain invariants even when a patch changes nested configuration.
25
43
  config = ConfigSchema.parse(merge(config, patch));
26
44
  },
27
45
  },
28
- apps: {
46
+ app: {
29
47
  register: (id, appReference) => {
30
- if (finished) {
31
- throw new Error('Initialization has finished. Register apps while ' +
32
- 'init.mjs is being evaluated.');
33
- }
34
- if (id.trim().length === 0) {
35
- throw new Error('App ID must not be empty.');
36
- }
37
- if (apps.has(id)) {
48
+ checkFinished();
49
+ checkNonEmptyString(id, 'App ID');
50
+ if (registeredApps.has(id)) {
38
51
  throw new Error(`An app with ID "${id}" was registered multiple times.`);
39
52
  }
40
- apps.set(id, appReference);
53
+ registeredApps.set(id, AppPackageReference.parse(appReference));
41
54
  },
42
- initialAppId: (appId) => {
43
- if (finished) {
44
- throw new Error('Initialization has finished. Select an initial app while ' +
45
- 'init.mjs is being evaluated.');
46
- }
47
- if (appId.trim().length === 0) {
48
- throw new Error('App ID must not be empty.');
49
- }
55
+ initial: (appId) => {
56
+ checkFinished();
57
+ checkNonEmptyString(appId, 'App ID');
50
58
  initialAppId = appId;
51
59
  },
52
60
  },
53
61
  ex: {
54
62
  register: (name, execute) => {
55
- if (finished) {
56
- throw new Error('Initialization has finished. Register Ex commands while ' +
57
- 'init.mjs is being evaluated.');
58
- }
59
- if (name.trim().length === 0) {
60
- throw new Error('Ex command name must not be empty.');
63
+ checkFinished();
64
+ checkNonEmptyString(name, 'Ex command name');
65
+ if (typeof execute !== 'function') {
66
+ throw new Error('Ex command handler must be a function.');
61
67
  }
62
68
  if (exCommands.has(name)) {
63
69
  throw new Error(`An Ex command named "${name}" was registered multiple times.`);
64
70
  }
65
- exCommands.set(name, {
66
- name,
67
- execute,
68
- });
71
+ exCommands.set(name, { name, execute });
69
72
  },
70
73
  },
71
74
  },
72
75
  finish: () => {
73
- if (finished) {
74
- throw new Error('Initialization has already finished.');
75
- }
76
- if (apps.size === 0) {
76
+ checkFinished();
77
+ if (registeredApps.size === 0) {
77
78
  throw new Error('Initialization did not register any apps. Call ' +
78
79
  'dirvi.apps.register(id, appReference) at least once in init.mjs.');
79
80
  }
81
+ let initial;
80
82
  if (initialAppId !== undefined) {
81
- if (!apps.has(initialAppId)) {
83
+ if (!registeredApps.has(initialAppId)) {
82
84
  throw new Error(`Startup app "${initialAppId}" has not been registered.`);
83
85
  }
84
- finished = true;
85
- return {
86
- config,
87
- initialAppId: initialAppId,
88
- registeredApps: new Map(apps),
89
- exCommands: [...exCommands.values()],
90
- };
86
+ initial = initialAppId;
87
+ }
88
+ else {
89
+ initial = getLastRegisteredAppId(registeredApps);
91
90
  }
92
- const lastRegisteredAppRef = getLastRegisteredAppId(apps);
93
91
  finished = true;
94
92
  return {
95
93
  config,
96
- initialAppId: lastRegisteredAppRef,
97
- registeredApps: new Map(apps),
98
- exCommands: [...exCommands.values()],
94
+ app: {
95
+ initial,
96
+ registered: new Map(registeredApps),
97
+ },
98
+ exCommands: new Map(exCommands),
99
99
  };
100
100
  },
101
101
  };
@@ -1,12 +1,15 @@
1
1
  import { ShellApi } from './shell-api.js';
2
+ export type DirviApi = {
3
+ shell: ShellApi;
4
+ };
2
5
  /**
3
6
  * A command registered by init.mjs and invoked through Ex mode.
4
7
  *
5
- * The command receives the live DirviApi only when it is executed. This keeps
8
+ * The command receives the live Api only when it is executed. This keeps
6
9
  * initialization separate from the running application lifecycle.
7
10
  */
8
11
  export type ExCommand = {
9
12
  readonly name: string;
10
- readonly execute: (shell: ShellApi) => void | Promise<void>;
13
+ readonly execute: (api: DirviApi) => void | Promise<void>;
11
14
  };
12
15
  //# sourceMappingURL=ex-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ex-command.d.ts","sourceRoot":"","sources":["../../src/domain/ex-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D,CAAC"}
1
+ {"version":3,"file":"ex-command.d.ts","sourceRoot":"","sources":["../../src/domain/ex-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,QAAQ,CAAC;CACjB,CAAA;AAGD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D,CAAC"}
@@ -14,8 +14,10 @@ export type AppInput = string | undefined;
14
14
  */
15
15
  export type Initialization = {
16
16
  readonly config: Readonly<Config>;
17
- readonly initialAppId: string;
18
- readonly registeredApps: ReadonlyMap<string, AppPackageReference>;
19
- readonly exCommands: readonly ExCommand[];
17
+ readonly app: {
18
+ initial: string;
19
+ registered: ReadonlyMap<string, AppPackageReference>;
20
+ };
21
+ readonly exCommands: ReadonlyMap<string, ExCommand>;
20
22
  };
21
23
  //# sourceMappingURL=initialization.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"initialization.d.ts","sourceRoot":"","sources":["../../src/domain/initialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAClE,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;CAC3C,CAAC"}
1
+ {"version":3,"file":"initialization.d.ts","sourceRoot":"","sources":["../../src/domain/initialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;KACtD,CAAC;IACF,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrD,CAAC"}
@@ -1,23 +1,28 @@
1
1
  import { AppPackageReference } from './app-pack-ref.js';
2
2
  import { ConfigPatch } from './config.js';
3
- import { ShellApi } from './shell-api.js';
3
+ import { DirviApi } from './ex-command.js';
4
4
  /**
5
- * The startup configuration API exposed to init.mjs as the global `dirvi`.
5
+ * The startup configuration API exposed to `init.mjs` as the global `dirvi`.
6
6
  *
7
- * This is intentionally a narrow facade. It is the public scripting boundary,
8
- * rather than an escape hatch into UI state or infrastructure implementations.
7
+ * These types describe the intended API for TypeScript consumers and provide
8
+ * editor guidance and compile-time checking. They do not validate values at
9
+ * runtime: `init.mjs` may be plain JavaScript and can pass values that do not
10
+ * match these types. The runtime must validate inputs at the scripting
11
+ * boundary before relying on them.
12
+ *
13
+ * This is intentionally a narrow facade; it is the public scripting boundary.
9
14
  */
10
15
  export type PublicInitApi = {
11
16
  readonly options: {
12
17
  set: (patch: ConfigPatch) => void;
13
18
  };
14
- readonly apps: {
19
+ readonly app: {
15
20
  /**
16
21
  * Optionally selects the app initially opened by the shell.
17
22
  *
18
23
  * If omitted, the runtime falls back to the most recently registered app.
19
24
  */
20
- initialAppId: (appId: string) => void;
25
+ initial: (appId: string) => void;
21
26
  /**
22
27
  * Registers an application made available by init.mjs.
23
28
  */
@@ -36,7 +41,7 @@ export type PublicInitApi = {
36
41
  * });
37
42
  * ```
38
43
  */
39
- register: (name: string, execute: (shell: ShellApi) => void | Promise<void>) => void;
44
+ register: (name: string, execute: (api: DirviApi) => void | Promise<void>) => void;
40
45
  };
41
46
  };
42
47
  //# sourceMappingURL=public-init-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-init-api.d.ts","sourceRoot":"","sources":["../../src/domain/public-init-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,OAAO,EAAE;QAChB,GAAG,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;KACnC,CAAC;IAEF,QAAQ,CAAC,IAAI,EAAE;QACb;;;;WAIG;QACH,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACtC;;WAEG;QACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,mBAAmB,KAAK,IAAI,CAAC;KACnE,CAAC;IAEF,QAAQ,CAAC,EAAE,EAAE;QACX;;;;;;;;;;;WAWG;QACH,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAC/C,IAAI,CAAC;KACX,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"public-init-api.d.ts","sourceRoot":"","sources":["../../src/domain/public-init-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,OAAO,EAAE;QAChB,GAAG,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;KACnC,CAAC;IAEF,QAAQ,CAAC,GAAG,EAAE;QACZ;;;;WAIG;QACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACjC;;WAEG;QACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,mBAAmB,KAAK,IAAI,CAAC;KACnE,CAAC;IAEF,QAAQ,CAAC,EAAE,EAAE;QACX;;;;;;;;;;;WAWG;QACH,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAC7C,IAAI,CAAC;KACX,CAAC;CACH,CAAC"}
package/dist/ui/App.d.ts CHANGED
@@ -1,14 +1,12 @@
1
1
  import type { AppApi, EffectToAction, IntentToEffect, Reducer, SerializableKey, State } from 'dirvi-lib';
2
- import type { Config } from '../domain/config.js';
3
2
  import type { AppScreenRenderer } from './app-screen-renderer.js';
4
- import { AppPackageReference } from '../domain/app-pack-ref.js';
5
3
  import { ShellApi } from '../domain/shell-api.js';
4
+ import { Initialization } from '../domain/initialization.js';
6
5
  type AppProps<Id extends SerializableKey, Value, ViewKey = string> = {
7
6
  screenRenderer: AppScreenRenderer;
8
7
  shellApi: ShellApi;
9
8
  appApi: AppApi<Id, Value, ViewKey>;
10
- config: Config;
11
- registeredApps: ReadonlyMap<string, AppPackageReference>;
9
+ initialization: Initialization;
12
10
  initialState: State<Id, Value>;
13
11
  reducer: Reducer<Id, Value>;
14
12
  intentToEffect: IntentToEffect<Id, Value>;
@@ -17,6 +15,6 @@ type AppProps<Id extends SerializableKey, Value, ViewKey = string> = {
17
15
  clipboard?: (value: string) => void;
18
16
  onError?: (error: Error) => void;
19
17
  };
20
- export declare function App<Id extends SerializableKey, Value, ViewKey = string>({ screenRenderer, shellApi, appApi, config, registeredApps, initialState, reducer, intentToEffect, effectToAction, stdout, clipboard, onError, }: AppProps<Id, Value, ViewKey>): import("react").JSX.Element;
18
+ export declare function App<Id extends SerializableKey, Value, ViewKey = string>({ screenRenderer, shellApi, appApi, initialization, initialState, reducer, intentToEffect, effectToAction, stdout, clipboard, onError, }: AppProps<Id, Value, ViewKey>): import("react").JSX.Element;
21
19
  export {};
22
20
  //# sourceMappingURL=App.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,MAAM,EAEN,cAAc,EAEd,cAAc,EAEd,OAAO,EACP,eAAe,EACf,KAAK,EAGN,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAMlD,KAAK,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,IAAI;IACnE,cAAc,EAAE,iBAAiB,CAAC;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACzD,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,GAAG,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,EACvE,cAAc,EACd,QAAQ,EACR,MAAM,EACN,MAAM,EACN,cAAc,EACd,YAAY,EACZ,OAAO,EACP,cAAc,EACd,cAAc,EACd,MAAM,EACN,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,+BAmU9B"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,MAAM,EAEN,cAAc,EAEd,cAAc,EAEd,OAAO,EACP,eAAe,EACf,KAAK,EAGN,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,KAAK,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,IAAI;IACnE,cAAc,EAAE,iBAAiB,CAAC;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,GAAG,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,EACvE,cAAc,EACd,QAAQ,EACR,MAAM,EACN,cAAc,EACd,YAAY,EACZ,OAAO,EACP,cAAc,EACd,cAAc,EACd,MAAM,EACN,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,+BAgW9B"}
package/dist/ui/App.js CHANGED
@@ -2,10 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useReducer, useRef, useState, } from 'react';
3
3
  import { createFeedbackApi, userInputToIntent } from 'dirvi-lib';
4
4
  import { useView } from './hooks/useView.js';
5
- function toError(error) {
6
- return error instanceof Error ? error : new Error(String(error));
7
- }
8
- export function App({ screenRenderer, shellApi, appApi, config, registeredApps, initialState, reducer, intentToEffect, effectToAction, stdout, clipboard, onError, }) {
5
+ export function App({ screenRenderer, shellApi, appApi, initialization, initialState, reducer, intentToEffect, effectToAction, stdout, clipboard, onError, }) {
9
6
  const ScreenRenderer = screenRenderer;
10
7
  const [state, dispatch] = useReducer(reducer, initialState);
11
8
  const stateRef = useRef(state); // Gives `subscribeToResync` callback a way to
@@ -72,11 +69,29 @@ export function App({ screenRenderer, shellApi, appApi, config, registeredApps,
72
69
  return;
73
70
  }
74
71
  switch (effect.effectType) {
72
+ case 'userExCommand': {
73
+ setInputState({
74
+ inputMode: 'normal',
75
+ normalBuffer: '',
76
+ });
77
+ const command = initialization.exCommands.get(effect.name);
78
+ if (command === undefined) {
79
+ feedbackApi.addMessage(`Command is no longer registered: ${effect.name}`, 'error');
80
+ return;
81
+ }
82
+ void Promise.resolve()
83
+ .then(() => command.execute({ shell: shellApi })) // TODO: Add args
84
+ .catch((error) => {
85
+ const appError = error instanceof Error ? error : new Error(String(error));
86
+ feedbackApi.addMessage(`Command "${effect.name}" failed: ${appError.message}`, 'error');
87
+ });
88
+ return;
89
+ }
75
90
  case 'quit':
76
91
  setExitStatus(effect.exitMessage);
77
92
  return;
78
93
  case 'listApps': {
79
- const appIds = [...registeredApps.keys()];
94
+ const appIds = [...initialization.app.registered.keys()];
80
95
  const lines = appIds.map((id) => `${id}`);
81
96
  setInputState({
82
97
  inputMode: 'normal',
@@ -211,11 +226,11 @@ export function App({ screenRenderer, shellApi, appApi, config, registeredApps,
211
226
  feedbackApi.addMessage(['Fold trees:', ...lines].join('\n'));
212
227
  return;
213
228
  }
214
- case 'unrecognizedCommand':
215
- feedbackApi.addMessage(`Unrecognized command: ${effect.commandLine}`, 'error');
229
+ case 'emitError':
230
+ feedbackApi.addMessage(effect.message, 'error');
216
231
  return;
217
232
  }
218
- }, [appApi, effectToAction, feedbackApi, navEntry, state, stdout, registeredApps]);
233
+ }, [appApi, effectToAction, feedbackApi, navEntry, state, stdout, initialization.app.registered, shellApi]);
219
234
  // ===========================================================================
220
235
  // Input hook
221
236
  // ===========================================================================
@@ -234,5 +249,5 @@ export function App({ screenRenderer, shellApi, appApi, config, registeredApps,
234
249
  // ===========================================================================
235
250
  // Render
236
251
  // ===========================================================================
237
- return (_jsx(ScreenRenderer, { view: view, feedback: feedback, feedbackApi: feedbackApi, config: config, inputState: inputState, handleInput: handleInput, onRowsChange: handleRowsChange, exitStatus: exitStatus }));
252
+ return (_jsx(ScreenRenderer, { view: view, feedback: feedback, feedbackApi: feedbackApi, config: initialization.config, inputState: inputState, handleInput: handleInput, onRowsChange: handleRowsChange, exitStatus: exitStatus }));
238
253
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AppSetup.d.ts","sourceRoot":"","sources":["../../src/ui/AppSetup.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAS,MAAM,WAAW,CAAC;AAOhE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAI7D,KAAK,eAAe,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,IAAI;IAC1E,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,EAC5E,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,+BAwFrC"}
1
+ {"version":3,"file":"AppSetup.d.ts","sourceRoot":"","sources":["../../src/ui/AppSetup.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAS,MAAM,WAAW,CAAC;AAOhE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAI7D,KAAK,eAAe,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,IAAI;IAC1E,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,EAC5E,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,+BAuFrC"}
@@ -4,7 +4,6 @@ import { createEffectToAction, createIntentToEffect, createReducer, } from 'dirv
4
4
  import { App } from './App.js';
5
5
  export function AppSetup({ appScreenRenderer, loadingScreenRenderer, initialization, shellApi, appApi, stdout, clipboard, }) {
6
6
  const [initialState, setInitialState] = useState();
7
- const [config, setConfig] = useState(initialization.config);
8
7
  // Loading and setting initial state.
9
8
  useEffect(() => {
10
9
  let mounted = true;
@@ -36,12 +35,12 @@ export function AppSetup({ appScreenRenderer, loadingScreenRenderer, initializat
36
35
  }, [appApi]);
37
36
  // --- Pure function deps ---
38
37
  const reducer = useMemo(() => createReducer(appApi.treeNodeApi, appApi.foldsApi), [appApi.treeNodeApi, appApi.foldsApi]);
39
- const intentToEffect = useMemo(() => createIntentToEffect(appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi), [appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi]);
38
+ const intentToEffect = useMemo(() => createIntentToEffect(new Set(initialization.exCommands.keys()), appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi), [appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi, initialization.exCommands]);
40
39
  const effectToAction = useMemo(() => createEffectToAction(appApi.foldsApi, appApi.cursorApi, appApi.navNodeApi), [appApi.navNodeApi, appApi.cursorApi, appApi.foldsApi]);
41
40
  // --- JSX ---
42
41
  const LoadingScreenRenderer = loadingScreenRenderer;
43
42
  if (initialState === undefined) {
44
43
  return _jsx(LoadingScreenRenderer, {});
45
44
  }
46
- return (_jsx(App, { screenRenderer: appScreenRenderer, shellApi: shellApi, appApi: appApi, config: config, registeredApps: initialization.registeredApps, initialState: initialState, reducer: reducer, intentToEffect: intentToEffect, effectToAction: effectToAction, ...(stdout === undefined ? {} : { stdout }), ...(clipboard === undefined ? {} : { clipboard }) }));
45
+ return (_jsx(App, { screenRenderer: appScreenRenderer, shellApi: shellApi, appApi: appApi, initialization: initialization, initialState: initialState, reducer: reducer, intentToEffect: intentToEffect, effectToAction: effectToAction, ...(stdout === undefined ? {} : { stdout }), ...(clipboard === undefined ? {} : { clipboard }) }));
47
46
  }
package/dist/ui/Shell.js CHANGED
@@ -18,7 +18,7 @@ export function Shell({ loadingScreenRenderer, appScreenRenderer, initialAppOpti
18
18
  const shellApi = useMemo(() => {
19
19
  return {
20
20
  openApp: async (appId, input) => {
21
- const appReference = initialization.registeredApps.get(appId);
21
+ const appReference = initialization.app.registered.get(appId);
22
22
  if (appReference === undefined) {
23
23
  throw new Error(`App "${appId}" has not been registered.`);
24
24
  }
@@ -29,20 +29,20 @@ export function Shell({ loadingScreenRenderer, appScreenRenderer, initialAppOpti
29
29
  setAppApiApplicator(() => loadedAppApiApplicator);
30
30
  },
31
31
  };
32
- }, [initialization.registeredApps, packageLoader]);
32
+ }, [packageLoader, initialization.app.registered]);
33
33
  useEffect(() => {
34
34
  void shellApi
35
- .openApp(initialAppOptions.app ?? initialization.initialAppId, initialAppOptions.input)
35
+ .openApp(initialAppOptions.app ?? initialization.app.initial, initialAppOptions.input)
36
36
  .catch((error) => {
37
37
  setAppError(error instanceof Error ? error : new Error(String(error)));
38
38
  });
39
- }, [initialAppOptions.input, initialization.initialAppId, shellApi]);
39
+ }, [initialAppOptions.input, initialization.app.initial, shellApi]);
40
40
  if (appError !== undefined) {
41
41
  throw appError;
42
42
  }
43
- const initialAppReference = initialization.registeredApps.get(initialization.initialAppId);
43
+ const initialAppReference = initialization.app.registered.get(initialization.app.initial);
44
44
  if (initialAppReference === undefined) {
45
- throw new Error(`Startup app "${initialization.initialAppId}" has not been registered.`);
45
+ throw new Error(`Startup app "${initialization.app.initial}" has not been registered.`);
46
46
  }
47
47
  if (appApiApplicator === undefined) {
48
48
  const LoadingScreenRenderer = loadingScreenRenderer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mak-98/dirvi-app",
3
- "version": "0.11.0-beta.5",
3
+ "version": "0.11.0-beta.6",
4
4
  "description": "Shared React application logic for dirvi hosts.",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-or-later",
@@ -16,8 +16,8 @@
16
16
  "dist"
17
17
  ],
18
18
  "dependencies": {
19
- "dirvi-apis": "0.11.0-beta.5",
20
- "dirvi-lib": "0.11.0-beta.5",
19
+ "dirvi-apis": "0.11.0-beta.6",
20
+ "dirvi-lib": "0.11.0-beta.6",
21
21
  "zod": "^4.4.3"
22
22
  },
23
23
  "peerDependencies": {