@heojeongbo/wirestage 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/LICENSES.md +21 -0
- package/README.md +150 -2
- package/dist/app/playwright/index.d.ts +3 -0
- package/dist/app/playwright/index.d.ts.map +1 -0
- package/dist/app/playwright/index.js +2 -0
- package/dist/app/playwright/index.js.map +1 -0
- package/dist/app/playwright/lib/fixture.d.ts +61 -0
- package/dist/app/playwright/lib/fixture.d.ts.map +1 -0
- package/dist/app/playwright/lib/fixture.js +110 -0
- package/dist/app/playwright/lib/fixture.js.map +1 -0
- package/dist/connect.d.ts +7 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +7 -0
- package/dist/connect.js.map +1 -0
- package/dist/entities/frame/@x/plugin.d.ts +9 -0
- package/dist/entities/frame/@x/plugin.d.ts.map +1 -0
- package/dist/entities/frame/@x/plugin.js +2 -0
- package/dist/entities/frame/@x/plugin.js.map +1 -0
- package/dist/entities/frame/index.d.ts +6 -0
- package/dist/entities/frame/index.d.ts.map +1 -0
- package/dist/entities/frame/index.js +4 -0
- package/dist/entities/frame/index.js.map +1 -0
- package/dist/entities/frame/lib/filter.d.ts +8 -0
- package/dist/entities/frame/lib/filter.d.ts.map +1 -0
- package/dist/entities/frame/lib/filter.js +62 -0
- package/dist/entities/frame/lib/filter.js.map +1 -0
- package/dist/entities/frame/lib/payload.d.ts +8 -0
- package/dist/entities/frame/lib/payload.d.ts.map +1 -0
- package/dist/entities/frame/lib/payload.js +42 -0
- package/dist/entities/frame/lib/payload.js.map +1 -0
- package/dist/entities/frame/lib/snapshot.d.ts +15 -0
- package/dist/entities/frame/lib/snapshot.d.ts.map +1 -0
- package/dist/entities/frame/lib/snapshot.js +90 -0
- package/dist/entities/frame/lib/snapshot.js.map +1 -0
- package/dist/entities/frame/lib/timeline.d.ts +23 -0
- package/dist/entities/frame/lib/timeline.d.ts.map +1 -0
- package/dist/entities/frame/lib/timeline.js +122 -0
- package/dist/entities/frame/lib/timeline.js.map +1 -0
- package/dist/entities/frame/model/frame.d.ts +182 -0
- package/dist/entities/frame/model/frame.d.ts.map +1 -0
- package/dist/entities/frame/model/frame.js +2 -0
- package/dist/entities/frame/model/frame.js.map +1 -0
- package/dist/entities/plugin/index.d.ts +9 -0
- package/dist/entities/plugin/index.d.ts.map +1 -0
- package/dist/entities/plugin/index.js +3 -0
- package/dist/entities/plugin/index.js.map +1 -0
- package/dist/entities/plugin/lib/define-plugin.d.ts +8 -0
- package/dist/entities/plugin/lib/define-plugin.d.ts.map +1 -0
- package/dist/entities/plugin/lib/define-plugin.js +9 -0
- package/dist/entities/plugin/lib/define-plugin.js.map +1 -0
- package/dist/entities/plugin/lib/named.d.ts +10 -0
- package/dist/entities/plugin/lib/named.d.ts.map +1 -0
- package/dist/entities/plugin/lib/named.js +17 -0
- package/dist/entities/plugin/lib/named.js.map +1 -0
- package/dist/entities/plugin/model/attachment.d.ts +18 -0
- package/dist/entities/plugin/model/attachment.d.ts.map +1 -0
- package/dist/entities/plugin/model/attachment.js +2 -0
- package/dist/entities/plugin/model/attachment.js.map +1 -0
- package/dist/entities/plugin/model/http.d.ts +126 -0
- package/dist/entities/plugin/model/http.d.ts.map +1 -0
- package/dist/entities/plugin/model/http.js +2 -0
- package/dist/entities/plugin/model/http.js.map +1 -0
- package/dist/entities/plugin/model/page.d.ts +100 -0
- package/dist/entities/plugin/model/page.d.ts.map +1 -0
- package/dist/entities/plugin/model/page.js +2 -0
- package/dist/entities/plugin/model/page.js.map +1 -0
- package/dist/entities/plugin/model/plugin.d.ts +83 -0
- package/dist/entities/plugin/model/plugin.d.ts.map +1 -0
- package/dist/entities/plugin/model/plugin.js +2 -0
- package/dist/entities/plugin/model/plugin.js.map +1 -0
- package/dist/entities/plugin/model/socket.d.ts +102 -0
- package/dist/entities/plugin/model/socket.d.ts.map +1 -0
- package/dist/entities/plugin/model/socket.js +2 -0
- package/dist/entities/plugin/model/socket.js.map +1 -0
- package/dist/entities/plugin/model/stream.d.ts +43 -0
- package/dist/entities/plugin/model/stream.d.ts.map +1 -0
- package/dist/entities/plugin/model/stream.js +2 -0
- package/dist/entities/plugin/model/stream.js.map +1 -0
- package/dist/features/connect/index.d.ts +5 -0
- package/dist/features/connect/index.d.ts.map +1 -0
- package/dist/features/connect/index.js +4 -0
- package/dist/features/connect/index.js.map +1 -0
- package/dist/features/connect/lib/calls.d.ts +9 -0
- package/dist/features/connect/lib/calls.d.ts.map +1 -0
- package/dist/features/connect/lib/calls.js +46 -0
- package/dist/features/connect/lib/calls.js.map +1 -0
- package/dist/features/connect/lib/client.d.ts +33 -0
- package/dist/features/connect/lib/client.d.ts.map +1 -0
- package/dist/features/connect/lib/client.js +147 -0
- package/dist/features/connect/lib/client.js.map +1 -0
- package/dist/features/connect/lib/create-connect.d.ts +14 -0
- package/dist/features/connect/lib/create-connect.d.ts.map +1 -0
- package/dist/features/connect/lib/create-connect.js +124 -0
- package/dist/features/connect/lib/create-connect.js.map +1 -0
- package/dist/features/connect/lib/faults.d.ts +18 -0
- package/dist/features/connect/lib/faults.d.ts.map +1 -0
- package/dist/features/connect/lib/faults.js +85 -0
- package/dist/features/connect/lib/faults.js.map +1 -0
- package/dist/features/connect/lib/protocol.d.ts +42 -0
- package/dist/features/connect/lib/protocol.d.ts.map +1 -0
- package/dist/features/connect/lib/protocol.js +228 -0
- package/dist/features/connect/lib/protocol.js.map +1 -0
- package/dist/features/connect/lib/record.d.ts +14 -0
- package/dist/features/connect/lib/record.d.ts.map +1 -0
- package/dist/features/connect/lib/record.js +36 -0
- package/dist/features/connect/lib/record.js.map +1 -0
- package/dist/features/connect/lib/recorder.d.ts +77 -0
- package/dist/features/connect/lib/recorder.d.ts.map +1 -0
- package/dist/features/connect/lib/recorder.js +209 -0
- package/dist/features/connect/lib/recorder.js.map +1 -0
- package/dist/features/connect/lib/rules.d.ts +51 -0
- package/dist/features/connect/lib/rules.d.ts.map +1 -0
- package/dist/features/connect/lib/rules.js +222 -0
- package/dist/features/connect/lib/rules.js.map +1 -0
- package/dist/features/connect/lib/serve.d.ts +10 -0
- package/dist/features/connect/lib/serve.d.ts.map +1 -0
- package/dist/features/connect/lib/serve.js +78 -0
- package/dist/features/connect/lib/serve.js.map +1 -0
- package/dist/features/connect/lib/status-of.d.ts +11 -0
- package/dist/features/connect/lib/status-of.d.ts.map +1 -0
- package/dist/features/connect/lib/status-of.js +22 -0
- package/dist/features/connect/lib/status-of.js.map +1 -0
- package/dist/features/connect/lib/stubs.d.ts +18 -0
- package/dist/features/connect/lib/stubs.d.ts.map +1 -0
- package/dist/features/connect/lib/stubs.js +174 -0
- package/dist/features/connect/lib/stubs.js.map +1 -0
- package/dist/features/connect/lib/universal.d.ts +19 -0
- package/dist/features/connect/lib/universal.d.ts.map +1 -0
- package/dist/features/connect/lib/universal.js +71 -0
- package/dist/features/connect/lib/universal.js.map +1 -0
- package/dist/features/connect/model/types.d.ts +247 -0
- package/dist/features/connect/model/types.d.ts.map +1 -0
- package/dist/features/connect/model/types.js +2 -0
- package/dist/features/connect/model/types.js.map +1 -0
- package/dist/features/rest/index.d.ts +5 -0
- package/dist/features/rest/index.d.ts.map +1 -0
- package/dist/features/rest/index.js +3 -0
- package/dist/features/rest/index.js.map +1 -0
- package/dist/features/rest/lib/calls.d.ts +8 -0
- package/dist/features/rest/lib/calls.d.ts.map +1 -0
- package/dist/features/rest/lib/calls.js +32 -0
- package/dist/features/rest/lib/calls.js.map +1 -0
- package/dist/features/rest/lib/create-rest.d.ts +8 -0
- package/dist/features/rest/lib/create-rest.d.ts.map +1 -0
- package/dist/features/rest/lib/create-rest.js +136 -0
- package/dist/features/rest/lib/create-rest.js.map +1 -0
- package/dist/features/rest/lib/path.d.ts +14 -0
- package/dist/features/rest/lib/path.d.ts.map +1 -0
- package/dist/features/rest/lib/path.js +58 -0
- package/dist/features/rest/lib/path.js.map +1 -0
- package/dist/features/rest/lib/reply.d.ts +25 -0
- package/dist/features/rest/lib/reply.d.ts.map +1 -0
- package/dist/features/rest/lib/reply.js +40 -0
- package/dist/features/rest/lib/reply.js.map +1 -0
- package/dist/features/rest/model/types.d.ts +74 -0
- package/dist/features/rest/model/types.d.ts.map +1 -0
- package/dist/features/rest/model/types.js +2 -0
- package/dist/features/rest/model/types.js.map +1 -0
- package/dist/features/sse/index.d.ts +4 -0
- package/dist/features/sse/index.d.ts.map +1 -0
- package/dist/features/sse/index.js +3 -0
- package/dist/features/sse/index.js.map +1 -0
- package/dist/features/sse/lib/create-sse.d.ts +9 -0
- package/dist/features/sse/lib/create-sse.d.ts.map +1 -0
- package/dist/features/sse/lib/create-sse.js +120 -0
- package/dist/features/sse/lib/create-sse.js.map +1 -0
- package/dist/features/sse/lib/encode.d.ts +8 -0
- package/dist/features/sse/lib/encode.d.ts.map +1 -0
- package/dist/features/sse/lib/encode.js +29 -0
- package/dist/features/sse/lib/encode.js.map +1 -0
- package/dist/features/sse/model/types.d.ts +62 -0
- package/dist/features/sse/model/types.d.ts.map +1 -0
- package/dist/features/sse/model/types.js +2 -0
- package/dist/features/sse/model/types.js.map +1 -0
- package/dist/features/webrtc/index.d.ts +3 -0
- package/dist/features/webrtc/index.d.ts.map +1 -0
- package/dist/features/webrtc/index.js +2 -0
- package/dist/features/webrtc/index.js.map +1 -0
- package/dist/features/webrtc/lib/create-webrtc.d.ts +9 -0
- package/dist/features/webrtc/lib/create-webrtc.d.ts.map +1 -0
- package/dist/features/webrtc/lib/create-webrtc.js +123 -0
- package/dist/features/webrtc/lib/create-webrtc.js.map +1 -0
- package/dist/features/webrtc/lib/rtc-page-module.d.ts +22 -0
- package/dist/features/webrtc/lib/rtc-page-module.d.ts.map +1 -0
- package/dist/features/webrtc/lib/rtc-page-module.js +161 -0
- package/dist/features/webrtc/lib/rtc-page-module.js.map +1 -0
- package/dist/features/webrtc/lib/to-frame.d.ts +9 -0
- package/dist/features/webrtc/lib/to-frame.d.ts.map +1 -0
- package/dist/features/webrtc/lib/to-frame.js +43 -0
- package/dist/features/webrtc/lib/to-frame.js.map +1 -0
- package/dist/features/webrtc/model/types.d.ts +70 -0
- package/dist/features/webrtc/model/types.d.ts.map +1 -0
- package/dist/features/webrtc/model/types.js +2 -0
- package/dist/features/webrtc/model/types.js.map +1 -0
- package/dist/features/websocket/index.d.ts +3 -0
- package/dist/features/websocket/index.d.ts.map +1 -0
- package/dist/features/websocket/index.js +2 -0
- package/dist/features/websocket/index.js.map +1 -0
- package/dist/features/websocket/lib/create-websocket.d.ts +9 -0
- package/dist/features/websocket/lib/create-websocket.d.ts.map +1 -0
- package/dist/features/websocket/lib/create-websocket.js +34 -0
- package/dist/features/websocket/lib/create-websocket.js.map +1 -0
- package/dist/features/websocket/lib/mock.d.ts +6 -0
- package/dist/features/websocket/lib/mock.d.ts.map +1 -0
- package/dist/features/websocket/lib/mock.js +96 -0
- package/dist/features/websocket/lib/mock.js.map +1 -0
- package/dist/features/websocket/lib/proxy.d.ts +9 -0
- package/dist/features/websocket/lib/proxy.d.ts.map +1 -0
- package/dist/features/websocket/lib/proxy.js +107 -0
- package/dist/features/websocket/lib/proxy.js.map +1 -0
- package/dist/features/websocket/lib/wire.d.ts +16 -0
- package/dist/features/websocket/lib/wire.d.ts.map +1 -0
- package/dist/features/websocket/lib/wire.js +46 -0
- package/dist/features/websocket/lib/wire.js.map +1 -0
- package/dist/features/websocket/model/types.d.ts +129 -0
- package/dist/features/websocket/model/types.d.ts.map +1 -0
- package/dist/features/websocket/model/types.js +2 -0
- package/dist/features/websocket/model/types.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/playwright.d.ts +4 -0
- package/dist/playwright.d.ts.map +1 -0
- package/dist/playwright.js +2 -0
- package/dist/playwright.js.map +1 -0
- package/dist/rest.d.ts +3 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +3 -0
- package/dist/rest.js.map +1 -0
- package/dist/shared/api/http-server/index.d.ts +3 -0
- package/dist/shared/api/http-server/index.d.ts.map +1 -0
- package/dist/shared/api/http-server/index.js +2 -0
- package/dist/shared/api/http-server/index.js.map +1 -0
- package/dist/shared/api/http-server/listen.d.ts +25 -0
- package/dist/shared/api/http-server/listen.d.ts.map +1 -0
- package/dist/shared/api/http-server/listen.js +44 -0
- package/dist/shared/api/http-server/listen.js.map +1 -0
- package/dist/shared/api/playwright/index.d.ts +2 -0
- package/dist/shared/api/playwright/index.d.ts.map +1 -0
- package/dist/shared/api/playwright/index.js +2 -0
- package/dist/shared/api/playwright/index.js.map +1 -0
- package/dist/shared/api/playwright/ports.d.ts +117 -0
- package/dist/shared/api/playwright/ports.d.ts.map +1 -0
- package/dist/shared/api/playwright/ports.js +11 -0
- package/dist/shared/api/playwright/ports.js.map +1 -0
- package/dist/shared/api/stream-server/index.d.ts +3 -0
- package/dist/shared/api/stream-server/index.d.ts.map +1 -0
- package/dist/shared/api/stream-server/index.js +2 -0
- package/dist/shared/api/stream-server/index.js.map +1 -0
- package/dist/shared/api/stream-server/stream-server.d.ts +43 -0
- package/dist/shared/api/stream-server/stream-server.d.ts.map +1 -0
- package/dist/shared/api/stream-server/stream-server.js +160 -0
- package/dist/shared/api/stream-server/stream-server.js.map +1 -0
- package/dist/shared/lib/async/arrivals.d.ts +31 -0
- package/dist/shared/lib/async/arrivals.d.ts.map +1 -0
- package/dist/shared/lib/async/arrivals.js +57 -0
- package/dist/shared/lib/async/arrivals.js.map +1 -0
- package/dist/shared/lib/async/async-queue.d.ts +23 -0
- package/dist/shared/lib/async/async-queue.d.ts.map +1 -0
- package/dist/shared/lib/async/async-queue.js +80 -0
- package/dist/shared/lib/async/async-queue.js.map +1 -0
- package/dist/shared/lib/async/deferred.d.ts +12 -0
- package/dist/shared/lib/async/deferred.d.ts.map +1 -0
- package/dist/shared/lib/async/deferred.js +34 -0
- package/dist/shared/lib/async/deferred.js.map +1 -0
- package/dist/shared/lib/async/index.d.ts +8 -0
- package/dist/shared/lib/async/index.d.ts.map +1 -0
- package/dist/shared/lib/async/index.js +5 -0
- package/dist/shared/lib/async/index.js.map +1 -0
- package/dist/shared/lib/async/run-all.d.ts +8 -0
- package/dist/shared/lib/async/run-all.d.ts.map +1 -0
- package/dist/shared/lib/async/run-all.js +22 -0
- package/dist/shared/lib/async/run-all.js.map +1 -0
- package/dist/shared/lib/bytes/bytes.d.ts +18 -0
- package/dist/shared/lib/bytes/bytes.d.ts.map +1 -0
- package/dist/shared/lib/bytes/bytes.js +48 -0
- package/dist/shared/lib/bytes/bytes.js.map +1 -0
- package/dist/shared/lib/bytes/index.d.ts +3 -0
- package/dist/shared/lib/bytes/index.d.ts.map +1 -0
- package/dist/shared/lib/bytes/index.js +2 -0
- package/dist/shared/lib/bytes/index.js.map +1 -0
- package/dist/shared/lib/clock/clock.d.ts +29 -0
- package/dist/shared/lib/clock/clock.d.ts.map +1 -0
- package/dist/shared/lib/clock/clock.js +85 -0
- package/dist/shared/lib/clock/clock.js.map +1 -0
- package/dist/shared/lib/clock/index.d.ts +3 -0
- package/dist/shared/lib/clock/index.d.ts.map +1 -0
- package/dist/shared/lib/clock/index.js +2 -0
- package/dist/shared/lib/clock/index.js.map +1 -0
- package/dist/shared/lib/cookies/index.d.ts +3 -0
- package/dist/shared/lib/cookies/index.d.ts.map +1 -0
- package/dist/shared/lib/cookies/index.js +2 -0
- package/dist/shared/lib/cookies/index.js.map +1 -0
- package/dist/shared/lib/cookies/set-cookie.d.ts +22 -0
- package/dist/shared/lib/cookies/set-cookie.d.ts.map +1 -0
- package/dist/shared/lib/cookies/set-cookie.js +89 -0
- package/dist/shared/lib/cookies/set-cookie.js.map +1 -0
- package/dist/shared/lib/envelope/envelope.d.ts +50 -0
- package/dist/shared/lib/envelope/envelope.d.ts.map +1 -0
- package/dist/shared/lib/envelope/envelope.js +111 -0
- package/dist/shared/lib/envelope/envelope.js.map +1 -0
- package/dist/shared/lib/envelope/index.d.ts +3 -0
- package/dist/shared/lib/envelope/index.d.ts.map +1 -0
- package/dist/shared/lib/envelope/index.js +2 -0
- package/dist/shared/lib/envelope/index.js.map +1 -0
- package/dist/shared/lib/errors/index.d.ts +3 -0
- package/dist/shared/lib/errors/index.d.ts.map +1 -0
- package/dist/shared/lib/errors/index.js +2 -0
- package/dist/shared/lib/errors/index.js.map +1 -0
- package/dist/shared/lib/errors/wirestage-error.d.ts +28 -0
- package/dist/shared/lib/errors/wirestage-error.d.ts.map +1 -0
- package/dist/shared/lib/errors/wirestage-error.js +16 -0
- package/dist/shared/lib/errors/wirestage-error.js.map +1 -0
- package/dist/shared/lib/id/id.d.ts +10 -0
- package/dist/shared/lib/id/id.d.ts.map +1 -0
- package/dist/shared/lib/id/id.js +26 -0
- package/dist/shared/lib/id/id.js.map +1 -0
- package/dist/shared/lib/id/index.d.ts +2 -0
- package/dist/shared/lib/id/index.d.ts.map +1 -0
- package/dist/shared/lib/id/index.js +2 -0
- package/dist/shared/lib/id/index.js.map +1 -0
- package/dist/shared/lib/logger/index.d.ts +3 -0
- package/dist/shared/lib/logger/index.d.ts.map +1 -0
- package/dist/shared/lib/logger/index.js +2 -0
- package/dist/shared/lib/logger/index.js.map +1 -0
- package/dist/shared/lib/logger/logger.d.ts +46 -0
- package/dist/shared/lib/logger/logger.d.ts.map +1 -0
- package/dist/shared/lib/logger/logger.js +67 -0
- package/dist/shared/lib/logger/logger.js.map +1 -0
- package/dist/shared/lib/match/index.d.ts +3 -0
- package/dist/shared/lib/match/index.d.ts.map +1 -0
- package/dist/shared/lib/match/index.js +2 -0
- package/dist/shared/lib/match/index.js.map +1 -0
- package/dist/shared/lib/match/url-matcher.d.ts +27 -0
- package/dist/shared/lib/match/url-matcher.d.ts.map +1 -0
- package/dist/shared/lib/match/url-matcher.js +88 -0
- package/dist/shared/lib/match/url-matcher.js.map +1 -0
- package/dist/sse.d.ts +3 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +3 -0
- package/dist/sse.js.map +1 -0
- package/dist/webrtc.d.ts +3 -0
- package/dist/webrtc.d.ts.map +1 -0
- package/dist/webrtc.js +3 -0
- package/dist/webrtc.js.map +1 -0
- package/dist/websocket.d.ts +3 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +3 -0
- package/dist/websocket.js.map +1 -0
- package/dist/widgets/stage/index.d.ts +3 -0
- package/dist/widgets/stage/index.d.ts.map +1 -0
- package/dist/widgets/stage/index.js +2 -0
- package/dist/widgets/stage/index.js.map +1 -0
- package/dist/widgets/stage/lib/attached-context.d.ts +10 -0
- package/dist/widgets/stage/lib/attached-context.d.ts.map +1 -0
- package/dist/widgets/stage/lib/attached-context.js +2 -0
- package/dist/widgets/stage/lib/attached-context.js.map +1 -0
- package/dist/widgets/stage/lib/create-stage.d.ts +12 -0
- package/dist/widgets/stage/lib/create-stage.d.ts.map +1 -0
- package/dist/widgets/stage/lib/create-stage.js +248 -0
- package/dist/widgets/stage/lib/create-stage.js.map +1 -0
- package/dist/widgets/stage/lib/http-router.d.ts +35 -0
- package/dist/widgets/stage/lib/http-router.d.ts.map +1 -0
- package/dist/widgets/stage/lib/http-router.js +455 -0
- package/dist/widgets/stage/lib/http-router.js.map +1 -0
- package/dist/widgets/stage/lib/page-host.d.ts +36 -0
- package/dist/widgets/stage/lib/page-host.d.ts.map +1 -0
- package/dist/widgets/stage/lib/page-host.js +240 -0
- package/dist/widgets/stage/lib/page-host.js.map +1 -0
- package/dist/widgets/stage/lib/page-runtime.d.ts +93 -0
- package/dist/widgets/stage/lib/page-runtime.d.ts.map +1 -0
- package/dist/widgets/stage/lib/page-runtime.js +247 -0
- package/dist/widgets/stage/lib/page-runtime.js.map +1 -0
- package/dist/widgets/stage/lib/reads.d.ts +21 -0
- package/dist/widgets/stage/lib/reads.d.ts.map +1 -0
- package/dist/widgets/stage/lib/reads.js +97 -0
- package/dist/widgets/stage/lib/reads.js.map +1 -0
- package/dist/widgets/stage/lib/response-stream.d.ts +9 -0
- package/dist/widgets/stage/lib/response-stream.d.ts.map +1 -0
- package/dist/widgets/stage/lib/response-stream.js +56 -0
- package/dist/widgets/stage/lib/response-stream.js.map +1 -0
- package/dist/widgets/stage/lib/socket-router.d.ts +25 -0
- package/dist/widgets/stage/lib/socket-router.d.ts.map +1 -0
- package/dist/widgets/stage/lib/socket-router.js +204 -0
- package/dist/widgets/stage/lib/socket-router.js.map +1 -0
- package/dist/widgets/stage/model/stage.d.ts +86 -0
- package/dist/widgets/stage/model/stage.d.ts.map +1 -0
- package/dist/widgets/stage/model/stage.js +2 -0
- package/dist/widgets/stage/model/stage.js.map +1 -0
- package/package.json +140 -5
- package/src/app/playwright/index.ts +7 -0
- package/src/app/playwright/lib/fixture.ts +201 -0
- package/src/connect.ts +6 -0
- package/src/entities/frame/@x/plugin.ts +8 -0
- package/src/entities/frame/index.ts +19 -0
- package/src/entities/frame/lib/filter.ts +58 -0
- package/src/entities/frame/lib/payload.ts +42 -0
- package/src/entities/frame/lib/snapshot.ts +105 -0
- package/src/entities/frame/lib/timeline.ts +147 -0
- package/src/entities/frame/model/frame.ts +191 -0
- package/src/entities/plugin/index.ts +36 -0
- package/src/entities/plugin/lib/define-plugin.ts +12 -0
- package/src/entities/plugin/lib/named.ts +21 -0
- package/src/entities/plugin/model/attachment.ts +18 -0
- package/src/entities/plugin/model/http.ts +147 -0
- package/src/entities/plugin/model/page.ts +110 -0
- package/src/entities/plugin/model/plugin.ts +96 -0
- package/src/entities/plugin/model/socket.ts +108 -0
- package/src/entities/plugin/model/stream.ts +43 -0
- package/src/features/connect/index.ts +23 -0
- package/src/features/connect/lib/calls.ts +58 -0
- package/src/features/connect/lib/client.ts +203 -0
- package/src/features/connect/lib/create-connect.ts +164 -0
- package/src/features/connect/lib/faults.ts +132 -0
- package/src/features/connect/lib/protocol.ts +321 -0
- package/src/features/connect/lib/record.ts +48 -0
- package/src/features/connect/lib/recorder.ts +306 -0
- package/src/features/connect/lib/rules.ts +385 -0
- package/src/features/connect/lib/serve.ts +114 -0
- package/src/features/connect/lib/status-of.ts +20 -0
- package/src/features/connect/lib/stubs.ts +282 -0
- package/src/features/connect/lib/universal.ts +100 -0
- package/src/features/connect/model/types.ts +305 -0
- package/src/features/rest/index.ts +23 -0
- package/src/features/rest/lib/calls.ts +31 -0
- package/src/features/rest/lib/create-rest.ts +169 -0
- package/src/features/rest/lib/path.ts +70 -0
- package/src/features/rest/lib/reply.ts +74 -0
- package/src/features/rest/model/types.ts +113 -0
- package/src/features/sse/index.ts +10 -0
- package/src/features/sse/lib/create-sse.ts +128 -0
- package/src/features/sse/lib/encode.ts +28 -0
- package/src/features/sse/model/types.ts +66 -0
- package/src/features/webrtc/index.ts +6 -0
- package/src/features/webrtc/lib/create-webrtc.ts +149 -0
- package/src/features/webrtc/lib/rtc-page-module.ts +189 -0
- package/src/features/webrtc/lib/to-frame.ts +63 -0
- package/src/features/webrtc/model/types.ts +80 -0
- package/src/features/websocket/index.ts +15 -0
- package/src/features/websocket/lib/create-websocket.ts +41 -0
- package/src/features/websocket/lib/mock.ts +114 -0
- package/src/features/websocket/lib/proxy.ts +141 -0
- package/src/features/websocket/lib/wire.ts +78 -0
- package/src/features/websocket/model/types.ts +130 -0
- package/src/index.ts +111 -0
- package/src/playwright.ts +8 -0
- package/src/rest.ts +2 -0
- package/src/shared/api/http-server/index.ts +2 -0
- package/src/shared/api/http-server/listen.ts +71 -0
- package/src/shared/api/playwright/index.ts +17 -0
- package/src/shared/api/playwright/ports.ts +145 -0
- package/src/shared/api/stream-server/index.ts +7 -0
- package/src/shared/api/stream-server/stream-server.ts +246 -0
- package/src/shared/lib/async/arrivals.ts +91 -0
- package/src/shared/lib/async/async-queue.ts +101 -0
- package/src/shared/lib/async/deferred.ts +38 -0
- package/src/shared/lib/async/index.ts +11 -0
- package/src/shared/lib/async/run-all.ts +19 -0
- package/src/shared/lib/bytes/bytes.ts +53 -0
- package/src/shared/lib/bytes/index.ts +9 -0
- package/src/shared/lib/clock/clock.ts +114 -0
- package/src/shared/lib/clock/index.ts +2 -0
- package/src/shared/lib/cookies/index.ts +2 -0
- package/src/shared/lib/cookies/set-cookie.ts +105 -0
- package/src/shared/lib/envelope/envelope.ts +133 -0
- package/src/shared/lib/envelope/index.ts +9 -0
- package/src/shared/lib/errors/index.ts +5 -0
- package/src/shared/lib/errors/wirestage-error.ts +50 -0
- package/src/shared/lib/id/id.ts +29 -0
- package/src/shared/lib/id/index.ts +1 -0
- package/src/shared/lib/logger/index.ts +12 -0
- package/src/shared/lib/logger/logger.ts +126 -0
- package/src/shared/lib/match/index.ts +6 -0
- package/src/shared/lib/match/url-matcher.ts +107 -0
- package/src/sse.ts +2 -0
- package/src/webrtc.ts +2 -0
- package/src/websocket.ts +2 -0
- package/src/widgets/stage/index.ts +9 -0
- package/src/widgets/stage/lib/attached-context.ts +10 -0
- package/src/widgets/stage/lib/create-stage.ts +305 -0
- package/src/widgets/stage/lib/http-router.ts +620 -0
- package/src/widgets/stage/lib/page-host.ts +375 -0
- package/src/widgets/stage/lib/page-runtime.ts +314 -0
- package/src/widgets/stage/lib/reads.ts +128 -0
- package/src/widgets/stage/lib/response-stream.ts +66 -0
- package/src/widgets/stage/lib/socket-router.ts +271 -0
- package/src/widgets/stage/model/stage.ts +108 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DescMessage,
|
|
3
|
+
DescMethod,
|
|
4
|
+
DescMethodServerStreaming,
|
|
5
|
+
DescMethodUnary,
|
|
6
|
+
DescService,
|
|
7
|
+
JsonReadOptions,
|
|
8
|
+
JsonWriteOptions,
|
|
9
|
+
MessageInitShape,
|
|
10
|
+
MessageShape,
|
|
11
|
+
} from "@bufbuild/protobuf";
|
|
12
|
+
import type {
|
|
13
|
+
Client,
|
|
14
|
+
Code,
|
|
15
|
+
ConnectRouter,
|
|
16
|
+
HandlerContext,
|
|
17
|
+
ServiceImpl,
|
|
18
|
+
} from "@connectrpc/connect";
|
|
19
|
+
|
|
20
|
+
import type { Frame, FrameSource } from "../../../entities/frame/index.js";
|
|
21
|
+
import type {
|
|
22
|
+
AbortErrorCode,
|
|
23
|
+
HttpRequestView,
|
|
24
|
+
StreamEnd as ResponseEnd,
|
|
25
|
+
} from "../../../entities/plugin/index.js";
|
|
26
|
+
import type { CookieJarPort } from "../../../shared/api/playwright/index.js";
|
|
27
|
+
|
|
28
|
+
/** The three wire protocols connect-es speaks. Browsers use the first two. */
|
|
29
|
+
export type RpcProtocol = "connect" | "grpc-web" | "grpc";
|
|
30
|
+
|
|
31
|
+
export interface ConnectOptions {
|
|
32
|
+
/**
|
|
33
|
+
* What the app's transport puts in front of `/<package>.<Service>/<Method>`:
|
|
34
|
+
* a path prefix (`/api`) on any origin, or an origin with one
|
|
35
|
+
* (`https://api.example.test/rpc`). Without it a stub matches that suffix
|
|
36
|
+
* under any prefix. It is also where `client()` calls by default.
|
|
37
|
+
*/
|
|
38
|
+
readonly baseURL?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Protocols stubs answer. Default: connect and grpc-web — the two a browser
|
|
41
|
+
* can speak. A call in another protocol passes every stub by. Native gRPC
|
|
42
|
+
* is for `serve()`.
|
|
43
|
+
*/
|
|
44
|
+
readonly protocols?: readonly RpcProtocol[];
|
|
45
|
+
/**
|
|
46
|
+
* Services whose traffic is recorded and decoded even when nothing stubs
|
|
47
|
+
* it, so `calls()` sees the real backend's answers too.
|
|
48
|
+
*/
|
|
49
|
+
readonly record?: readonly DescService[];
|
|
50
|
+
/**
|
|
51
|
+
* `live` (default) answers server streams from a local server, message by
|
|
52
|
+
* message, as the stub produces them. `buffered` collects the whole stream
|
|
53
|
+
* and fulfills it at once — the only choice on an https page without
|
|
54
|
+
* `streamServer.tls`, and only useful for streams that end.
|
|
55
|
+
*/
|
|
56
|
+
readonly streaming?: "live" | "buffered";
|
|
57
|
+
/** The protocol `client()` uses by default. Default `connect`. */
|
|
58
|
+
readonly clientProtocol?: RpcProtocol;
|
|
59
|
+
readonly jsonOptions?: Partial<JsonReadOptions & JsonWriteOptions>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface HoldOptions<I extends DescMessage = DescMessage> {
|
|
63
|
+
/** Take this many calls, then leave the rest to the next rule. */
|
|
64
|
+
readonly times?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Take only the calls this accepts; the rest go on to the next rule, or to
|
|
67
|
+
* the real backend. Gets the decoded request message, and the raw request
|
|
68
|
+
* for its headers. A request that does not decode never matches.
|
|
69
|
+
*/
|
|
70
|
+
readonly match?: (request: MessageShape<I>, view: HttpRequestView) => boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface StubOptions<I extends DescMessage = DescMessage>
|
|
74
|
+
extends HoldOptions<I> {
|
|
75
|
+
/** Wait this long before answering. */
|
|
76
|
+
readonly delayMs?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface StubHandle {
|
|
80
|
+
/** Calls this stub took. */
|
|
81
|
+
readonly hits: number;
|
|
82
|
+
remove(): Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type UnaryReply<I extends DescMessage, O extends DescMessage> =
|
|
86
|
+
| MessageInitShape<O>
|
|
87
|
+
| ((
|
|
88
|
+
request: MessageShape<I>,
|
|
89
|
+
context: HandlerContext,
|
|
90
|
+
) => MessageInitShape<O> | Promise<MessageInitShape<O>>);
|
|
91
|
+
|
|
92
|
+
export interface UnaryStub<I extends DescMessage> extends StubHandle {
|
|
93
|
+
/** Requests received so far, decoded. */
|
|
94
|
+
readonly requests: readonly MessageShape<I>[];
|
|
95
|
+
/** The next request this stub receives (or already received and nobody took). */
|
|
96
|
+
next(options?: { readonly timeout?: number }): Promise<MessageShape<I>>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* How a test-driven stream ended: cleanly, with an error status (`failed`),
|
|
101
|
+
* reset by the test (`cut`), or let go of by the page (`cancelled`).
|
|
102
|
+
*/
|
|
103
|
+
export type StreamEnd = ResponseEnd | "failed";
|
|
104
|
+
|
|
105
|
+
export interface StreamCall<I extends DescMessage, O extends DescMessage> {
|
|
106
|
+
readonly request: MessageShape<I>;
|
|
107
|
+
readonly requestHeaders: Headers;
|
|
108
|
+
/** The protocol the page called with; undefined for an unidentified call. */
|
|
109
|
+
readonly protocol: RpcProtocol | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Send a message. Messages go out in order; this resolves once the
|
|
112
|
+
* message is written, and rejects with `CLOSED` when the stream ended
|
|
113
|
+
* before it was.
|
|
114
|
+
*/
|
|
115
|
+
send(message: MessageInitShape<O>): Promise<void>;
|
|
116
|
+
/** End with OK. Resolves once the stream is over. */
|
|
117
|
+
end(): Promise<void>;
|
|
118
|
+
/** End with an error status. Resolves once the stream is over. */
|
|
119
|
+
fail(code: Code, message?: string): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Reset the connection mid-stream: no status, no trailer — what a network
|
|
122
|
+
* drop looks like to the client. Recorded as a `cut` fault, not a status.
|
|
123
|
+
*/
|
|
124
|
+
cut(): Promise<void>;
|
|
125
|
+
readonly closed: Promise<StreamEnd>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface StreamStub<I extends DescMessage, O extends DescMessage>
|
|
129
|
+
extends StubHandle {
|
|
130
|
+
/** The next call the page opens (or already opened and nobody took). */
|
|
131
|
+
next(options?: { readonly timeout?: number }): Promise<StreamCall<I, O>>;
|
|
132
|
+
readonly calls: readonly StreamCall<I, O>[];
|
|
133
|
+
/** Send to every open call. */
|
|
134
|
+
broadcast(message: MessageInitShape<O>): Promise<void>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* A call held at the network boundary until the test decides. Each decision
|
|
139
|
+
* resolves once it is carried out, so `calls()` right after one sees it; the
|
|
140
|
+
* first decision stands and later ones do nothing.
|
|
141
|
+
*/
|
|
142
|
+
export interface HeldCall<I extends DescMessage, O extends DescMessage> {
|
|
143
|
+
readonly request: MessageShape<I> | undefined;
|
|
144
|
+
readonly view: HttpRequestView;
|
|
145
|
+
/**
|
|
146
|
+
* Let it go on: to the next rule that matches it, and to the real backend
|
|
147
|
+
* when there is none.
|
|
148
|
+
*/
|
|
149
|
+
release(): Promise<void>;
|
|
150
|
+
/** Answer it with this message. */
|
|
151
|
+
reply(message: MessageInitShape<O>): Promise<void>;
|
|
152
|
+
/** Answer it with an error status. */
|
|
153
|
+
fail(code: Code, message?: string): Promise<void>;
|
|
154
|
+
/** Fail it at the network level. */
|
|
155
|
+
abort(error?: AbortErrorCode): Promise<void>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface HoldStub<I extends DescMessage, O extends DescMessage>
|
|
159
|
+
extends StubHandle {
|
|
160
|
+
next(options?: { readonly timeout?: number }): Promise<HeldCall<I, O>>;
|
|
161
|
+
readonly calls: readonly HeldCall<I, O>[];
|
|
162
|
+
/**
|
|
163
|
+
* Stop holding: every call held so far goes on, and so does every later
|
|
164
|
+
* one. A call already decided stays decided.
|
|
165
|
+
*/
|
|
166
|
+
releaseAll(): Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** One recorded RPC, reassembled from its frames. */
|
|
170
|
+
export interface RpcCall<I extends DescMessage, O extends DescMessage> {
|
|
171
|
+
readonly correlation: string;
|
|
172
|
+
/**
|
|
173
|
+
* Who made the call: `page`, `test` for a drive client, `network` for a
|
|
174
|
+
* client outside the browser calling a served fake. Undefined when the
|
|
175
|
+
* request never read as an RPC.
|
|
176
|
+
*/
|
|
177
|
+
readonly caller: FrameSource | undefined;
|
|
178
|
+
/**
|
|
179
|
+
* Who answered: `stub`, `network` for the real backend, `server` for a
|
|
180
|
+
* served fake. Undefined while nobody has.
|
|
181
|
+
*/
|
|
182
|
+
readonly answeredBy: FrameSource | undefined;
|
|
183
|
+
/** The page that made the call (`p1`, ...); undefined for a drive client's. */
|
|
184
|
+
readonly page: string | undefined;
|
|
185
|
+
/** Its browser context (`c1`, ...); undefined for a drive client's. */
|
|
186
|
+
readonly context: string | undefined;
|
|
187
|
+
readonly protocol: RpcProtocol | undefined;
|
|
188
|
+
/** The first request message. */
|
|
189
|
+
readonly request: MessageShape<I> | undefined;
|
|
190
|
+
readonly requests: readonly MessageShape<I>[];
|
|
191
|
+
readonly responses: readonly MessageShape<O>[];
|
|
192
|
+
/** Undefined while the call is open, and when it ended in a fault. Code 0 is OK. */
|
|
193
|
+
readonly status:
|
|
194
|
+
| { readonly code: number; readonly message: string }
|
|
195
|
+
| undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Why the call ended without a status: `abort` (a stub failed it), `cut`
|
|
198
|
+
* (the test reset the stream), `cancelled` (the page let go), `network`
|
|
199
|
+
* (the connection to the real backend failed).
|
|
200
|
+
*/
|
|
201
|
+
readonly fault: string | undefined;
|
|
202
|
+
readonly frames: readonly Frame[];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface ClientOptions {
|
|
206
|
+
/** Absolute, or a path resolved against the stage's base URL. */
|
|
207
|
+
readonly baseURL?: string;
|
|
208
|
+
readonly protocol?: RpcProtocol;
|
|
209
|
+
/** Protobuf binary (default) or JSON on the wire. */
|
|
210
|
+
readonly binary?: boolean;
|
|
211
|
+
/** Sent with every call that does not set the header itself. */
|
|
212
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
213
|
+
/**
|
|
214
|
+
* Share a browser context's cookie jar: its cookies go out on the call, so
|
|
215
|
+
* the call is made as the signed-in page, and the cookies a response sets
|
|
216
|
+
* — an error response included — are kept in it. Pass the context.
|
|
217
|
+
* Defaults to the first attached context; `null` uses none.
|
|
218
|
+
*/
|
|
219
|
+
readonly session?: CookieJarPort | null;
|
|
220
|
+
/** Accept self-signed certificates (dev servers). */
|
|
221
|
+
readonly ignoreHttpsErrors?: boolean;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface StandaloneClientOptions
|
|
225
|
+
extends Omit<ClientOptions, "baseURL" | "session"> {
|
|
226
|
+
readonly baseURL: string;
|
|
227
|
+
readonly session?: CookieJarPort;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface ServeOptions {
|
|
231
|
+
/** 0, the default, picks a free port. A fixed port fails loudly when taken. */
|
|
232
|
+
readonly port?: number;
|
|
233
|
+
readonly host?: string;
|
|
234
|
+
/** Protocols served. Default all three. */
|
|
235
|
+
readonly protocols?: readonly RpcProtocol[];
|
|
236
|
+
/**
|
|
237
|
+
* HTTP/2 (h2c). Required by native gRPC clients; an HTTP/1.1-only client
|
|
238
|
+
* (grpc-web, Connect over 1.1) needs it off. Default: on when `protocols`
|
|
239
|
+
* includes grpc.
|
|
240
|
+
*/
|
|
241
|
+
readonly http2?: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface RpcServer {
|
|
245
|
+
readonly url: string;
|
|
246
|
+
readonly port: number;
|
|
247
|
+
close(): Promise<void>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface ConnectApi {
|
|
251
|
+
/**
|
|
252
|
+
* Stub a whole service, or the methods of it that `impl` defines. A
|
|
253
|
+
* method a browser cannot call (client or bidirectional streaming) is
|
|
254
|
+
* refused: `serve()` is where those are faked.
|
|
255
|
+
*/
|
|
256
|
+
service<S extends DescService>(
|
|
257
|
+
service: S,
|
|
258
|
+
impl: Partial<ServiceImpl<S>>,
|
|
259
|
+
options?: StubOptions,
|
|
260
|
+
): Promise<StubHandle>;
|
|
261
|
+
/** Stub one unary method with a message or a function of the request. */
|
|
262
|
+
unary<I extends DescMessage, O extends DescMessage>(
|
|
263
|
+
method: DescMethodUnary<I, O>,
|
|
264
|
+
reply: UnaryReply<I, O>,
|
|
265
|
+
options?: StubOptions<I>,
|
|
266
|
+
): Promise<UnaryStub<I>>;
|
|
267
|
+
/** Stub one server-streaming method and drive it from the test. */
|
|
268
|
+
stream<I extends DescMessage, O extends DescMessage>(
|
|
269
|
+
method: DescMethodServerStreaming<I, O>,
|
|
270
|
+
options?: StubOptions<I>,
|
|
271
|
+
): Promise<StreamStub<I, O>>;
|
|
272
|
+
/** Answer every call to `method` with an error status. */
|
|
273
|
+
fail<I extends DescMessage>(
|
|
274
|
+
method: DescMethod & { readonly input: I },
|
|
275
|
+
code: Code,
|
|
276
|
+
message?: string,
|
|
277
|
+
options?: StubOptions<I>,
|
|
278
|
+
): Promise<StubHandle>;
|
|
279
|
+
/** Fail every call to `method` at the network level. */
|
|
280
|
+
abort<I extends DescMessage>(
|
|
281
|
+
method: DescMethod & { readonly input: I },
|
|
282
|
+
options?: StubOptions<I> & { readonly error?: AbortErrorCode },
|
|
283
|
+
): Promise<StubHandle>;
|
|
284
|
+
/** Hold calls until the test releases, answers or aborts each one. */
|
|
285
|
+
hold<I extends DescMessage, O extends DescMessage>(
|
|
286
|
+
method: DescMethodUnary<I, O> | DescMethodServerStreaming<I, O>,
|
|
287
|
+
options?: HoldOptions<I>,
|
|
288
|
+
): Promise<HoldStub<I, O>>;
|
|
289
|
+
/** Record and decode calls to this service without answering them. */
|
|
290
|
+
record(service: DescService): Promise<StubHandle>;
|
|
291
|
+
/** Every recorded call to `method`, oldest first. */
|
|
292
|
+
calls<I extends DescMessage, O extends DescMessage>(
|
|
293
|
+
method: DescMethod & { readonly input: I; readonly output: O },
|
|
294
|
+
): Promise<RpcCall<I, O>[]>;
|
|
295
|
+
/** A typed client for the real backend, signed in as the page. */
|
|
296
|
+
client<S extends DescService>(service: S, options?: ClientOptions): Client<S>;
|
|
297
|
+
/**
|
|
298
|
+
* Serve stubs on a port of their own, for clients outside the browser — a
|
|
299
|
+
* native gRPC client, a backend service under test. Calls are recorded.
|
|
300
|
+
*/
|
|
301
|
+
serve(
|
|
302
|
+
routes: (router: ConnectRouter) => void,
|
|
303
|
+
options?: ServeOptions,
|
|
304
|
+
): Promise<RpcServer>;
|
|
305
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { rest } from "./lib/create-rest.js";
|
|
2
|
+
export type { ReplyInit } from "./lib/reply.js";
|
|
3
|
+
export {
|
|
4
|
+
abort,
|
|
5
|
+
bytes,
|
|
6
|
+
delay,
|
|
7
|
+
empty,
|
|
8
|
+
json,
|
|
9
|
+
passthrough,
|
|
10
|
+
text,
|
|
11
|
+
} from "./lib/reply.js";
|
|
12
|
+
export type {
|
|
13
|
+
RestApi,
|
|
14
|
+
RestCall,
|
|
15
|
+
RestMethod,
|
|
16
|
+
RestOptions,
|
|
17
|
+
RestPath,
|
|
18
|
+
RestReply,
|
|
19
|
+
RestRequest,
|
|
20
|
+
RestResolver,
|
|
21
|
+
RestRoute,
|
|
22
|
+
RestRouteOptions,
|
|
23
|
+
} from "./model/types.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Frame } from "../../../entities/frame/index.js";
|
|
2
|
+
import type { RestCall } from "../model/types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pair each recorded request with how it ended. One call per exchange,
|
|
6
|
+
* oldest first; a frame with no correlation is an exchange of its own.
|
|
7
|
+
*/
|
|
8
|
+
export function assembleCalls(frames: readonly Frame[]): RestCall[] {
|
|
9
|
+
const byCall = new Map<string, { request?: Frame; end?: Frame }>();
|
|
10
|
+
for (const frame of frames) {
|
|
11
|
+
const key = frame.correlation ?? `#${frame.seq}`;
|
|
12
|
+
const entry = byCall.get(key) ?? {};
|
|
13
|
+
if (frame.kind === "request") entry.request = frame;
|
|
14
|
+
else entry.end = frame;
|
|
15
|
+
byCall.set(key, entry);
|
|
16
|
+
}
|
|
17
|
+
const calls: RestCall[] = [];
|
|
18
|
+
for (const [correlation, { request, end }] of byCall) {
|
|
19
|
+
if (request === undefined) continue;
|
|
20
|
+
const status = end?.meta["status"];
|
|
21
|
+
calls.push({
|
|
22
|
+
correlation,
|
|
23
|
+
method: String(request.meta["method"]),
|
|
24
|
+
url: String(request.meta["url"]),
|
|
25
|
+
request,
|
|
26
|
+
response: end?.kind === "response" ? end : undefined,
|
|
27
|
+
status: typeof status === "number" ? status : undefined,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return calls;
|
|
31
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {
|
|
2
|
+
definePlugin,
|
|
3
|
+
type HttpOutcome,
|
|
4
|
+
type HttpRequestView,
|
|
5
|
+
type WirePlugin,
|
|
6
|
+
} from "../../../entities/plugin/index.js";
|
|
7
|
+
import { createArrivals } from "../../../shared/lib/async/index.js";
|
|
8
|
+
import type {
|
|
9
|
+
RestApi,
|
|
10
|
+
RestMethod,
|
|
11
|
+
RestOptions,
|
|
12
|
+
RestReply,
|
|
13
|
+
RestRequest,
|
|
14
|
+
} from "../model/types.js";
|
|
15
|
+
import { assembleCalls } from "./calls.js";
|
|
16
|
+
import { compilePath } from "./path.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* REST and other plain HTTP: routes by method and path with `:params`, replies
|
|
20
|
+
* built from small helpers, faults, and recording of the real responses.
|
|
21
|
+
*/
|
|
22
|
+
export function rest(options: RestOptions = {}): WirePlugin<"rest", RestApi> {
|
|
23
|
+
return definePlugin({
|
|
24
|
+
name: "rest",
|
|
25
|
+
scope: "Rest",
|
|
26
|
+
setup(context) {
|
|
27
|
+
const { name } = context;
|
|
28
|
+
/** The record rule being added, once: every context gets it. */
|
|
29
|
+
let recording: Promise<unknown> | undefined;
|
|
30
|
+
|
|
31
|
+
const toOutcome = async (reply: RestReply): Promise<HttpOutcome> => {
|
|
32
|
+
switch (reply.kind) {
|
|
33
|
+
case "response":
|
|
34
|
+
return {
|
|
35
|
+
type: "fulfill",
|
|
36
|
+
status: reply.status,
|
|
37
|
+
headers: reply.headers,
|
|
38
|
+
...(reply.body === undefined ? {} : { body: reply.body }),
|
|
39
|
+
};
|
|
40
|
+
case "passthrough":
|
|
41
|
+
return { type: "fallback" };
|
|
42
|
+
case "abort":
|
|
43
|
+
return { type: "abort", error: reply.error };
|
|
44
|
+
case "delay":
|
|
45
|
+
await context.clock.sleep(reply.ms);
|
|
46
|
+
return toOutcome(reply.reply);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const on: RestApi["on"] = async (
|
|
51
|
+
method,
|
|
52
|
+
path,
|
|
53
|
+
resolver,
|
|
54
|
+
routeOptions = {},
|
|
55
|
+
) => {
|
|
56
|
+
const matcher = compilePath(path, options.baseURL);
|
|
57
|
+
// Own, enumerable fields: a request spreads and prints whole.
|
|
58
|
+
const toRequest = (view: HttpRequestView): RestRequest => ({
|
|
59
|
+
get correlation() {
|
|
60
|
+
return view.correlation;
|
|
61
|
+
},
|
|
62
|
+
method: view.method,
|
|
63
|
+
url: view.url,
|
|
64
|
+
headers: view.headers,
|
|
65
|
+
page: view.page,
|
|
66
|
+
context: view.context,
|
|
67
|
+
resourceType: view.resourceType,
|
|
68
|
+
body: view.body,
|
|
69
|
+
text: view.text,
|
|
70
|
+
json: view.json,
|
|
71
|
+
// The rule's URL predicate is this matcher, so it matched.
|
|
72
|
+
params: matcher.match(view.url) as Record<string, string>,
|
|
73
|
+
query: view.url.searchParams,
|
|
74
|
+
});
|
|
75
|
+
const label = `${method} ${String(path)}`;
|
|
76
|
+
const requests = createArrivals<RestRequest>({
|
|
77
|
+
clock: context.clock,
|
|
78
|
+
label: `${label} request`,
|
|
79
|
+
});
|
|
80
|
+
const { match } = routeOptions;
|
|
81
|
+
const rule = await context.http.add({
|
|
82
|
+
protocol: name,
|
|
83
|
+
label,
|
|
84
|
+
url: (url) => matcher.match(url) !== undefined,
|
|
85
|
+
...(method === "*" ? {} : { method }),
|
|
86
|
+
...(routeOptions.times === undefined
|
|
87
|
+
? {}
|
|
88
|
+
: { times: routeOptions.times }),
|
|
89
|
+
...(match === undefined
|
|
90
|
+
? {}
|
|
91
|
+
: { match: (view) => match(toRequest(view)) }),
|
|
92
|
+
handle: async (view) => {
|
|
93
|
+
const request = toRequest(view);
|
|
94
|
+
requests.push(request);
|
|
95
|
+
return toOutcome(
|
|
96
|
+
typeof resolver === "function"
|
|
97
|
+
? await resolver(request)
|
|
98
|
+
: resolver,
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
get hits() {
|
|
104
|
+
return rule.hits;
|
|
105
|
+
},
|
|
106
|
+
get requests() {
|
|
107
|
+
return requests.items;
|
|
108
|
+
},
|
|
109
|
+
next: (waitOptions) => requests.next(waitOptions),
|
|
110
|
+
remove: () => rule.remove(),
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const verb =
|
|
115
|
+
(method: RestMethod): RestApi["get"] =>
|
|
116
|
+
(path, resolver, routeOptions) =>
|
|
117
|
+
on(method, path, resolver, routeOptions);
|
|
118
|
+
|
|
119
|
+
const api: RestApi = {
|
|
120
|
+
on,
|
|
121
|
+
get: verb("GET"),
|
|
122
|
+
post: verb("POST"),
|
|
123
|
+
put: verb("PUT"),
|
|
124
|
+
patch: verb("PATCH"),
|
|
125
|
+
delete: verb("DELETE"),
|
|
126
|
+
async calls(filter = {}) {
|
|
127
|
+
await context.sync();
|
|
128
|
+
const matcher =
|
|
129
|
+
filter.path === undefined
|
|
130
|
+
? undefined
|
|
131
|
+
: compilePath(filter.path, options.baseURL);
|
|
132
|
+
const wanted = filter.method?.toUpperCase();
|
|
133
|
+
return assembleCalls(
|
|
134
|
+
context.timeline.frames({ protocol: name }),
|
|
135
|
+
).filter(
|
|
136
|
+
(call) =>
|
|
137
|
+
(wanted === undefined || wanted === call.method) &&
|
|
138
|
+
(matcher === undefined ||
|
|
139
|
+
matcher.match(new URL(call.url)) !== undefined),
|
|
140
|
+
);
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
api,
|
|
146
|
+
async attach() {
|
|
147
|
+
if (options.record === undefined || options.record === false) return;
|
|
148
|
+
const base = compilePath(`${options.baseURL ?? ""}/**`, undefined);
|
|
149
|
+
recording ??= context.http
|
|
150
|
+
.add({
|
|
151
|
+
protocol: name,
|
|
152
|
+
label: "record",
|
|
153
|
+
url:
|
|
154
|
+
options.record === true
|
|
155
|
+
? (url) => base.match(url) !== undefined
|
|
156
|
+
: options.record,
|
|
157
|
+
handle: () => ({ type: "fallback" }),
|
|
158
|
+
})
|
|
159
|
+
.catch((error: unknown) => {
|
|
160
|
+
// The router took the rule back: the next attach adds it again.
|
|
161
|
+
recording = undefined;
|
|
162
|
+
throw error;
|
|
163
|
+
});
|
|
164
|
+
await recording;
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { WirestageError } from "../../../shared/lib/errors/index.js";
|
|
2
|
+
import { globSource } from "../../../shared/lib/match/index.js";
|
|
3
|
+
import type { RestPath } from "../model/types.js";
|
|
4
|
+
|
|
5
|
+
export interface PathMatcher {
|
|
6
|
+
/** The `:name` params when `url` matches, undefined when it does not. */
|
|
7
|
+
match(url: URL): Record<string, string> | undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `/rooms/:id/files/*` against a URL's path, or — for a pattern that starts
|
|
12
|
+
* with a scheme — against origin plus path. The glob is the one every other
|
|
13
|
+
* pattern of the library takes (`*` one segment, `**` any number, none
|
|
14
|
+
* included, `{a,b}` either), plus `:name` params. The query never takes
|
|
15
|
+
* part: a route for `/search` should answer `/search?q=x`.
|
|
16
|
+
*/
|
|
17
|
+
export function compilePath(
|
|
18
|
+
path: RestPath,
|
|
19
|
+
baseURL: string | undefined,
|
|
20
|
+
): PathMatcher {
|
|
21
|
+
if (path instanceof RegExp)
|
|
22
|
+
return {
|
|
23
|
+
match(url) {
|
|
24
|
+
path.lastIndex = 0;
|
|
25
|
+
const found = path.exec(url.pathname);
|
|
26
|
+
return found === null ? undefined : { ...found.groups };
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
if (path.includes("?"))
|
|
30
|
+
// It would compile, and then never match anything.
|
|
31
|
+
throw new WirestageError(
|
|
32
|
+
"INVALID_ARGUMENT",
|
|
33
|
+
`route "${path}" names a query, and a route matches the path alone: drop the "?…" and check \`request.query\` in the resolver or in \`match\``,
|
|
34
|
+
);
|
|
35
|
+
const full = joinBase(baseURL, path);
|
|
36
|
+
const absolute = /^[a-z][a-z\d+.-]*:\/\//i.test(full);
|
|
37
|
+
const { source, params: keys } = globSource(full, { params: true });
|
|
38
|
+
const pattern = new RegExp(`^${source}/?$`);
|
|
39
|
+
return {
|
|
40
|
+
match(url) {
|
|
41
|
+
const subject = absolute ? `${url.origin}${url.pathname}` : url.pathname;
|
|
42
|
+
const found = pattern.exec(subject);
|
|
43
|
+
if (found === null) return undefined;
|
|
44
|
+
const params: Record<string, string> = {};
|
|
45
|
+
keys.forEach((key, index) => {
|
|
46
|
+
params[key] = decode(found[index + 1] as string);
|
|
47
|
+
});
|
|
48
|
+
return params;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A path segment, percent-decoded. A malformed escape is kept as it came:
|
|
55
|
+
* this runs for every request of the context, and must not throw for one
|
|
56
|
+
* odd URL.
|
|
57
|
+
*/
|
|
58
|
+
function decode(segment: string): string {
|
|
59
|
+
try {
|
|
60
|
+
return decodeURIComponent(segment);
|
|
61
|
+
} catch {
|
|
62
|
+
return segment;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function joinBase(baseURL: string | undefined, path: string): string {
|
|
67
|
+
if (baseURL === undefined || /^[a-z][a-z\d+.-]*:\/\//i.test(path))
|
|
68
|
+
return path;
|
|
69
|
+
return `${baseURL.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { AbortErrorCode } from "../../../entities/plugin/index.js";
|
|
2
|
+
import type { RestReply } from "../model/types.js";
|
|
3
|
+
|
|
4
|
+
export interface ReplyInit {
|
|
5
|
+
readonly status?: number;
|
|
6
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const response = (
|
|
10
|
+
body: Uint8Array | string | undefined,
|
|
11
|
+
contentType: string | undefined,
|
|
12
|
+
init: ReplyInit,
|
|
13
|
+
defaultStatus: number,
|
|
14
|
+
): RestReply => ({
|
|
15
|
+
kind: "response",
|
|
16
|
+
status: init.status ?? defaultStatus,
|
|
17
|
+
headers: {
|
|
18
|
+
...(contentType === undefined ? {} : { "content-type": contentType }),
|
|
19
|
+
...init.headers,
|
|
20
|
+
},
|
|
21
|
+
...(body === undefined ? {} : { body }),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/** A JSON body. A bigint field (protobuf int64) is written as a string. */
|
|
25
|
+
export function json(value: unknown, init: ReplyInit = {}): RestReply {
|
|
26
|
+
return response(
|
|
27
|
+
JSON.stringify(value, (_key, v: unknown) =>
|
|
28
|
+
typeof v === "bigint" ? v.toString() : v,
|
|
29
|
+
),
|
|
30
|
+
"application/json",
|
|
31
|
+
init,
|
|
32
|
+
200,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function text(value: string, init: ReplyInit = {}): RestReply {
|
|
37
|
+
return response(value, "text/plain; charset=utf-8", init, 200);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function bytes(
|
|
41
|
+
value: Uint8Array,
|
|
42
|
+
init: ReplyInit & { readonly contentType?: string } = {},
|
|
43
|
+
): RestReply {
|
|
44
|
+
return response(
|
|
45
|
+
value,
|
|
46
|
+
init.contentType ?? "application/octet-stream",
|
|
47
|
+
init,
|
|
48
|
+
200,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** No body. 204 unless `status` says otherwise. */
|
|
53
|
+
export function empty(init: ReplyInit = {}): RestReply {
|
|
54
|
+
return response(undefined, undefined, init, 204);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Decline to answer: the request goes on to the next route that matches it,
|
|
59
|
+
* and to the real server when there is none. A route that only watches —
|
|
60
|
+
* `route.next()`, `route.requests` — answers with this.
|
|
61
|
+
*/
|
|
62
|
+
export function passthrough(): RestReply {
|
|
63
|
+
return { kind: "passthrough" };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Fail the request at the network level, as a dropped connection would. */
|
|
67
|
+
export function abort(error: AbortErrorCode = "failed"): RestReply {
|
|
68
|
+
return { kind: "abort", error };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Answer `reply`, `ms` later. (Not named `then`, so a reply never looks like a thenable.) */
|
|
72
|
+
export function delay(ms: number, reply: RestReply): RestReply {
|
|
73
|
+
return { kind: "delay", ms, reply };
|
|
74
|
+
}
|