@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.
- package/dist/application/init-runtime.d.ts +11 -3
- package/dist/application/init-runtime.d.ts.map +1 -1
- package/dist/application/init-runtime.js +53 -53
- package/dist/domain/ex-command.d.ts +5 -2
- package/dist/domain/ex-command.d.ts.map +1 -1
- package/dist/domain/initialization.d.ts +5 -3
- package/dist/domain/initialization.d.ts.map +1 -1
- package/dist/domain/public-init-api.d.ts +12 -7
- package/dist/domain/public-init-api.d.ts.map +1 -1
- package/dist/ui/App.d.ts +3 -5
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +24 -9
- package/dist/ui/AppSetup.d.ts.map +1 -1
- package/dist/ui/AppSetup.js +2 -3
- package/dist/ui/Shell.js +6 -6
- package/package.json +3 -3
|
@@ -11,10 +11,18 @@ export type InitRuntime = {
|
|
|
11
11
|
readonly finish: () => Initialization;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
|
-
* Creates
|
|
14
|
+
* Creates an isolated startup configuration session.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
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
|
|
4
|
+
* Creates an isolated startup configuration session.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
46
|
+
app: {
|
|
29
47
|
register: (id, appReference) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
53
|
+
registeredApps.set(id, AppPackageReference.parse(appReference));
|
|
41
54
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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 (!
|
|
83
|
+
if (!registeredApps.has(initialAppId)) {
|
|
82
84
|
throw new Error(`Startup app "${initialAppId}" has not been registered.`);
|
|
83
85
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|
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: (
|
|
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":"
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
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,
|
|
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 {
|
|
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
|
-
*
|
|
8
|
-
*
|
|
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
|
|
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
|
-
|
|
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: (
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
package/dist/ui/App.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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 = [...
|
|
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 '
|
|
215
|
-
feedbackApi.addMessage(
|
|
229
|
+
case 'emitError':
|
|
230
|
+
feedbackApi.addMessage(effect.message, 'error');
|
|
216
231
|
return;
|
|
217
232
|
}
|
|
218
|
-
}, [appApi, effectToAction, feedbackApi, navEntry, state, stdout,
|
|
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,+
|
|
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"}
|
package/dist/ui/AppSetup.js
CHANGED
|
@@ -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,
|
|
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.
|
|
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.
|
|
32
|
+
}, [packageLoader, initialization.app.registered]);
|
|
33
33
|
useEffect(() => {
|
|
34
34
|
void shellApi
|
|
35
|
-
.openApp(initialAppOptions.app ?? initialization.
|
|
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.
|
|
39
|
+
}, [initialAppOptions.input, initialization.app.initial, shellApi]);
|
|
40
40
|
if (appError !== undefined) {
|
|
41
41
|
throw appError;
|
|
42
42
|
}
|
|
43
|
-
const initialAppReference = initialization.
|
|
43
|
+
const initialAppReference = initialization.app.registered.get(initialization.app.initial);
|
|
44
44
|
if (initialAppReference === undefined) {
|
|
45
|
-
throw new Error(`Startup app "${initialization.
|
|
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.
|
|
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.
|
|
20
|
-
"dirvi-lib": "0.11.0-beta.
|
|
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": {
|