janela 0.5.0 → 0.6.0
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/README.md +49 -9
- package/bin/janela.mjs +9 -1
- package/package.json +2 -2
- package/runtime/janela.ts +387 -266
- package/runtime/types.ts +0 -119
- package/templates/react/files/src-host/main.ts +20 -21
- package/templates/solid/files/src-host/main.ts +20 -21
- package/templates/svelte/files/src-host/main.ts +20 -21
- package/templates/vue/files/src-host/main.ts +20 -21
package/README.md
CHANGED
|
@@ -138,24 +138,27 @@ framework templates' default.
|
|
|
138
138
|
|
|
139
139
|
```ts
|
|
140
140
|
// src-host/main.ts
|
|
141
|
-
import { defineCommands, defineEvents,
|
|
141
|
+
import { defineCommands, defineEvents, type JanelaApp } from "janela/host";
|
|
142
142
|
|
|
143
|
-
export
|
|
143
|
+
export type AppCommands = {
|
|
144
144
|
add: { args: { a: number; b: number }; result: number };
|
|
145
145
|
greet: { args: { name: string }; result: string };
|
|
146
146
|
wait: { args: { ms: number }; result: string };
|
|
147
|
-
}
|
|
147
|
+
};
|
|
148
|
+
export type AppEvents = { added: number };
|
|
148
149
|
|
|
149
|
-
export const
|
|
150
|
+
export const commands = defineCommands<AppCommands>();
|
|
151
|
+
export const events = defineEvents<AppEvents>();
|
|
150
152
|
|
|
151
153
|
export type App = { commands: typeof commands; events: typeof events };
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
// Typing the app with the contract is what makes the methods below checked.
|
|
156
|
+
export function setup(app: JanelaApp<AppCommands, AppEvents>): void {
|
|
157
|
+
app.command("add", (args) => { // args inferred: { a: number; b: number }
|
|
158
|
+
app.emit("added", args.a + args.b); // event name and payload checked
|
|
156
159
|
return args.a + args.b; // return type checked against the contract
|
|
157
160
|
});
|
|
158
|
-
|
|
161
|
+
app.commandAsync("wait", (args, resolve) => {
|
|
159
162
|
app.sleep(args.ms, () => resolve("waited " + args.ms + "ms"));
|
|
160
163
|
});
|
|
161
164
|
}
|
|
@@ -309,6 +312,43 @@ nested modal loop would otherwise re-enter the host loop underneath a live TS
|
|
|
309
312
|
frame; [docs/native-shell.md](../../docs/native-shell.md) has the details, the
|
|
310
313
|
per-platform table, and the Windows GUI-subsystem note.
|
|
311
314
|
|
|
315
|
+
## Migrating from 0.5.x
|
|
316
|
+
|
|
317
|
+
The contract now rides on the app itself, so the standalone registrars are no
|
|
318
|
+
longer needed. Type the app with your contract and call its methods:
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
// before (0.5.x)
|
|
322
|
+
export function setup(app: JanelaApp): void {
|
|
323
|
+
on(app, commands, "add", (args) => args.a + args.b);
|
|
324
|
+
onAsync(app, commands, "wait", (args, resolve) => { … });
|
|
325
|
+
emit(app, events, "added", 42);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// after (0.6.x)
|
|
329
|
+
export function setup(app: JanelaApp<AppCommands, AppEvents>): void {
|
|
330
|
+
app.command("add", (args) => args.a + args.b);
|
|
331
|
+
app.commandAsync("wait", (args, resolve) => { … });
|
|
332
|
+
app.emit("added", 42);
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Declare each contract as a named type so the same one feeds `defineCommands`
|
|
337
|
+
and the `setup` signature:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
export type AppCommands = { add: { args: { a: number; b: number }; result: number } };
|
|
341
|
+
export type AppEvents = { added: number };
|
|
342
|
+
export const commands = defineCommands<AppCommands>();
|
|
343
|
+
export const events = defineEvents<AppEvents>();
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
`on`, `onAsync` and `emit` still work — they are `@deprecated` one-line
|
|
347
|
+
wrappers now — so 0.5.x code keeps compiling. The page side is unchanged:
|
|
348
|
+
`createClient<App>()` and `client.invoke(...)` are exactly as before. An app
|
|
349
|
+
with no contract needs no change at all: `setup(app: JanelaApp)` still gets an
|
|
350
|
+
untyped `app.command(name, handler)`.
|
|
351
|
+
|
|
312
352
|
## Migrating from 0.4.x
|
|
313
353
|
|
|
314
354
|
Nothing breaks: `app.command`, `app.emit`, and the untyped `invoke` / `listen`
|
|
@@ -338,7 +378,7 @@ export const commands = defineCommands<{
|
|
|
338
378
|
}>();
|
|
339
379
|
export type App = { commands: typeof commands; events: typeof events };
|
|
340
380
|
|
|
341
|
-
|
|
381
|
+
app.command("add", (args) => args.a + args.b); // args inferred, no cast
|
|
342
382
|
```
|
|
343
383
|
|
|
344
384
|
then on the page, replace `invoke<number>("add", …)` with
|
package/bin/janela.mjs
CHANGED
|
@@ -516,10 +516,18 @@ function build(root, { devUrl = null, gui = true } = {}) {
|
|
|
516
516
|
join(buildDir, "entry.ts"),
|
|
517
517
|
`// Generated by janela — do not edit.\n` +
|
|
518
518
|
`import { createApp } from "./janela";\n` +
|
|
519
|
+
`import type { CommandShapes, JanelaApp } from "./janela";\n` +
|
|
519
520
|
`import { WINDOW } from "./config";\n` +
|
|
520
521
|
`import { INDEX_HTML } from "./frontend";\n` +
|
|
521
522
|
`import { setup } from "./main";\n\n` +
|
|
522
|
-
|
|
523
|
+
`// The app's type parameters are read back off setup()'s own signature,\n` +
|
|
524
|
+
`// so a contract-typed setup(app: JanelaApp<App>) and a plain\n` +
|
|
525
|
+
`// setup(app: JanelaApp) each get an app instantiated to match. scriptc\n` +
|
|
526
|
+
`// monomorphises generic classes, so the right instantiation must be\n` +
|
|
527
|
+
`// CONSTRUCTED here - no cast can bridge JanelaApp<A> and JanelaApp<B>.\n` +
|
|
528
|
+
`type CmdsOf<F> = F extends (app: JanelaApp<infer C, infer _E>) => void ? C : CommandShapes;\n` +
|
|
529
|
+
`type EvtsOf<F> = F extends (app: JanelaApp<infer _C, infer E>) => void ? E : Record<string, unknown>;\n\n` +
|
|
530
|
+
`const app = createApp<CmdsOf<typeof setup>, EvtsOf<typeof setup>>(WINDOW);\n` +
|
|
523
531
|
`setup(app);\n` +
|
|
524
532
|
`const rc = app.run(INDEX_HTML) + 0;\n` +
|
|
525
533
|
`console.log("[janela] run returned", rc);\n`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "janela",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Desktop apps in pure TypeScript, compiled to native. No Rust, no Node, no Electron.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"default": "./api/index.js"
|
|
14
14
|
},
|
|
15
15
|
"./host": {
|
|
16
|
-
"types": "./runtime/
|
|
16
|
+
"types": "./runtime/janela.ts"
|
|
17
17
|
},
|
|
18
18
|
"./global": {
|
|
19
19
|
"types": "./api/global.d.ts"
|