@mandujs/core 0.53.2 → 0.54.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 +654 -654
- package/package.json +2 -2
- package/src/a11y/__tests__/run-audit.test.ts +333 -333
- package/src/a11y/fix-hints.ts +76 -76
- package/src/a11y/index.ts +18 -18
- package/src/a11y/run-audit.ts +394 -394
- package/src/a11y/types.ts +125 -125
- package/src/auth/__tests__/login.test.ts +1 -1
- package/src/auth/__tests__/password.test.ts +122 -122
- package/src/auth/__tests__/tokens.test.ts +274 -274
- package/src/auth/__tests__/verification.test.ts +274 -274
- package/src/auth/index.ts +76 -76
- package/src/auth/login.ts +225 -225
- package/src/auth/password.ts +120 -120
- package/src/auth/reset.ts +243 -243
- package/src/auth/tokens.ts +612 -612
- package/src/auth/verification.ts +253 -253
- package/src/brain/__tests__/redactor.test.ts +94 -94
- package/src/brain/adapters/__tests__/_helpers.ts +83 -83
- package/src/brain/adapters/__tests__/anthropic-oauth.test.ts +196 -196
- package/src/brain/adapters/__tests__/chatgpt-auth.test.ts +193 -193
- package/src/brain/adapters/__tests__/openai-oauth.test.ts +209 -209
- package/src/brain/adapters/__tests__/resolver.test.ts +143 -143
- package/src/brain/adapters/anthropic-oauth.ts +1 -1
- package/src/brain/adapters/chatgpt-auth.ts +300 -300
- package/src/brain/adapters/index.ts +319 -319
- package/src/brain/adapters/oauth-flow.ts +439 -439
- package/src/brain/consent.ts +240 -240
- package/src/brain/credentials.ts +396 -396
- package/src/bundler/__tests__/build-runner.ts +113 -113
- package/src/bundler/__tests__/dev-reliability.test.ts +619 -619
- package/src/bundler/__tests__/extended-watch.test.ts +711 -711
- package/src/bundler/__tests__/fast-refresh.test.ts +10 -10
- package/src/bundler/__tests__/hdr.test.ts +353 -353
- package/src/bundler/__tests__/hmr-client.test.ts +532 -532
- package/src/bundler/__tests__/manifest-schema.test.ts +266 -266
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
- package/src/bundler/__tests__/reverse-import-graph.test.ts +519 -519
- package/src/bundler/__tests__/slot-dispatch.test.ts +573 -573
- package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -286
- package/src/bundler/__tests__/vendor-cache.test.ts +455 -455
- package/src/bundler/budget.ts +404 -404
- package/src/bundler/build.test.ts +179 -179
- package/src/bundler/build.ts +55 -55
- package/src/bundler/dev.ts +42 -42
- package/src/bundler/manifest-schema.ts +301 -301
- package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +263 -263
- package/src/bundler/plugins/__tests__/react-compiler-config.test.ts +83 -83
- package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -110
- package/src/bundler/plugins/block-generated-imports.ts +155 -155
- package/src/bundler/plugins/index.ts +83 -83
- package/src/bundler/plugins/react-compiler-config.ts +108 -108
- package/src/bundler/plugins/react-compiler-lint.ts +253 -253
- package/src/bundler/plugins/react-compiler.ts +162 -162
- package/src/bundler/reverse-import-graph.ts +339 -339
- package/src/bundler/safe-build.test.ts +201 -201
- package/src/bundler/safe-build.ts +103 -103
- package/src/bundler/scenario-matrix.ts +229 -229
- package/src/bundler/types.ts +10 -10
- package/src/bundler/vendor-cache-types.ts +130 -130
- package/src/bundler/vendor-cache.ts +526 -526
- package/src/change/snapshot.ts +18 -18
- package/src/client/Form.tsx +105 -105
- package/src/client/Link.tsx +9 -9
- package/src/client/__tests__/use-sse.test.ts +153 -153
- package/src/client/globals.ts +1 -1
- package/src/client/hooks.ts +362 -362
- package/src/client/hydrate.ts +340 -340
- package/src/client/prefetch-helper.ts +55 -55
- package/src/client/router.ts +11 -11
- package/src/client/runtime.ts +47 -47
- package/src/client/serialize.ts +404 -404
- package/src/client/use-fetch.ts +6 -6
- package/src/client/use-head.ts +197 -197
- package/src/client/use-sse.ts +378 -378
- package/src/client/window-state.ts +101 -101
- package/src/components/Image.tsx +162 -162
- package/src/config/validate.ts +3 -3
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/collection.ts +8 -8
- package/src/content/content-layer.ts +7 -7
- package/src/content/data-store.ts +245 -245
- package/src/content/frontmatter.ts +189 -189
- package/src/content/loader-context.ts +171 -171
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +172 -172
- package/src/content/loaders/glob.ts +253 -253
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/prebuild.test.ts +571 -571
- package/src/content/prebuild.ts +636 -636
- package/src/content/schema.ts +20 -20
- package/src/content/sidebar.ts +630 -630
- package/src/content/slug.ts +110 -110
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/define.ts +11 -11
- package/src/contract/index.ts +1 -1
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +410 -410
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/route-helpers.ts +1 -1
- package/src/contract/rpc.ts +443 -443
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/db/__tests__/db.test.ts +482 -482
- package/src/db/index.ts +138 -138
- package/src/db/migrations/history-table.ts +345 -345
- package/src/db/migrations/index.ts +3 -3
- package/src/db/migrations/lock.ts +324 -324
- package/src/db/migrations/runner.ts +650 -650
- package/src/deploy/cache.ts +140 -140
- package/src/deploy/compile/vercel.ts +344 -344
- package/src/deploy/index.ts +87 -87
- package/src/deploy/inference/brain.ts +268 -268
- package/src/deploy/inference/context.ts +182 -182
- package/src/deploy/inference/filling-extract.ts +245 -245
- package/src/deploy/inference/heuristic.ts +182 -182
- package/src/deploy/intent.ts +173 -173
- package/src/deploy/plan.ts +178 -178
- package/src/design/__tests__/agents-link.test.ts +109 -109
- package/src/design/__tests__/extract-patch-diff.test.ts +265 -265
- package/src/design/__tests__/lint.test.ts +110 -110
- package/src/design/__tests__/parser.test.ts +195 -195
- package/src/design/__tests__/tailwind-theme.test.ts +229 -229
- package/src/design/agents-link.ts +165 -165
- package/src/design/diff.ts +138 -138
- package/src/design/extract.ts +285 -285
- package/src/design/index.ts +102 -102
- package/src/design/lint.ts +209 -209
- package/src/design/parser.ts +555 -555
- package/src/design/patch.ts +241 -241
- package/src/design/scaffold.ts +147 -147
- package/src/design/tailwind-theme.ts +441 -441
- package/src/design/types.ts +210 -210
- package/src/desktop/__tests__/webview-fallback.test.ts +254 -254
- package/src/desktop/__tests__/window.test.ts +248 -248
- package/src/desktop/__tests__/worker.test.ts +266 -266
- package/src/desktop/index.ts +43 -43
- package/src/desktop/types.ts +158 -158
- package/src/desktop/worker.ts +180 -180
- package/src/dev-error-overlay/__tests__/overlay-injector.test.ts +241 -241
- package/src/dev-error-overlay/index.ts +30 -30
- package/src/dev-error-overlay/overlay-injector.ts +243 -243
- package/src/dev-error-overlay/overlay-styles.ts +52 -52
- package/src/dev-error-overlay/types.ts +66 -66
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +25 -25
- package/src/devtools/client/catchers/error-catcher.ts +344 -344
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/mandu-character.tsx +331 -331
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +30 -30
- package/src/devtools/client/components/panel/islands-panel.tsx +320 -320
- package/src/devtools/client/components/panel/network-panel.tsx +291 -291
- package/src/devtools/client/components/panel/panel-container.tsx +500 -500
- package/src/devtools/client/components/panel/preview-panel.tsx +46 -46
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +265 -265
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +450 -450
- package/src/devtools/types.ts +35 -35
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +233 -233
- package/src/devtools/worker/worker-manager.ts +410 -410
- package/src/diagnose/__tests__/checks.test.ts +451 -380
- package/src/diagnose/checks.ts +832 -720
- package/src/diagnose/index.ts +17 -16
- package/src/diagnose/run.ts +93 -91
- package/src/diagnose/types.ts +53 -53
- package/src/email/__tests__/email.test.ts +355 -355
- package/src/email/index.ts +282 -282
- package/src/email/smtp.ts +64 -64
- package/src/error/domains.ts +265 -265
- package/src/error/result.ts +60 -60
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/__tests__/session-sqlite.test.ts +454 -454
- package/src/filling/auth.ts +308 -308
- package/src/filling/cookie-codec.ts +299 -299
- package/src/filling/deps.ts +265 -265
- package/src/filling/session-sqlite.ts +617 -617
- package/src/filling/sse.ts +5 -5
- package/src/filling/ws.ts +78 -78
- package/src/generator/index.ts +3 -3
- package/src/guard/__tests__/design-inline-class.test.ts +219 -219
- package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -347
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/auto-correct.ts +1 -1
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/define-rule.ts +243 -243
- package/src/guard/design-inline-class.ts +393 -393
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/graph.ts +1 -1
- package/src/guard/healing.ts +36 -36
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/reporter.ts +442 -442
- package/src/guard/rule-presets.ts +379 -379
- package/src/guard/semantic-slots.ts +1 -1
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/tsgolint-bridge.ts +512 -512
- package/src/guard/types.ts +348 -348
- package/src/guard/watcher.ts +405 -405
- package/src/i18n/define.ts +126 -126
- package/src/i18n/index.ts +52 -52
- package/src/i18n/message-registry.ts +173 -173
- package/src/i18n/types.ts +112 -112
- package/src/id/index.ts +105 -105
- package/src/index.ts +2 -2
- package/src/kitchen/api/agent-devtools-api.ts +779 -544
- package/src/kitchen/api/errors-grouping.ts +126 -0
- package/src/kitchen/kitchen-handler.ts +192 -63
- package/src/kitchen/kitchen-ui.ts +842 -464
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/middleware/bridge.ts +147 -147
- package/src/middleware/compose.ts +134 -134
- package/src/middleware/compress.ts +62 -62
- package/src/middleware/cors.ts +47 -47
- package/src/middleware/csrf.ts +328 -328
- package/src/middleware/define.ts +132 -132
- package/src/middleware/jwt.ts +134 -134
- package/src/middleware/logger.ts +58 -58
- package/src/middleware/oauth/__tests__/oauth.test.ts +1 -1
- package/src/middleware/oauth/index.ts +505 -505
- package/src/middleware/oauth/providers.ts +115 -115
- package/src/middleware/rate-limit/index.ts +522 -522
- package/src/middleware/rate-limit/sqlite-store.ts +382 -382
- package/src/middleware/scheduler-cron.ts +96 -96
- package/src/middleware/secure/__tests__/secure.test.ts +360 -360
- package/src/middleware/secure/csp.ts +193 -193
- package/src/middleware/session.ts +174 -174
- package/src/middleware/timeout.ts +55 -55
- package/src/observability/logger-adapter.ts +36 -36
- package/src/observability/sqlite-store.ts +254 -254
- package/src/openapi/generator.ts +1 -1
- package/src/openapi/openapi.test.ts +43 -43
- package/src/perf/__tests__/user-marks.test.ts +354 -354
- package/src/perf/index.ts +133 -133
- package/src/plugins/__tests__/lifecycle-integration.test.ts +272 -272
- package/src/plugins/__tests__/runner.test.ts +409 -409
- package/src/plugins/define.ts +124 -124
- package/src/plugins/examples/dep-check-plugin.ts +80 -80
- package/src/plugins/examples/prerender-cache-plugin.ts +111 -111
- package/src/plugins/examples/sitemap-plugin.ts +65 -65
- package/src/plugins/runner.ts +361 -361
- package/src/plugins/types.ts +368 -368
- package/src/report/index.ts +1 -1
- package/src/resource/__tests__/generator.test.ts +32 -32
- package/src/resource/ddl/__tests__/diff.test.ts +639 -639
- package/src/resource/ddl/__tests__/emit.test.ts +823 -823
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
- package/src/resource/ddl/emit.ts +559 -559
- package/src/resource/ddl/persistence-types.ts +218 -218
- package/src/resource/ddl/type-map.ts +223 -223
- package/src/resource/ddl/types.ts +232 -232
- package/src/resource/generator-repo.ts +630 -630
- package/src/resource/schema.ts +1 -1
- package/src/router/fs-patterns.test.ts +96 -96
- package/src/router/fs-routes.ts +6 -6
- package/src/routes/index.ts +74 -74
- package/src/routes/metadata-routes.ts +427 -427
- package/src/routes/types.ts +341 -341
- package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -141
- package/src/runtime/__tests__/hdr-client.test.ts +223 -223
- package/src/runtime/__tests__/http-errors.test.ts +117 -117
- package/src/runtime/__tests__/not-found.test.ts +152 -152
- package/src/runtime/adapter.ts +47 -47
- package/src/runtime/boundary.tsx +252 -252
- package/src/runtime/cache.ts +494 -494
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/fast-refresh-runtime.ts +322 -322
- package/src/runtime/handler.ts +65 -65
- package/src/runtime/handlers.ts +300 -300
- package/src/runtime/http-errors.ts +113 -113
- package/src/runtime/image-handler.ts +1 -1
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/middleware.ts +264 -264
- package/src/runtime/not-found.ts +93 -93
- package/src/runtime/openapi-endpoint.ts +236 -236
- package/src/runtime/ppr.ts +74 -74
- package/src/runtime/registry.ts +171 -171
- package/src/runtime/router.ts +105 -105
- package/src/runtime/server.ts +67 -67
- package/src/runtime/shims.ts +48 -48
- package/src/runtime/ssr.ts +24 -31
- package/src/runtime/streaming-ssr.ts +32 -37
- package/src/runtime/trace.ts +144 -144
- package/src/scheduler/validate.ts +169 -169
- package/src/seo/index.ts +219 -219
- package/src/seo/integration/ssr.ts +306 -306
- package/src/seo/render/basic.ts +435 -435
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +197 -197
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +127 -127
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +104 -104
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +588 -588
- package/src/slot/validator.ts +39 -39
- package/src/storage/s3/__tests__/s3.test.ts +479 -479
- package/src/storage/s3/index.ts +412 -412
- package/src/testing/__tests__/assertions.test.ts +632 -632
- package/src/testing/__tests__/reporter.test.ts +454 -454
- package/src/testing/assertions.ts +986 -986
- package/src/testing/db.ts +157 -157
- package/src/testing/mocks.ts +203 -203
- package/src/testing/session.ts +190 -190
- package/src/types/branded.ts +56 -56
- package/src/types/index.ts +1 -1
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
- package/src/watcher/watcher.ts +18 -18
|
@@ -1,266 +1,266 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @mandujs/core/desktop — Worker protocol tests
|
|
3
|
-
*
|
|
4
|
-
* The Worker file auto-installs a global message listener on module
|
|
5
|
-
* evaluation, so to test the protocol we reach for the exported
|
|
6
|
-
* `_installHandler` helper and drive it with a mock message emitter and
|
|
7
|
-
* a mock `createWindow` implementation. No real Worker spawn, no FFI.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { describe, it, expect } from "bun:test";
|
|
11
|
-
import { _installHandler } from "../worker";
|
|
12
|
-
import type {
|
|
13
|
-
WindowHandle,
|
|
14
|
-
WindowOptions,
|
|
15
|
-
WorkerInbound,
|
|
16
|
-
WorkerOutbound,
|
|
17
|
-
} from "../types";
|
|
18
|
-
|
|
19
|
-
type MessageListener = (ev: { data: WorkerInbound }) => Promise<void> | void;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Stand in for `addEventListener('message', ...)` — retains the listener
|
|
23
|
-
* and exposes a `fire()` helper so tests can synchronously drive messages.
|
|
24
|
-
*/
|
|
25
|
-
function createEmitter(): {
|
|
26
|
-
listen: (cb: MessageListener) => void;
|
|
27
|
-
fire: (data: WorkerInbound) => Promise<void>;
|
|
28
|
-
} {
|
|
29
|
-
let listener: MessageListener | null = null;
|
|
30
|
-
return {
|
|
31
|
-
listen(cb) {
|
|
32
|
-
listener = cb;
|
|
33
|
-
},
|
|
34
|
-
async fire(data) {
|
|
35
|
-
if (!listener) throw new Error("no listener installed");
|
|
36
|
-
await listener({ data });
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* A fake WindowHandle we can wire up to _installHandler so we don't need a
|
|
43
|
-
* real Webview. Tracks every call so tests can assert order.
|
|
44
|
-
*/
|
|
45
|
-
function createFakeHandle(options: WindowOptions): {
|
|
46
|
-
handle: WindowHandle;
|
|
47
|
-
calls: string[];
|
|
48
|
-
closed: () => void;
|
|
49
|
-
} {
|
|
50
|
-
const calls: string[] = [];
|
|
51
|
-
calls.push(`ctor:${options.url}`);
|
|
52
|
-
let resolveClosed: (() => void) | null = null;
|
|
53
|
-
const closedPromise = new Promise<void>((r) => {
|
|
54
|
-
resolveClosed = r;
|
|
55
|
-
});
|
|
56
|
-
const handle: WindowHandle = {
|
|
57
|
-
async close() {
|
|
58
|
-
calls.push("close");
|
|
59
|
-
resolveClosed?.();
|
|
60
|
-
},
|
|
61
|
-
onClose(cb) {
|
|
62
|
-
closedPromise.then(cb);
|
|
63
|
-
},
|
|
64
|
-
async eval(js) {
|
|
65
|
-
calls.push(`eval:${js}`);
|
|
66
|
-
},
|
|
67
|
-
bind() {
|
|
68
|
-
calls.push("bind");
|
|
69
|
-
},
|
|
70
|
-
closed: closedPromise,
|
|
71
|
-
run() {
|
|
72
|
-
calls.push("run");
|
|
73
|
-
// Run returns synchronously in tests — no blocking.
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
return {
|
|
77
|
-
handle,
|
|
78
|
-
calls,
|
|
79
|
-
closed: () => resolveClosed?.(),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
describe("@mandujs/core/desktop — Worker protocol", () => {
|
|
84
|
-
it("handles open → ready sequence and stores handle", async () => {
|
|
85
|
-
const emitter = createEmitter();
|
|
86
|
-
let fake: ReturnType<typeof createFakeHandle> | null = null;
|
|
87
|
-
const outbound: WorkerOutbound[] = [];
|
|
88
|
-
|
|
89
|
-
// Install message handler with a fake createWindow.
|
|
90
|
-
const installed = _installHandler(emitter.listen, async (opts) => {
|
|
91
|
-
fake = createFakeHandle(opts);
|
|
92
|
-
return fake.handle;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Intercept `postMessage` on globalThis to capture outbound messages.
|
|
96
|
-
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
97
|
-
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
98
|
-
msg: WorkerOutbound,
|
|
99
|
-
) => {
|
|
100
|
-
outbound.push(msg);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
await emitter.fire({
|
|
105
|
-
type: "open",
|
|
106
|
-
options: { url: "http://127.0.0.1:3333/" },
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Give the microtask queue a chance to drain the deferred run() call.
|
|
110
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
111
|
-
|
|
112
|
-
expect(fake).not.toBeNull();
|
|
113
|
-
expect(fake!.calls).toContain("ctor:http://127.0.0.1:3333/");
|
|
114
|
-
expect(fake!.calls).toContain("run");
|
|
115
|
-
expect(outbound.some((m) => m.type === "ready")).toBe(true);
|
|
116
|
-
expect(installed.getHandle()).not.toBeNull();
|
|
117
|
-
} finally {
|
|
118
|
-
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it("rejects duplicate open messages", async () => {
|
|
123
|
-
const emitter = createEmitter();
|
|
124
|
-
const outbound: WorkerOutbound[] = [];
|
|
125
|
-
|
|
126
|
-
_installHandler(emitter.listen, async (opts) =>
|
|
127
|
-
createFakeHandle(opts).handle,
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
131
|
-
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
132
|
-
msg: WorkerOutbound,
|
|
133
|
-
) => {
|
|
134
|
-
outbound.push(msg);
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
await emitter.fire({
|
|
139
|
-
type: "open",
|
|
140
|
-
options: { url: "http://127.0.0.1:3333/" },
|
|
141
|
-
});
|
|
142
|
-
outbound.length = 0; // reset
|
|
143
|
-
await emitter.fire({
|
|
144
|
-
type: "open",
|
|
145
|
-
options: { url: "http://127.0.0.1:3333/" },
|
|
146
|
-
});
|
|
147
|
-
const error = outbound.find((m) => m.type === "error");
|
|
148
|
-
expect(error).toBeDefined();
|
|
149
|
-
if (error && error.type === "error") {
|
|
150
|
-
expect(error.message).toMatch(/already open/);
|
|
151
|
-
}
|
|
152
|
-
} finally {
|
|
153
|
-
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("handles eval after open", async () => {
|
|
158
|
-
const emitter = createEmitter();
|
|
159
|
-
let fake: ReturnType<typeof createFakeHandle> | null = null;
|
|
160
|
-
|
|
161
|
-
_installHandler(emitter.listen, async (opts) => {
|
|
162
|
-
fake = createFakeHandle(opts);
|
|
163
|
-
return fake.handle;
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
167
|
-
(globalThis as { postMessage?: unknown }).postMessage = () => {};
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
await emitter.fire({
|
|
171
|
-
type: "open",
|
|
172
|
-
options: { url: "http://127.0.0.1:3333/" },
|
|
173
|
-
});
|
|
174
|
-
await emitter.fire({
|
|
175
|
-
type: "eval",
|
|
176
|
-
js: "console.log('hi')",
|
|
177
|
-
});
|
|
178
|
-
expect(fake!.calls).toContain("eval:console.log('hi')");
|
|
179
|
-
} finally {
|
|
180
|
-
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("reports error when eval is received before open", async () => {
|
|
185
|
-
const emitter = createEmitter();
|
|
186
|
-
const outbound: WorkerOutbound[] = [];
|
|
187
|
-
|
|
188
|
-
_installHandler(emitter.listen, async (opts) =>
|
|
189
|
-
createFakeHandle(opts).handle,
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
193
|
-
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
194
|
-
msg: WorkerOutbound,
|
|
195
|
-
) => {
|
|
196
|
-
outbound.push(msg);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
await emitter.fire({
|
|
201
|
-
type: "eval",
|
|
202
|
-
js: "console.log('early')",
|
|
203
|
-
});
|
|
204
|
-
const error = outbound.find((m) => m.type === "error");
|
|
205
|
-
expect(error).toBeDefined();
|
|
206
|
-
if (error && error.type === "error") {
|
|
207
|
-
expect(error.message).toMatch(/before 'open'/);
|
|
208
|
-
}
|
|
209
|
-
} finally {
|
|
210
|
-
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it("handles close message gracefully when no window is open", async () => {
|
|
215
|
-
const emitter = createEmitter();
|
|
216
|
-
const outbound: WorkerOutbound[] = [];
|
|
217
|
-
|
|
218
|
-
_installHandler(emitter.listen, async (opts) =>
|
|
219
|
-
createFakeHandle(opts).handle,
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
223
|
-
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
224
|
-
msg: WorkerOutbound,
|
|
225
|
-
) => {
|
|
226
|
-
outbound.push(msg);
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
try {
|
|
230
|
-
await emitter.fire({ type: "close" });
|
|
231
|
-
// Should not throw or emit an error — close on nothing is a no-op.
|
|
232
|
-
expect(outbound.filter((m) => m.type === "error").length).toBe(0);
|
|
233
|
-
} finally {
|
|
234
|
-
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it("reports errors for unknown message types", async () => {
|
|
239
|
-
const emitter = createEmitter();
|
|
240
|
-
const outbound: WorkerOutbound[] = [];
|
|
241
|
-
|
|
242
|
-
_installHandler(emitter.listen, async (opts) =>
|
|
243
|
-
createFakeHandle(opts).handle,
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
247
|
-
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
248
|
-
msg: WorkerOutbound,
|
|
249
|
-
) => {
|
|
250
|
-
outbound.push(msg);
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
await emitter.fire({
|
|
255
|
-
type: "bogus" as unknown as "open",
|
|
256
|
-
} as WorkerInbound);
|
|
257
|
-
const error = outbound.find((m) => m.type === "error");
|
|
258
|
-
expect(error).toBeDefined();
|
|
259
|
-
if (error && error.type === "error") {
|
|
260
|
-
expect(error.message).toMatch(/Unknown message type/);
|
|
261
|
-
}
|
|
262
|
-
} finally {
|
|
263
|
-
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @mandujs/core/desktop — Worker protocol tests
|
|
3
|
+
*
|
|
4
|
+
* The Worker file auto-installs a global message listener on module
|
|
5
|
+
* evaluation, so to test the protocol we reach for the exported
|
|
6
|
+
* `_installHandler` helper and drive it with a mock message emitter and
|
|
7
|
+
* a mock `createWindow` implementation. No real Worker spawn, no FFI.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect } from "bun:test";
|
|
11
|
+
import { _installHandler } from "../worker";
|
|
12
|
+
import type {
|
|
13
|
+
WindowHandle,
|
|
14
|
+
WindowOptions,
|
|
15
|
+
WorkerInbound,
|
|
16
|
+
WorkerOutbound,
|
|
17
|
+
} from "../types";
|
|
18
|
+
|
|
19
|
+
type MessageListener = (ev: { data: WorkerInbound }) => Promise<void> | void;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Stand in for `addEventListener('message', ...)` — retains the listener
|
|
23
|
+
* and exposes a `fire()` helper so tests can synchronously drive messages.
|
|
24
|
+
*/
|
|
25
|
+
function createEmitter(): {
|
|
26
|
+
listen: (cb: MessageListener) => void;
|
|
27
|
+
fire: (data: WorkerInbound) => Promise<void>;
|
|
28
|
+
} {
|
|
29
|
+
let listener: MessageListener | null = null;
|
|
30
|
+
return {
|
|
31
|
+
listen(cb) {
|
|
32
|
+
listener = cb;
|
|
33
|
+
},
|
|
34
|
+
async fire(data) {
|
|
35
|
+
if (!listener) throw new Error("no listener installed");
|
|
36
|
+
await listener({ data });
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A fake WindowHandle we can wire up to _installHandler so we don't need a
|
|
43
|
+
* real Webview. Tracks every call so tests can assert order.
|
|
44
|
+
*/
|
|
45
|
+
function createFakeHandle(options: WindowOptions): {
|
|
46
|
+
handle: WindowHandle;
|
|
47
|
+
calls: string[];
|
|
48
|
+
closed: () => void;
|
|
49
|
+
} {
|
|
50
|
+
const calls: string[] = [];
|
|
51
|
+
calls.push(`ctor:${options.url}`);
|
|
52
|
+
let resolveClosed: (() => void) | null = null;
|
|
53
|
+
const closedPromise = new Promise<void>((r) => {
|
|
54
|
+
resolveClosed = r;
|
|
55
|
+
});
|
|
56
|
+
const handle: WindowHandle = {
|
|
57
|
+
async close() {
|
|
58
|
+
calls.push("close");
|
|
59
|
+
resolveClosed?.();
|
|
60
|
+
},
|
|
61
|
+
onClose(cb) {
|
|
62
|
+
closedPromise.then(cb);
|
|
63
|
+
},
|
|
64
|
+
async eval(js) {
|
|
65
|
+
calls.push(`eval:${js}`);
|
|
66
|
+
},
|
|
67
|
+
bind() {
|
|
68
|
+
calls.push("bind");
|
|
69
|
+
},
|
|
70
|
+
closed: closedPromise,
|
|
71
|
+
run() {
|
|
72
|
+
calls.push("run");
|
|
73
|
+
// Run returns synchronously in tests — no blocking.
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
handle,
|
|
78
|
+
calls,
|
|
79
|
+
closed: () => resolveClosed?.(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
describe("@mandujs/core/desktop — Worker protocol", () => {
|
|
84
|
+
it("handles open → ready sequence and stores handle", async () => {
|
|
85
|
+
const emitter = createEmitter();
|
|
86
|
+
let fake: ReturnType<typeof createFakeHandle> | null = null;
|
|
87
|
+
const outbound: WorkerOutbound[] = [];
|
|
88
|
+
|
|
89
|
+
// Install message handler with a fake createWindow.
|
|
90
|
+
const installed = _installHandler(emitter.listen, async (opts) => {
|
|
91
|
+
fake = createFakeHandle(opts);
|
|
92
|
+
return fake.handle;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Intercept `postMessage` on globalThis to capture outbound messages.
|
|
96
|
+
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
97
|
+
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
98
|
+
msg: WorkerOutbound,
|
|
99
|
+
) => {
|
|
100
|
+
outbound.push(msg);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
await emitter.fire({
|
|
105
|
+
type: "open",
|
|
106
|
+
options: { url: "http://127.0.0.1:3333/" },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Give the microtask queue a chance to drain the deferred run() call.
|
|
110
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
111
|
+
|
|
112
|
+
expect(fake).not.toBeNull();
|
|
113
|
+
expect(fake!.calls).toContain("ctor:http://127.0.0.1:3333/");
|
|
114
|
+
expect(fake!.calls).toContain("run");
|
|
115
|
+
expect(outbound.some((m) => m.type === "ready")).toBe(true);
|
|
116
|
+
expect(installed.getHandle()).not.toBeNull();
|
|
117
|
+
} finally {
|
|
118
|
+
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("rejects duplicate open messages", async () => {
|
|
123
|
+
const emitter = createEmitter();
|
|
124
|
+
const outbound: WorkerOutbound[] = [];
|
|
125
|
+
|
|
126
|
+
_installHandler(emitter.listen, async (opts) =>
|
|
127
|
+
createFakeHandle(opts).handle,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
131
|
+
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
132
|
+
msg: WorkerOutbound,
|
|
133
|
+
) => {
|
|
134
|
+
outbound.push(msg);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
await emitter.fire({
|
|
139
|
+
type: "open",
|
|
140
|
+
options: { url: "http://127.0.0.1:3333/" },
|
|
141
|
+
});
|
|
142
|
+
outbound.length = 0; // reset
|
|
143
|
+
await emitter.fire({
|
|
144
|
+
type: "open",
|
|
145
|
+
options: { url: "http://127.0.0.1:3333/" },
|
|
146
|
+
});
|
|
147
|
+
const error = outbound.find((m) => m.type === "error");
|
|
148
|
+
expect(error).toBeDefined();
|
|
149
|
+
if (error && error.type === "error") {
|
|
150
|
+
expect(error.message).toMatch(/already open/);
|
|
151
|
+
}
|
|
152
|
+
} finally {
|
|
153
|
+
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("handles eval after open", async () => {
|
|
158
|
+
const emitter = createEmitter();
|
|
159
|
+
let fake: ReturnType<typeof createFakeHandle> | null = null;
|
|
160
|
+
|
|
161
|
+
_installHandler(emitter.listen, async (opts) => {
|
|
162
|
+
fake = createFakeHandle(opts);
|
|
163
|
+
return fake.handle;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
167
|
+
(globalThis as { postMessage?: unknown }).postMessage = () => {};
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
await emitter.fire({
|
|
171
|
+
type: "open",
|
|
172
|
+
options: { url: "http://127.0.0.1:3333/" },
|
|
173
|
+
});
|
|
174
|
+
await emitter.fire({
|
|
175
|
+
type: "eval",
|
|
176
|
+
js: "console.log('hi')",
|
|
177
|
+
});
|
|
178
|
+
expect(fake!.calls).toContain("eval:console.log('hi')");
|
|
179
|
+
} finally {
|
|
180
|
+
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("reports error when eval is received before open", async () => {
|
|
185
|
+
const emitter = createEmitter();
|
|
186
|
+
const outbound: WorkerOutbound[] = [];
|
|
187
|
+
|
|
188
|
+
_installHandler(emitter.listen, async (opts) =>
|
|
189
|
+
createFakeHandle(opts).handle,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
193
|
+
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
194
|
+
msg: WorkerOutbound,
|
|
195
|
+
) => {
|
|
196
|
+
outbound.push(msg);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
await emitter.fire({
|
|
201
|
+
type: "eval",
|
|
202
|
+
js: "console.log('early')",
|
|
203
|
+
});
|
|
204
|
+
const error = outbound.find((m) => m.type === "error");
|
|
205
|
+
expect(error).toBeDefined();
|
|
206
|
+
if (error && error.type === "error") {
|
|
207
|
+
expect(error.message).toMatch(/before 'open'/);
|
|
208
|
+
}
|
|
209
|
+
} finally {
|
|
210
|
+
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("handles close message gracefully when no window is open", async () => {
|
|
215
|
+
const emitter = createEmitter();
|
|
216
|
+
const outbound: WorkerOutbound[] = [];
|
|
217
|
+
|
|
218
|
+
_installHandler(emitter.listen, async (opts) =>
|
|
219
|
+
createFakeHandle(opts).handle,
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
223
|
+
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
224
|
+
msg: WorkerOutbound,
|
|
225
|
+
) => {
|
|
226
|
+
outbound.push(msg);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
await emitter.fire({ type: "close" });
|
|
231
|
+
// Should not throw or emit an error — close on nothing is a no-op.
|
|
232
|
+
expect(outbound.filter((m) => m.type === "error").length).toBe(0);
|
|
233
|
+
} finally {
|
|
234
|
+
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("reports errors for unknown message types", async () => {
|
|
239
|
+
const emitter = createEmitter();
|
|
240
|
+
const outbound: WorkerOutbound[] = [];
|
|
241
|
+
|
|
242
|
+
_installHandler(emitter.listen, async (opts) =>
|
|
243
|
+
createFakeHandle(opts).handle,
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
const prevPost = (globalThis as { postMessage?: unknown }).postMessage;
|
|
247
|
+
(globalThis as { postMessage?: unknown }).postMessage = (
|
|
248
|
+
msg: WorkerOutbound,
|
|
249
|
+
) => {
|
|
250
|
+
outbound.push(msg);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
await emitter.fire({
|
|
255
|
+
type: "bogus" as unknown as "open",
|
|
256
|
+
} as WorkerInbound);
|
|
257
|
+
const error = outbound.find((m) => m.type === "error");
|
|
258
|
+
expect(error).toBeDefined();
|
|
259
|
+
if (error && error.type === "error") {
|
|
260
|
+
expect(error.message).toMatch(/Unknown message type/);
|
|
261
|
+
}
|
|
262
|
+
} finally {
|
|
263
|
+
(globalThis as { postMessage?: unknown }).postMessage = prevPost;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
package/src/desktop/index.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @mandujs/core/desktop
|
|
3
|
-
*
|
|
4
|
-
* Native desktop windowing for Mandu apps via `webview-bun` (optional peer).
|
|
5
|
-
* Phase 9c — see `docs/bun/phase-9-diagnostics/webview-bun-ffi.md`.
|
|
6
|
-
*
|
|
7
|
-
* Supported backends (from the peer):
|
|
8
|
-
* - Windows: WebView2 (Chromium Evergreen; 10/11)
|
|
9
|
-
* - macOS: WKWebView (11+)
|
|
10
|
-
* - Linux: WebKitGTK 6 + GTK 4
|
|
11
|
-
*
|
|
12
|
-
* `webview-bun` is declared as an **optional peer dependency** — Mandu's core
|
|
13
|
-
* runtime continues to work on web-only projects that never install it.
|
|
14
|
-
* Importing this module is safe in any environment; loading only occurs the
|
|
15
|
-
* first time `createWindow()` is called, at which point a missing peer throws
|
|
16
|
-
* with an actionable install message.
|
|
17
|
-
*
|
|
18
|
-
* @example Minimal desktop entry
|
|
19
|
-
* ```ts
|
|
20
|
-
* import { startServer } from "@mandujs/core";
|
|
21
|
-
* import { createWindow } from "@mandujs/core/desktop";
|
|
22
|
-
* import manifest from "../../.mandu/manifest.json" with { type: "json" };
|
|
23
|
-
*
|
|
24
|
-
* const server = startServer(manifest, { port: 0, hostname: "127.0.0.1" });
|
|
25
|
-
* const win = await createWindow({
|
|
26
|
-
* url: `http://127.0.0.1:${server.server.port}`,
|
|
27
|
-
* title: "My App",
|
|
28
|
-
* width: 1280,
|
|
29
|
-
* height: 800,
|
|
30
|
-
* });
|
|
31
|
-
* win.run(); // blocking; returns on user close
|
|
32
|
-
* server.stop();
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
export { createWindow } from "./window.js";
|
|
37
|
-
export type {
|
|
38
|
-
WindowHandle,
|
|
39
|
-
WindowOptions,
|
|
40
|
-
WindowSizeHint,
|
|
41
|
-
WorkerInbound,
|
|
42
|
-
WorkerOutbound,
|
|
43
|
-
} from "./types.js";
|
|
1
|
+
/**
|
|
2
|
+
* @mandujs/core/desktop
|
|
3
|
+
*
|
|
4
|
+
* Native desktop windowing for Mandu apps via `webview-bun` (optional peer).
|
|
5
|
+
* Phase 9c — see `docs/bun/phase-9-diagnostics/webview-bun-ffi.md`.
|
|
6
|
+
*
|
|
7
|
+
* Supported backends (from the peer):
|
|
8
|
+
* - Windows: WebView2 (Chromium Evergreen; 10/11)
|
|
9
|
+
* - macOS: WKWebView (11+)
|
|
10
|
+
* - Linux: WebKitGTK 6 + GTK 4
|
|
11
|
+
*
|
|
12
|
+
* `webview-bun` is declared as an **optional peer dependency** — Mandu's core
|
|
13
|
+
* runtime continues to work on web-only projects that never install it.
|
|
14
|
+
* Importing this module is safe in any environment; loading only occurs the
|
|
15
|
+
* first time `createWindow()` is called, at which point a missing peer throws
|
|
16
|
+
* with an actionable install message.
|
|
17
|
+
*
|
|
18
|
+
* @example Minimal desktop entry
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { startServer } from "@mandujs/core";
|
|
21
|
+
* import { createWindow } from "@mandujs/core/desktop";
|
|
22
|
+
* import manifest from "../../.mandu/manifest.json" with { type: "json" };
|
|
23
|
+
*
|
|
24
|
+
* const server = startServer(manifest, { port: 0, hostname: "127.0.0.1" });
|
|
25
|
+
* const win = await createWindow({
|
|
26
|
+
* url: `http://127.0.0.1:${server.server.port}`,
|
|
27
|
+
* title: "My App",
|
|
28
|
+
* width: 1280,
|
|
29
|
+
* height: 800,
|
|
30
|
+
* });
|
|
31
|
+
* win.run(); // blocking; returns on user close
|
|
32
|
+
* server.stop();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export { createWindow } from "./window.js";
|
|
37
|
+
export type {
|
|
38
|
+
WindowHandle,
|
|
39
|
+
WindowOptions,
|
|
40
|
+
WindowSizeHint,
|
|
41
|
+
WorkerInbound,
|
|
42
|
+
WorkerOutbound,
|
|
43
|
+
} from "./types.js";
|