@mandujs/core 0.53.3 → 0.54.1
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 +1 -1
- 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 -451
- package/src/diagnose/checks.ts +832 -832
- package/src/diagnose/index.ts +17 -17
- package/src/diagnose/run.ts +93 -93
- 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/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,254 +1,254 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 11 C / M-02 — FFI fallback unit tests.
|
|
3
|
-
*
|
|
4
|
-
* Scope:
|
|
5
|
-
* 1. The module imports cleanly even when the webview-bun peer and the
|
|
6
|
-
* libwebview shared library are BOTH absent. Phase 9 released the
|
|
7
|
-
* barrel as importable under these conditions; Phase 11 C preserves
|
|
8
|
-
* that invariant for the fallback.
|
|
9
|
-
* 2. `_ffiSymbols` shape is frozen — matches the upstream C ABI we
|
|
10
|
-
* pinned in `webview-fallback.ts` header.
|
|
11
|
-
* 3. `_mapHintToInt` mirrors the upstream `WEBVIEW_HINT_*` enum.
|
|
12
|
-
* 4. `_getLibraryCandidates()` probes the three expected slots
|
|
13
|
-
* (env var → package-relative mirror → system default).
|
|
14
|
-
* 5. `createFallbackWebview` rejects bad options BEFORE any `dlopen`
|
|
15
|
-
* attempt, so a CI without libwebview still passes.
|
|
16
|
-
* 6. `loadFFILibwebview` failure yields a user-actionable error
|
|
17
|
-
* message enumerating every probed path.
|
|
18
|
-
* 7. (opt-in E2E) On a machine with libwebview installed, a real
|
|
19
|
-
* window can be created via the fallback. Gated by
|
|
20
|
-
* `MANDU_DESKTOP_FALLBACK_E2E=1`.
|
|
21
|
-
*
|
|
22
|
-
* These tests deliberately exercise the FFI contract WITHOUT actually
|
|
23
|
-
* dlopening the library — CI cannot assume libwebview is installed. The
|
|
24
|
-
* opt-in block (test 7) is only active under an explicit env flag.
|
|
25
|
-
*
|
|
26
|
-
* References:
|
|
27
|
-
* docs/bun/phase-9-diagnostics/webview-bun-ffi.md §8 (fallback design)
|
|
28
|
-
* packages/core/src/desktop/webview-fallback.ts
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
import {
|
|
32
|
-
describe,
|
|
33
|
-
it,
|
|
34
|
-
expect,
|
|
35
|
-
beforeEach,
|
|
36
|
-
afterEach,
|
|
37
|
-
} from "bun:test";
|
|
38
|
-
|
|
39
|
-
describe("@mandujs/core/desktop/webview-fallback — module import", () => {
|
|
40
|
-
it("imports without loading libwebview", async () => {
|
|
41
|
-
// The import itself must succeed even when `bun:ffi.dlopen` would
|
|
42
|
-
// fail (no libwebview). Module-level code must not `dlopen` — that
|
|
43
|
-
// happens only on `createFallbackWebview()`.
|
|
44
|
-
const mod = await import("../webview-fallback");
|
|
45
|
-
expect(typeof mod.createFallbackWebview).toBe("function");
|
|
46
|
-
expect(typeof mod.loadFFILibwebview).toBe("function");
|
|
47
|
-
expect(typeof mod._mapHintToInt).toBe("function");
|
|
48
|
-
expect(typeof mod._getLibraryCandidates).toBe("function");
|
|
49
|
-
expect(typeof mod._defaultLibName).toBe("function");
|
|
50
|
-
expect(typeof mod._resetFFICache).toBe("function");
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("module import is idempotent — cache loader does not fire on import", async () => {
|
|
54
|
-
// Import twice; neither call should throw. If `import.meta.url`-based
|
|
55
|
-
// candidate probing has a side effect, that would manifest on the
|
|
56
|
-
// second call.
|
|
57
|
-
const a = await import("../webview-fallback");
|
|
58
|
-
const b = await import("../webview-fallback");
|
|
59
|
-
expect(a).toBe(b); // same module instance from Bun's ESM cache
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("@mandujs/core/desktop/webview-fallback — FFI symbol contract", () => {
|
|
64
|
-
it("_ffiSymbols declares the minimal webview C ABI we depend on", async () => {
|
|
65
|
-
const { _ffiSymbols } = await import("../webview-fallback");
|
|
66
|
-
// The set of symbols MUST match the upstream webview.h surface we
|
|
67
|
-
// pinned in Phase 11 C. Test the shape, not the exact order.
|
|
68
|
-
const expected = [
|
|
69
|
-
"webview_create",
|
|
70
|
-
"webview_navigate",
|
|
71
|
-
"webview_set_title",
|
|
72
|
-
"webview_set_size",
|
|
73
|
-
"webview_set_html",
|
|
74
|
-
"webview_run",
|
|
75
|
-
"webview_terminate",
|
|
76
|
-
"webview_destroy",
|
|
77
|
-
];
|
|
78
|
-
for (const sym of expected) {
|
|
79
|
-
expect(_ffiSymbols).toHaveProperty(sym);
|
|
80
|
-
const entry = (_ffiSymbols as Record<string, { args: unknown; returns: unknown }>)[sym];
|
|
81
|
-
expect(Array.isArray(entry.args)).toBe(true);
|
|
82
|
-
expect(typeof entry.returns).toBe("string");
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("_ffiSymbols is frozen — no mutation allowed at runtime", async () => {
|
|
87
|
-
const { _ffiSymbols } = await import("../webview-fallback");
|
|
88
|
-
expect(Object.isFrozen(_ffiSymbols)).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("webview_create returns a pointer and takes (i32, ptr)", async () => {
|
|
92
|
-
const { _ffiSymbols } = await import("../webview-fallback");
|
|
93
|
-
expect(_ffiSymbols.webview_create.args).toEqual(["i32", "ptr"]);
|
|
94
|
-
expect(_ffiSymbols.webview_create.returns).toBe("ptr");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("webview_set_size has 4 args matching (ptr,i32,i32,i32)", async () => {
|
|
98
|
-
const { _ffiSymbols } = await import("../webview-fallback");
|
|
99
|
-
expect(_ffiSymbols.webview_set_size.args).toEqual([
|
|
100
|
-
"ptr",
|
|
101
|
-
"i32",
|
|
102
|
-
"i32",
|
|
103
|
-
"i32",
|
|
104
|
-
]);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe("@mandujs/core/desktop/webview-fallback — _mapHintToInt", () => {
|
|
109
|
-
it("matches WEBVIEW_HINT_* enum values from upstream webview.h", async () => {
|
|
110
|
-
const { _mapHintToInt } = await import("../webview-fallback");
|
|
111
|
-
expect(_mapHintToInt("none")).toBe(0);
|
|
112
|
-
expect(_mapHintToInt("min")).toBe(1);
|
|
113
|
-
expect(_mapHintToInt("max")).toBe(2);
|
|
114
|
-
expect(_mapHintToInt("fixed")).toBe(3);
|
|
115
|
-
expect(_mapHintToInt(undefined)).toBe(0);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe("@mandujs/core/desktop/webview-fallback — library candidate probe", () => {
|
|
120
|
-
const ORIGINAL_ENV = process.env.MANDU_LIBWEBVIEW_PATH;
|
|
121
|
-
|
|
122
|
-
beforeEach(() => {
|
|
123
|
-
delete process.env.MANDU_LIBWEBVIEW_PATH;
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
afterEach(() => {
|
|
127
|
-
if (ORIGINAL_ENV !== undefined) {
|
|
128
|
-
process.env.MANDU_LIBWEBVIEW_PATH = ORIGINAL_ENV;
|
|
129
|
-
} else {
|
|
130
|
-
delete process.env.MANDU_LIBWEBVIEW_PATH;
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("_getLibraryCandidates includes the system default when no env is set", async () => {
|
|
135
|
-
const { _getLibraryCandidates, _defaultLibName } = await import(
|
|
136
|
-
"../webview-fallback"
|
|
137
|
-
);
|
|
138
|
-
const candidates = _getLibraryCandidates();
|
|
139
|
-
expect(candidates.length).toBeGreaterThanOrEqual(1);
|
|
140
|
-
// Last candidate is always the bare lib name.
|
|
141
|
-
expect(candidates[candidates.length - 1]).toBe(_defaultLibName());
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("_getLibraryCandidates prepends MANDU_LIBWEBVIEW_PATH when set", async () => {
|
|
145
|
-
process.env.MANDU_LIBWEBVIEW_PATH = "/opt/custom/libwebview.so";
|
|
146
|
-
const { _getLibraryCandidates } = await import("../webview-fallback");
|
|
147
|
-
const candidates = _getLibraryCandidates();
|
|
148
|
-
expect(candidates[0]).toBe("/opt/custom/libwebview.so");
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("_defaultLibName maps to platform extension", async () => {
|
|
152
|
-
const { _defaultLibName } = await import("../webview-fallback");
|
|
153
|
-
const name = _defaultLibName();
|
|
154
|
-
if (process.platform === "win32") expect(name).toBe("libwebview.dll");
|
|
155
|
-
else if (process.platform === "darwin")
|
|
156
|
-
expect(name).toBe("libwebview.dylib");
|
|
157
|
-
else expect(name).toBe("libwebview.so");
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe("@mandujs/core/desktop/webview-fallback — createFallbackWebview", () => {
|
|
162
|
-
it("rejects missing options before any dlopen attempt", async () => {
|
|
163
|
-
const { createFallbackWebview } = await import("../webview-fallback");
|
|
164
|
-
// An empty-object options bag must be caught by defensive guards
|
|
165
|
-
// BEFORE we touch the FFI peer — so this test passes on CI without
|
|
166
|
-
// libwebview.
|
|
167
|
-
await expect(
|
|
168
|
-
createFallbackWebview({} as never),
|
|
169
|
-
).rejects.toThrow(TypeError);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("rejects non-string url before any dlopen attempt", async () => {
|
|
173
|
-
const { createFallbackWebview } = await import("../webview-fallback");
|
|
174
|
-
await expect(
|
|
175
|
-
createFallbackWebview({ url: 42 as unknown as string }),
|
|
176
|
-
).rejects.toThrow(TypeError);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it("rejects empty url before any dlopen attempt", async () => {
|
|
180
|
-
const { createFallbackWebview } = await import("../webview-fallback");
|
|
181
|
-
await expect(
|
|
182
|
-
createFallbackWebview({ url: "" }),
|
|
183
|
-
).rejects.toThrow(TypeError);
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
describe("@mandujs/core/desktop/webview-fallback — loadFFILibwebview failure surface", () => {
|
|
188
|
-
const ORIGINAL_ENV = process.env.MANDU_LIBWEBVIEW_PATH;
|
|
189
|
-
|
|
190
|
-
beforeEach(async () => {
|
|
191
|
-
// Force an unreachable path so the loader's failure hint is
|
|
192
|
-
// exercised without depending on the actual libwebview install
|
|
193
|
-
// state of the CI runner.
|
|
194
|
-
process.env.MANDU_LIBWEBVIEW_PATH =
|
|
195
|
-
"/path/that/definitely/does/not/exist/libwebview.so";
|
|
196
|
-
const mod = await import("../webview-fallback");
|
|
197
|
-
mod._resetFFICache();
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
afterEach(async () => {
|
|
201
|
-
if (ORIGINAL_ENV !== undefined) {
|
|
202
|
-
process.env.MANDU_LIBWEBVIEW_PATH = ORIGINAL_ENV;
|
|
203
|
-
} else {
|
|
204
|
-
delete process.env.MANDU_LIBWEBVIEW_PATH;
|
|
205
|
-
}
|
|
206
|
-
const mod = await import("../webview-fallback");
|
|
207
|
-
mod._resetFFICache();
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("throws an actionable error enumerating every probed path", async () => {
|
|
211
|
-
const { loadFFILibwebview } = await import("../webview-fallback");
|
|
212
|
-
try {
|
|
213
|
-
await loadFFILibwebview();
|
|
214
|
-
throw new Error("unreachable — loadFFILibwebview should have thrown");
|
|
215
|
-
} catch (err) {
|
|
216
|
-
expect(err).toBeInstanceOf(Error);
|
|
217
|
-
const msg = (err as Error).message;
|
|
218
|
-
// Actionable hints — install options + env var hint.
|
|
219
|
-
expect(msg).toContain("libwebview");
|
|
220
|
-
expect(msg).toContain("MANDU_LIBWEBVIEW_PATH");
|
|
221
|
-
expect(msg).toContain("webview/webview");
|
|
222
|
-
// Should enumerate the failing candidate we injected.
|
|
223
|
-
expect(msg).toContain("libwebview.so");
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
// ─── Opt-in E2E (real window) ──────────────────────────────────────────────
|
|
229
|
-
//
|
|
230
|
-
// Runs ONLY when MANDU_DESKTOP_FALLBACK_E2E=1 AND platform supports it.
|
|
231
|
-
// CI skips this block unconditionally.
|
|
232
|
-
|
|
233
|
-
const canOpenFallbackWindow =
|
|
234
|
-
process.env.MANDU_DESKTOP_FALLBACK_E2E === "1" &&
|
|
235
|
-
(process.platform === "win32" ||
|
|
236
|
-
process.platform === "darwin" ||
|
|
237
|
-
process.platform === "linux");
|
|
238
|
-
|
|
239
|
-
describe.skipIf(!canOpenFallbackWindow)(
|
|
240
|
-
"@mandujs/core/desktop/webview-fallback — browser smoke (opt-in)",
|
|
241
|
-
() => {
|
|
242
|
-
it("opens a data: URL window via the FFI fallback", async () => {
|
|
243
|
-
const { createFallbackWebview } = await import("../webview-fallback");
|
|
244
|
-
const handle = await createFallbackWebview({
|
|
245
|
-
url: "data:text/html,<h1>Mandu FFI fallback smoke</h1>",
|
|
246
|
-
title: "Mandu Fallback E2E",
|
|
247
|
-
width: 400,
|
|
248
|
-
height: 300,
|
|
249
|
-
});
|
|
250
|
-
await handle.close();
|
|
251
|
-
await handle.closed;
|
|
252
|
-
});
|
|
253
|
-
},
|
|
254
|
-
);
|
|
1
|
+
/**
|
|
2
|
+
* Phase 11 C / M-02 — FFI fallback unit tests.
|
|
3
|
+
*
|
|
4
|
+
* Scope:
|
|
5
|
+
* 1. The module imports cleanly even when the webview-bun peer and the
|
|
6
|
+
* libwebview shared library are BOTH absent. Phase 9 released the
|
|
7
|
+
* barrel as importable under these conditions; Phase 11 C preserves
|
|
8
|
+
* that invariant for the fallback.
|
|
9
|
+
* 2. `_ffiSymbols` shape is frozen — matches the upstream C ABI we
|
|
10
|
+
* pinned in `webview-fallback.ts` header.
|
|
11
|
+
* 3. `_mapHintToInt` mirrors the upstream `WEBVIEW_HINT_*` enum.
|
|
12
|
+
* 4. `_getLibraryCandidates()` probes the three expected slots
|
|
13
|
+
* (env var → package-relative mirror → system default).
|
|
14
|
+
* 5. `createFallbackWebview` rejects bad options BEFORE any `dlopen`
|
|
15
|
+
* attempt, so a CI without libwebview still passes.
|
|
16
|
+
* 6. `loadFFILibwebview` failure yields a user-actionable error
|
|
17
|
+
* message enumerating every probed path.
|
|
18
|
+
* 7. (opt-in E2E) On a machine with libwebview installed, a real
|
|
19
|
+
* window can be created via the fallback. Gated by
|
|
20
|
+
* `MANDU_DESKTOP_FALLBACK_E2E=1`.
|
|
21
|
+
*
|
|
22
|
+
* These tests deliberately exercise the FFI contract WITHOUT actually
|
|
23
|
+
* dlopening the library — CI cannot assume libwebview is installed. The
|
|
24
|
+
* opt-in block (test 7) is only active under an explicit env flag.
|
|
25
|
+
*
|
|
26
|
+
* References:
|
|
27
|
+
* docs/bun/phase-9-diagnostics/webview-bun-ffi.md §8 (fallback design)
|
|
28
|
+
* packages/core/src/desktop/webview-fallback.ts
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import {
|
|
32
|
+
describe,
|
|
33
|
+
it,
|
|
34
|
+
expect,
|
|
35
|
+
beforeEach,
|
|
36
|
+
afterEach,
|
|
37
|
+
} from "bun:test";
|
|
38
|
+
|
|
39
|
+
describe("@mandujs/core/desktop/webview-fallback — module import", () => {
|
|
40
|
+
it("imports without loading libwebview", async () => {
|
|
41
|
+
// The import itself must succeed even when `bun:ffi.dlopen` would
|
|
42
|
+
// fail (no libwebview). Module-level code must not `dlopen` — that
|
|
43
|
+
// happens only on `createFallbackWebview()`.
|
|
44
|
+
const mod = await import("../webview-fallback");
|
|
45
|
+
expect(typeof mod.createFallbackWebview).toBe("function");
|
|
46
|
+
expect(typeof mod.loadFFILibwebview).toBe("function");
|
|
47
|
+
expect(typeof mod._mapHintToInt).toBe("function");
|
|
48
|
+
expect(typeof mod._getLibraryCandidates).toBe("function");
|
|
49
|
+
expect(typeof mod._defaultLibName).toBe("function");
|
|
50
|
+
expect(typeof mod._resetFFICache).toBe("function");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("module import is idempotent — cache loader does not fire on import", async () => {
|
|
54
|
+
// Import twice; neither call should throw. If `import.meta.url`-based
|
|
55
|
+
// candidate probing has a side effect, that would manifest on the
|
|
56
|
+
// second call.
|
|
57
|
+
const a = await import("../webview-fallback");
|
|
58
|
+
const b = await import("../webview-fallback");
|
|
59
|
+
expect(a).toBe(b); // same module instance from Bun's ESM cache
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("@mandujs/core/desktop/webview-fallback — FFI symbol contract", () => {
|
|
64
|
+
it("_ffiSymbols declares the minimal webview C ABI we depend on", async () => {
|
|
65
|
+
const { _ffiSymbols } = await import("../webview-fallback");
|
|
66
|
+
// The set of symbols MUST match the upstream webview.h surface we
|
|
67
|
+
// pinned in Phase 11 C. Test the shape, not the exact order.
|
|
68
|
+
const expected = [
|
|
69
|
+
"webview_create",
|
|
70
|
+
"webview_navigate",
|
|
71
|
+
"webview_set_title",
|
|
72
|
+
"webview_set_size",
|
|
73
|
+
"webview_set_html",
|
|
74
|
+
"webview_run",
|
|
75
|
+
"webview_terminate",
|
|
76
|
+
"webview_destroy",
|
|
77
|
+
];
|
|
78
|
+
for (const sym of expected) {
|
|
79
|
+
expect(_ffiSymbols).toHaveProperty(sym);
|
|
80
|
+
const entry = (_ffiSymbols as Record<string, { args: unknown; returns: unknown }>)[sym];
|
|
81
|
+
expect(Array.isArray(entry.args)).toBe(true);
|
|
82
|
+
expect(typeof entry.returns).toBe("string");
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("_ffiSymbols is frozen — no mutation allowed at runtime", async () => {
|
|
87
|
+
const { _ffiSymbols } = await import("../webview-fallback");
|
|
88
|
+
expect(Object.isFrozen(_ffiSymbols)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("webview_create returns a pointer and takes (i32, ptr)", async () => {
|
|
92
|
+
const { _ffiSymbols } = await import("../webview-fallback");
|
|
93
|
+
expect(_ffiSymbols.webview_create.args).toEqual(["i32", "ptr"]);
|
|
94
|
+
expect(_ffiSymbols.webview_create.returns).toBe("ptr");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("webview_set_size has 4 args matching (ptr,i32,i32,i32)", async () => {
|
|
98
|
+
const { _ffiSymbols } = await import("../webview-fallback");
|
|
99
|
+
expect(_ffiSymbols.webview_set_size.args).toEqual([
|
|
100
|
+
"ptr",
|
|
101
|
+
"i32",
|
|
102
|
+
"i32",
|
|
103
|
+
"i32",
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("@mandujs/core/desktop/webview-fallback — _mapHintToInt", () => {
|
|
109
|
+
it("matches WEBVIEW_HINT_* enum values from upstream webview.h", async () => {
|
|
110
|
+
const { _mapHintToInt } = await import("../webview-fallback");
|
|
111
|
+
expect(_mapHintToInt("none")).toBe(0);
|
|
112
|
+
expect(_mapHintToInt("min")).toBe(1);
|
|
113
|
+
expect(_mapHintToInt("max")).toBe(2);
|
|
114
|
+
expect(_mapHintToInt("fixed")).toBe(3);
|
|
115
|
+
expect(_mapHintToInt(undefined)).toBe(0);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("@mandujs/core/desktop/webview-fallback — library candidate probe", () => {
|
|
120
|
+
const ORIGINAL_ENV = process.env.MANDU_LIBWEBVIEW_PATH;
|
|
121
|
+
|
|
122
|
+
beforeEach(() => {
|
|
123
|
+
delete process.env.MANDU_LIBWEBVIEW_PATH;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
afterEach(() => {
|
|
127
|
+
if (ORIGINAL_ENV !== undefined) {
|
|
128
|
+
process.env.MANDU_LIBWEBVIEW_PATH = ORIGINAL_ENV;
|
|
129
|
+
} else {
|
|
130
|
+
delete process.env.MANDU_LIBWEBVIEW_PATH;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("_getLibraryCandidates includes the system default when no env is set", async () => {
|
|
135
|
+
const { _getLibraryCandidates, _defaultLibName } = await import(
|
|
136
|
+
"../webview-fallback"
|
|
137
|
+
);
|
|
138
|
+
const candidates = _getLibraryCandidates();
|
|
139
|
+
expect(candidates.length).toBeGreaterThanOrEqual(1);
|
|
140
|
+
// Last candidate is always the bare lib name.
|
|
141
|
+
expect(candidates[candidates.length - 1]).toBe(_defaultLibName());
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("_getLibraryCandidates prepends MANDU_LIBWEBVIEW_PATH when set", async () => {
|
|
145
|
+
process.env.MANDU_LIBWEBVIEW_PATH = "/opt/custom/libwebview.so";
|
|
146
|
+
const { _getLibraryCandidates } = await import("../webview-fallback");
|
|
147
|
+
const candidates = _getLibraryCandidates();
|
|
148
|
+
expect(candidates[0]).toBe("/opt/custom/libwebview.so");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("_defaultLibName maps to platform extension", async () => {
|
|
152
|
+
const { _defaultLibName } = await import("../webview-fallback");
|
|
153
|
+
const name = _defaultLibName();
|
|
154
|
+
if (process.platform === "win32") expect(name).toBe("libwebview.dll");
|
|
155
|
+
else if (process.platform === "darwin")
|
|
156
|
+
expect(name).toBe("libwebview.dylib");
|
|
157
|
+
else expect(name).toBe("libwebview.so");
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("@mandujs/core/desktop/webview-fallback — createFallbackWebview", () => {
|
|
162
|
+
it("rejects missing options before any dlopen attempt", async () => {
|
|
163
|
+
const { createFallbackWebview } = await import("../webview-fallback");
|
|
164
|
+
// An empty-object options bag must be caught by defensive guards
|
|
165
|
+
// BEFORE we touch the FFI peer — so this test passes on CI without
|
|
166
|
+
// libwebview.
|
|
167
|
+
await expect(
|
|
168
|
+
createFallbackWebview({} as never),
|
|
169
|
+
).rejects.toThrow(TypeError);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("rejects non-string url before any dlopen attempt", async () => {
|
|
173
|
+
const { createFallbackWebview } = await import("../webview-fallback");
|
|
174
|
+
await expect(
|
|
175
|
+
createFallbackWebview({ url: 42 as unknown as string }),
|
|
176
|
+
).rejects.toThrow(TypeError);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("rejects empty url before any dlopen attempt", async () => {
|
|
180
|
+
const { createFallbackWebview } = await import("../webview-fallback");
|
|
181
|
+
await expect(
|
|
182
|
+
createFallbackWebview({ url: "" }),
|
|
183
|
+
).rejects.toThrow(TypeError);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("@mandujs/core/desktop/webview-fallback — loadFFILibwebview failure surface", () => {
|
|
188
|
+
const ORIGINAL_ENV = process.env.MANDU_LIBWEBVIEW_PATH;
|
|
189
|
+
|
|
190
|
+
beforeEach(async () => {
|
|
191
|
+
// Force an unreachable path so the loader's failure hint is
|
|
192
|
+
// exercised without depending on the actual libwebview install
|
|
193
|
+
// state of the CI runner.
|
|
194
|
+
process.env.MANDU_LIBWEBVIEW_PATH =
|
|
195
|
+
"/path/that/definitely/does/not/exist/libwebview.so";
|
|
196
|
+
const mod = await import("../webview-fallback");
|
|
197
|
+
mod._resetFFICache();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
afterEach(async () => {
|
|
201
|
+
if (ORIGINAL_ENV !== undefined) {
|
|
202
|
+
process.env.MANDU_LIBWEBVIEW_PATH = ORIGINAL_ENV;
|
|
203
|
+
} else {
|
|
204
|
+
delete process.env.MANDU_LIBWEBVIEW_PATH;
|
|
205
|
+
}
|
|
206
|
+
const mod = await import("../webview-fallback");
|
|
207
|
+
mod._resetFFICache();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("throws an actionable error enumerating every probed path", async () => {
|
|
211
|
+
const { loadFFILibwebview } = await import("../webview-fallback");
|
|
212
|
+
try {
|
|
213
|
+
await loadFFILibwebview();
|
|
214
|
+
throw new Error("unreachable — loadFFILibwebview should have thrown");
|
|
215
|
+
} catch (err) {
|
|
216
|
+
expect(err).toBeInstanceOf(Error);
|
|
217
|
+
const msg = (err as Error).message;
|
|
218
|
+
// Actionable hints — install options + env var hint.
|
|
219
|
+
expect(msg).toContain("libwebview");
|
|
220
|
+
expect(msg).toContain("MANDU_LIBWEBVIEW_PATH");
|
|
221
|
+
expect(msg).toContain("webview/webview");
|
|
222
|
+
// Should enumerate the failing candidate we injected.
|
|
223
|
+
expect(msg).toContain("libwebview.so");
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// ─── Opt-in E2E (real window) ──────────────────────────────────────────────
|
|
229
|
+
//
|
|
230
|
+
// Runs ONLY when MANDU_DESKTOP_FALLBACK_E2E=1 AND platform supports it.
|
|
231
|
+
// CI skips this block unconditionally.
|
|
232
|
+
|
|
233
|
+
const canOpenFallbackWindow =
|
|
234
|
+
process.env.MANDU_DESKTOP_FALLBACK_E2E === "1" &&
|
|
235
|
+
(process.platform === "win32" ||
|
|
236
|
+
process.platform === "darwin" ||
|
|
237
|
+
process.platform === "linux");
|
|
238
|
+
|
|
239
|
+
describe.skipIf(!canOpenFallbackWindow)(
|
|
240
|
+
"@mandujs/core/desktop/webview-fallback — browser smoke (opt-in)",
|
|
241
|
+
() => {
|
|
242
|
+
it("opens a data: URL window via the FFI fallback", async () => {
|
|
243
|
+
const { createFallbackWebview } = await import("../webview-fallback");
|
|
244
|
+
const handle = await createFallbackWebview({
|
|
245
|
+
url: "data:text/html,<h1>Mandu FFI fallback smoke</h1>",
|
|
246
|
+
title: "Mandu Fallback E2E",
|
|
247
|
+
width: 400,
|
|
248
|
+
height: 300,
|
|
249
|
+
});
|
|
250
|
+
await handle.close();
|
|
251
|
+
await handle.closed;
|
|
252
|
+
});
|
|
253
|
+
},
|
|
254
|
+
);
|