@mandujs/core 0.54.31 → 0.55.0-beta.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 +106 -210
- package/scripts/postinstall-lock.ts +153 -153
- 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 +15 -15
- package/src/a11y/types.ts +125 -125
- package/src/agent/__tests__/apply.test.ts +224 -0
- package/src/agent/__tests__/context.test.ts +97 -98
- package/src/agent/apply.ts +1031 -0
- package/src/agent/context.ts +552 -552
- package/src/agent/index.ts +4 -3
- package/src/agent/plan.ts +161 -243
- package/src/agent/repair.ts +239 -162
- package/src/agent/sync.ts +197 -198
- package/src/agent/types.ts +242 -94
- package/src/agent/verify.ts +55 -55
- package/src/auth/__tests__/login.test.ts +1 -1
- package/src/auth/__tests__/password.test.ts +15 -5
- package/src/auth/__tests__/reset.test.ts +2 -2
- 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 +14 -2
- 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/brain/doctor/analyzer.ts +7 -7
- package/src/bundler/__snapshots__/build.test.ts.snap +5 -5
- package/src/bundler/__tests__/build-runner.ts +166 -166
- package/src/bundler/__tests__/client-boundary-transform.test.ts +524 -524
- package/src/bundler/__tests__/cold-start.test.ts +60 -60
- package/src/bundler/__tests__/css.test.ts +49 -20
- 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 +24 -24
- package/src/bundler/__tests__/generation.test.ts +447 -0
- package/src/bundler/__tests__/hdr.test.ts +24 -18
- package/src/bundler/__tests__/hmr-client.test.ts +62 -24
- package/src/bundler/__tests__/jsx-runtime-shim.test.ts +179 -140
- package/src/bundler/__tests__/manifest-schema.test.ts +305 -266
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
- package/src/bundler/__tests__/reverse-import-graph.test.ts +42 -42
- 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/analyzer.ts +15 -15
- package/src/bundler/budget.ts +404 -404
- package/src/bundler/build.test.ts +898 -915
- package/src/bundler/build.ts +113 -24
- package/src/bundler/client-boundary-transform.ts +977 -977
- package/src/bundler/css.ts +65 -44
- package/src/bundler/dev.ts +105 -73
- package/src/bundler/fast-refresh-preamble.ts +47 -47
- package/src/bundler/generation.ts +602 -0
- package/src/bundler/index.ts +3 -3
- package/src/bundler/manifest-schema.ts +55 -40
- package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +13 -13
- 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 +16 -15
- 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/prerender.ts +29 -9
- package/src/bundler/reverse-import-graph.ts +339 -339
- package/src/bundler/safe-build.test.ts +1 -1
- package/src/bundler/safe-build.ts +103 -103
- package/src/bundler/scenario-matrix.ts +229 -229
- package/src/bundler/types.ts +58 -56
- 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__/props-serialization.test.ts +37 -37
- 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 +2 -2
- package/src/client/index.ts +1 -1
- package/src/client/island.ts +79 -79
- package/src/client/prefetch-helper.ts +55 -55
- package/src/client/props-serialization.ts +233 -233
- package/src/client/runtime-entry.ts +598 -598
- package/src/client/runtime.ts +1 -1
- package/src/client/serialize.ts +50 -50
- 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-compat.ts +3 -0
- package/src/components/Image.tsx +162 -162
- package/src/config/validate.ts +1 -1
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/collection.ts +9 -9
- 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/generate-types.ts +1 -1
- package/src/content/index.ts +2 -2
- 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/types.ts +58 -58
- package/src/db/__tests__/db.test.ts +9 -9
- package/src/db/index.ts +2 -2
- 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 +82 -82
- 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__/smoke.test.ts +2 -2
- package/src/desktop/__tests__/webview-fallback.test.ts +12 -32
- package/src/desktop/__tests__/window.test.ts +20 -99
- 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/webview-fallback.ts +17 -4
- package/src/desktop/window.ts +17 -8
- 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/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 +16 -16
- package/src/devtools/client/components/panel/network-panel.tsx +291 -291
- package/src/devtools/client/components/panel/panel-container.tsx +1 -1
- 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/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/types.ts +35 -35
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +233 -233
- package/src/diagnose/__tests__/checks.test.ts +136 -136
- package/src/diagnose/checks.ts +185 -185
- package/src/diagnose/index.ts +17 -17
- package/src/diagnose/run.ts +10 -10
- 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/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 +5 -1
- package/src/filling/auth.ts +308 -308
- package/src/filling/body-parse.test.ts +60 -60
- package/src/filling/cookie-codec.ts +5 -3
- package/src/filling/deps.ts +265 -265
- package/src/filling/head-method.test.ts +154 -154
- 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/generate.ts +30 -30
- package/src/generator/index.ts +3 -3
- package/src/generator/templates.test.ts +48 -48
- package/src/generator/templates.ts +219 -219
- 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/check.ts +39 -24
- package/src/guard/config-guard.ts +13 -13
- 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/fs-routes-policy.ts +51 -51
- package/src/guard/graph.ts +1 -1
- package/src/guard/healing.ts +36 -36
- package/src/guard/index.ts +11 -11
- 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/__tests__/id.test.ts +3 -3
- package/src/id/index.ts +105 -105
- package/src/index.ts +9 -48
- package/src/internal/client-boundary.ts +266 -266
- package/src/internal/index.ts +2 -2
- package/src/kitchen/api/agent-devtools-api.ts +779 -779
- package/src/kitchen/api/bundle-inspector.ts +179 -0
- package/src/kitchen/api/errors-grouping.ts +126 -126
- package/src/kitchen/api/file-api.ts +11 -11
- package/src/kitchen/kitchen-handler.ts +36 -0
- package/src/kitchen/kitchen-ui.ts +456 -0
- 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/perf/user-marks.ts +1 -1
- 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 +7 -7
- package/src/resource/__tests__/schema.test.ts +14 -14
- package/src/resource/ddl/__tests__/diff.test.ts +639 -639
- package/src/resource/ddl/__tests__/emit.test.ts +165 -165
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
- package/src/resource/ddl/emit.ts +146 -146
- 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/generator-schema.ts +11 -11
- package/src/resource/generators/slot.ts +72 -72
- package/src/resource/schema.ts +21 -21
- package/src/router/client-entry.test.ts +227 -227
- package/src/router/client-entry.ts +218 -218
- package/src/router/fs-patterns.test.ts +96 -96
- package/src/router/fs-routes.test.ts +532 -532
- package/src/router/fs-routes.ts +53 -53
- package/src/router/fs-scanner.ts +216 -216
- package/src/router/fs-types.ts +19 -19
- package/src/router/route-source-analyzer.ts +521 -521
- 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__/devtools-adapter.test.ts +68 -68
- 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__/inline-client-hydration.test.ts +237 -237
- package/src/runtime/__tests__/not-found.test.ts +152 -152
- package/src/runtime/__tests__/observability-lifecycle.test.ts +103 -103
- package/src/runtime/__tests__/page-render-response.test.ts +517 -517
- package/src/runtime/__tests__/request-middleware.test.ts +70 -70
- package/src/runtime/__tests__/searchparams-page-props.test.ts +81 -81
- 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/devtools-adapter.ts +68 -68
- package/src/runtime/escape.ts +34 -34
- package/src/runtime/fast-refresh-runtime.ts +322 -322
- package/src/runtime/fast-refresh-types.ts +1 -1
- package/src/runtime/handler.ts +65 -65
- package/src/runtime/handlers.ts +30 -11
- 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/observability-lifecycle.ts +290 -290
- package/src/runtime/openapi-endpoint.ts +236 -236
- package/src/runtime/page-render-response.ts +287 -274
- package/src/runtime/ppr.ts +74 -74
- package/src/runtime/rate-limit.ts +1 -1
- package/src/runtime/redirect.ts +1 -1
- package/src/runtime/registry.ts +171 -171
- package/src/runtime/request-middleware.ts +31 -31
- package/src/runtime/router.test.ts +4 -4
- package/src/runtime/router.ts +10 -10
- package/src/runtime/server.ts +39 -20
- package/src/runtime/shims.ts +48 -48
- package/src/runtime/ssr.ts +43 -17
- package/src/runtime/static-files.ts +369 -289
- package/src/runtime/streaming-ssr.ts +219 -180
- package/src/runtime/trace.ts +144 -144
- package/src/scheduler/__tests__/scheduler.test.ts +12 -11
- package/src/scheduler/index.ts +11 -5
- 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/spec/schema.ts +35 -35
- 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/index.ts +9 -3
- package/src/testing/lcov.ts +192 -0
- 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/__tests__/watcher.test.ts +59 -59
- package/src/watcher/watcher.ts +61 -61
|
@@ -1,153 +1,153 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for useSSE hook and readStreamWithYield utility
|
|
3
|
-
*
|
|
4
|
-
* These tests verify the microtask-starvation-safe ReadableStream reading
|
|
5
|
-
* utilities work correctly.
|
|
6
|
-
*/
|
|
7
|
-
import { describe, test, expect, beforeEach, mock } from "bun:test";
|
|
8
|
-
import { readStreamWithYield } from "../use-sse";
|
|
9
|
-
|
|
10
|
-
// Note: useSSE is a React hook and would need a React testing environment.
|
|
11
|
-
// We test the lower-level readStreamWithYield utility here since it contains
|
|
12
|
-
// the core macrotask-yielding logic that prevents main thread blocking.
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Helper: create a ReadableStream from an array of strings
|
|
16
|
-
*/
|
|
17
|
-
function createMockStream(chunks: string[]): ReadableStream<Uint8Array> {
|
|
18
|
-
const encoder = new TextEncoder();
|
|
19
|
-
let index = 0;
|
|
20
|
-
|
|
21
|
-
return new ReadableStream({
|
|
22
|
-
pull(controller) {
|
|
23
|
-
if (index < chunks.length) {
|
|
24
|
-
controller.enqueue(encoder.encode(chunks[index++]));
|
|
25
|
-
} else {
|
|
26
|
-
controller.close();
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
describe("readStreamWithYield", () => {
|
|
33
|
-
test("should read all chunks from a stream", async () => {
|
|
34
|
-
const chunks = ["Hello", " ", "World"];
|
|
35
|
-
const stream = createMockStream(chunks);
|
|
36
|
-
const received: string[] = [];
|
|
37
|
-
|
|
38
|
-
await readStreamWithYield(stream, {
|
|
39
|
-
onChunk: (text) => received.push(text),
|
|
40
|
-
onDone: () => {},
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
expect(received).toEqual(chunks);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("should call onDone when stream completes", async () => {
|
|
47
|
-
const stream = createMockStream(["a", "b"]);
|
|
48
|
-
let doneCalled = false;
|
|
49
|
-
|
|
50
|
-
await readStreamWithYield(stream, {
|
|
51
|
-
onChunk: () => {},
|
|
52
|
-
onDone: () => {
|
|
53
|
-
doneCalled = true;
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
expect(doneCalled).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test("should call onError on stream failure", async () => {
|
|
61
|
-
const stream = new ReadableStream({
|
|
62
|
-
start(controller) {
|
|
63
|
-
controller.error(new Error("test error"));
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
let errorCaught: Error | null = null;
|
|
68
|
-
|
|
69
|
-
await readStreamWithYield(stream, {
|
|
70
|
-
onChunk: () => {},
|
|
71
|
-
onError: (err) => {
|
|
72
|
-
errorCaught = err;
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
expect(errorCaught).not.toBeNull();
|
|
77
|
-
expect(errorCaught!.message).toBe("test error");
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("should respect abort signal", async () => {
|
|
81
|
-
const controller = new AbortController();
|
|
82
|
-
const chunks = ["a", "b", "c", "d", "e"];
|
|
83
|
-
const stream = createMockStream(chunks);
|
|
84
|
-
const received: string[] = [];
|
|
85
|
-
|
|
86
|
-
// Abort after first chunk
|
|
87
|
-
let chunkCount = 0;
|
|
88
|
-
|
|
89
|
-
await readStreamWithYield(stream, {
|
|
90
|
-
onChunk: (text) => {
|
|
91
|
-
received.push(text);
|
|
92
|
-
chunkCount++;
|
|
93
|
-
if (chunkCount >= 2) {
|
|
94
|
-
controller.abort();
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
signal: controller.signal,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Should have received at most 2-3 chunks (abort may not be immediate)
|
|
101
|
-
expect(received.length).toBeLessThanOrEqual(3);
|
|
102
|
-
expect(received.length).toBeGreaterThanOrEqual(2);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test("should handle empty stream", async () => {
|
|
106
|
-
const stream = createMockStream([]);
|
|
107
|
-
const received: string[] = [];
|
|
108
|
-
let doneCalled = false;
|
|
109
|
-
|
|
110
|
-
await readStreamWithYield(stream, {
|
|
111
|
-
onChunk: (text) => received.push(text),
|
|
112
|
-
onDone: () => {
|
|
113
|
-
doneCalled = true;
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
expect(received).toEqual([]);
|
|
118
|
-
expect(doneCalled).toBe(true);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test("should yield between chunks (non-blocking)", async () => {
|
|
122
|
-
// Create a stream with many rapid chunks
|
|
123
|
-
const chunkCount = 50;
|
|
124
|
-
const chunks = Array.from({ length: chunkCount }, (_, i) => `chunk-${i}`);
|
|
125
|
-
const stream = createMockStream(chunks);
|
|
126
|
-
const received: string[] = [];
|
|
127
|
-
|
|
128
|
-
// Track that setTimeout(0) yields are happening by checking
|
|
129
|
-
// that the promise resolves in multiple event loop ticks
|
|
130
|
-
let macrotaskCount = 0;
|
|
131
|
-
const originalSetTimeout = globalThis.setTimeout;
|
|
132
|
-
|
|
133
|
-
// Count macrotask yields (setTimeout(0) calls from yieldToMacrotask)
|
|
134
|
-
const timeoutSpy = mock((fn: Function, ms: number) => {
|
|
135
|
-
if (ms === 0) macrotaskCount++;
|
|
136
|
-
return originalSetTimeout(fn, ms);
|
|
137
|
-
});
|
|
138
|
-
// @ts-expect-error - mock override
|
|
139
|
-
globalThis.setTimeout = timeoutSpy;
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
await readStreamWithYield(stream, {
|
|
143
|
-
onChunk: (text) => received.push(text),
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// Every chunk should cause a macrotask yield
|
|
147
|
-
expect(received.length).toBe(chunkCount);
|
|
148
|
-
expect(macrotaskCount).toBeGreaterThanOrEqual(chunkCount);
|
|
149
|
-
} finally {
|
|
150
|
-
globalThis.setTimeout = originalSetTimeout;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Tests for useSSE hook and readStreamWithYield utility
|
|
3
|
+
*
|
|
4
|
+
* These tests verify the microtask-starvation-safe ReadableStream reading
|
|
5
|
+
* utilities work correctly.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, test, expect, beforeEach, mock } from "bun:test";
|
|
8
|
+
import { readStreamWithYield } from "../use-sse";
|
|
9
|
+
|
|
10
|
+
// Note: useSSE is a React hook and would need a React testing environment.
|
|
11
|
+
// We test the lower-level readStreamWithYield utility here since it contains
|
|
12
|
+
// the core macrotask-yielding logic that prevents main thread blocking.
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Helper: create a ReadableStream from an array of strings
|
|
16
|
+
*/
|
|
17
|
+
function createMockStream(chunks: string[]): ReadableStream<Uint8Array> {
|
|
18
|
+
const encoder = new TextEncoder();
|
|
19
|
+
let index = 0;
|
|
20
|
+
|
|
21
|
+
return new ReadableStream({
|
|
22
|
+
pull(controller) {
|
|
23
|
+
if (index < chunks.length) {
|
|
24
|
+
controller.enqueue(encoder.encode(chunks[index++]));
|
|
25
|
+
} else {
|
|
26
|
+
controller.close();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe("readStreamWithYield", () => {
|
|
33
|
+
test("should read all chunks from a stream", async () => {
|
|
34
|
+
const chunks = ["Hello", " ", "World"];
|
|
35
|
+
const stream = createMockStream(chunks);
|
|
36
|
+
const received: string[] = [];
|
|
37
|
+
|
|
38
|
+
await readStreamWithYield(stream, {
|
|
39
|
+
onChunk: (text) => received.push(text),
|
|
40
|
+
onDone: () => {},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(received).toEqual(chunks);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("should call onDone when stream completes", async () => {
|
|
47
|
+
const stream = createMockStream(["a", "b"]);
|
|
48
|
+
let doneCalled = false;
|
|
49
|
+
|
|
50
|
+
await readStreamWithYield(stream, {
|
|
51
|
+
onChunk: () => {},
|
|
52
|
+
onDone: () => {
|
|
53
|
+
doneCalled = true;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(doneCalled).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("should call onError on stream failure", async () => {
|
|
61
|
+
const stream = new ReadableStream({
|
|
62
|
+
start(controller) {
|
|
63
|
+
controller.error(new Error("test error"));
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
let errorCaught: Error | null = null;
|
|
68
|
+
|
|
69
|
+
await readStreamWithYield(stream, {
|
|
70
|
+
onChunk: () => {},
|
|
71
|
+
onError: (err) => {
|
|
72
|
+
errorCaught = err;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(errorCaught).not.toBeNull();
|
|
77
|
+
expect(errorCaught!.message).toBe("test error");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("should respect abort signal", async () => {
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const chunks = ["a", "b", "c", "d", "e"];
|
|
83
|
+
const stream = createMockStream(chunks);
|
|
84
|
+
const received: string[] = [];
|
|
85
|
+
|
|
86
|
+
// Abort after first chunk
|
|
87
|
+
let chunkCount = 0;
|
|
88
|
+
|
|
89
|
+
await readStreamWithYield(stream, {
|
|
90
|
+
onChunk: (text) => {
|
|
91
|
+
received.push(text);
|
|
92
|
+
chunkCount++;
|
|
93
|
+
if (chunkCount >= 2) {
|
|
94
|
+
controller.abort();
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
signal: controller.signal,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Should have received at most 2-3 chunks (abort may not be immediate)
|
|
101
|
+
expect(received.length).toBeLessThanOrEqual(3);
|
|
102
|
+
expect(received.length).toBeGreaterThanOrEqual(2);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("should handle empty stream", async () => {
|
|
106
|
+
const stream = createMockStream([]);
|
|
107
|
+
const received: string[] = [];
|
|
108
|
+
let doneCalled = false;
|
|
109
|
+
|
|
110
|
+
await readStreamWithYield(stream, {
|
|
111
|
+
onChunk: (text) => received.push(text),
|
|
112
|
+
onDone: () => {
|
|
113
|
+
doneCalled = true;
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
expect(received).toEqual([]);
|
|
118
|
+
expect(doneCalled).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("should yield between chunks (non-blocking)", async () => {
|
|
122
|
+
// Create a stream with many rapid chunks
|
|
123
|
+
const chunkCount = 50;
|
|
124
|
+
const chunks = Array.from({ length: chunkCount }, (_, i) => `chunk-${i}`);
|
|
125
|
+
const stream = createMockStream(chunks);
|
|
126
|
+
const received: string[] = [];
|
|
127
|
+
|
|
128
|
+
// Track that setTimeout(0) yields are happening by checking
|
|
129
|
+
// that the promise resolves in multiple event loop ticks
|
|
130
|
+
let macrotaskCount = 0;
|
|
131
|
+
const originalSetTimeout = globalThis.setTimeout;
|
|
132
|
+
|
|
133
|
+
// Count macrotask yields (setTimeout(0) calls from yieldToMacrotask)
|
|
134
|
+
const timeoutSpy = mock((fn: Function, ms: number) => {
|
|
135
|
+
if (ms === 0) macrotaskCount++;
|
|
136
|
+
return originalSetTimeout(fn, ms);
|
|
137
|
+
});
|
|
138
|
+
// @ts-expect-error - mock override
|
|
139
|
+
globalThis.setTimeout = timeoutSpy;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
await readStreamWithYield(stream, {
|
|
143
|
+
onChunk: (text) => received.push(text),
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Every chunk should cause a macrotask yield
|
|
147
|
+
expect(received.length).toBe(chunkCount);
|
|
148
|
+
expect(macrotaskCount).toBeGreaterThanOrEqual(chunkCount);
|
|
149
|
+
} finally {
|
|
150
|
+
globalThis.setTimeout = originalSetTimeout;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
package/src/client/globals.ts
CHANGED