@planet-matrix/mobius-model 0.6.0 → 0.10.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/CHANGELOG.md +50 -0
- package/oxlint.config.ts +1 -2
- package/package.json +29 -17
- package/scripts/build.ts +2 -52
- package/src/ai/README.md +1 -0
- package/src/ai/ai.ts +107 -0
- package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
- package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
- package/src/ai/chat-completion-ai/index.ts +7 -0
- package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
- package/src/ai/embedding-ai/embedding-ai.ts +63 -0
- package/src/ai/embedding-ai/embedding.ts +50 -0
- package/src/ai/embedding-ai/index.ts +4 -0
- package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
- package/src/ai/index.ts +4 -0
- package/src/aio/README.md +100 -0
- package/src/aio/content.ts +141 -0
- package/src/aio/index.ts +3 -0
- package/src/aio/json.ts +127 -0
- package/src/aio/prompt.ts +246 -0
- package/src/basic/README.md +20 -15
- package/src/basic/error.ts +19 -5
- package/src/basic/function.ts +2 -2
- package/src/basic/index.ts +1 -0
- package/src/basic/promise.ts +141 -71
- package/src/basic/schedule.ts +111 -0
- package/src/basic/stream.ts +135 -25
- package/src/credential/README.md +107 -0
- package/src/credential/api-key.ts +158 -0
- package/src/credential/bearer.ts +73 -0
- package/src/credential/index.ts +4 -0
- package/src/credential/json-web-token.ts +96 -0
- package/src/credential/password.ts +170 -0
- package/src/cron/README.md +86 -0
- package/src/cron/cron.ts +87 -0
- package/src/cron/index.ts +1 -0
- package/src/drizzle/README.md +1 -0
- package/src/drizzle/drizzle.ts +1 -0
- package/src/drizzle/helper.ts +47 -0
- package/src/drizzle/index.ts +5 -0
- package/src/drizzle/infer.ts +52 -0
- package/src/drizzle/kysely.ts +8 -0
- package/src/drizzle/pagination.ts +198 -0
- package/src/email/README.md +1 -0
- package/src/email/index.ts +1 -0
- package/src/email/resend.ts +25 -0
- package/src/event/class-event-proxy.ts +5 -6
- package/src/event/common.ts +13 -3
- package/src/event/event-manager.ts +3 -3
- package/src/event/instance-event-proxy.ts +5 -6
- package/src/event/internal.ts +4 -4
- package/src/exception/README.md +28 -19
- package/src/exception/error/error.ts +123 -0
- package/src/exception/error/index.ts +2 -0
- package/src/exception/error/match.ts +38 -0
- package/src/exception/error/must-fix.ts +17 -0
- package/src/exception/index.ts +2 -0
- package/src/file-system/find.ts +53 -0
- package/src/file-system/index.ts +2 -0
- package/src/file-system/path.ts +76 -0
- package/src/file-system/resolve.ts +22 -0
- package/src/form/README.md +25 -0
- package/src/form/index.ts +1 -0
- package/src/form/inputor-controller/base.ts +861 -0
- package/src/form/inputor-controller/boolean.ts +39 -0
- package/src/form/inputor-controller/file.ts +39 -0
- package/src/form/inputor-controller/form.ts +179 -0
- package/src/form/inputor-controller/helper.ts +117 -0
- package/src/form/inputor-controller/index.ts +17 -0
- package/src/form/inputor-controller/multi-select.ts +99 -0
- package/src/form/inputor-controller/number.ts +116 -0
- package/src/form/inputor-controller/select.ts +109 -0
- package/src/form/inputor-controller/text.ts +82 -0
- package/src/http/READMD.md +1 -0
- package/src/http/api/api-core.ts +84 -0
- package/src/http/api/api-handler.ts +79 -0
- package/src/http/api/api-host.ts +47 -0
- package/src/http/api/api-result.ts +56 -0
- package/src/http/api/api-schema.ts +154 -0
- package/src/http/api/api-server.ts +130 -0
- package/src/http/api/api-test.ts +142 -0
- package/src/http/api/api-type.ts +34 -0
- package/src/http/api/api.ts +81 -0
- package/src/http/api/index.ts +11 -0
- package/src/http/api-adapter/api-core-node-http.ts +260 -0
- package/src/http/api-adapter/api-host-node-http.ts +156 -0
- package/src/http/api-adapter/api-result-arktype.ts +294 -0
- package/src/http/api-adapter/api-result-zod.ts +286 -0
- package/src/http/api-adapter/index.ts +5 -0
- package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
- package/src/http/bin/gen-api-list/index.ts +1 -0
- package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
- package/src/http/bin/gen-api-test/index.ts +1 -0
- package/src/http/bin/gen-api-type/calc-code.ts +25 -0
- package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
- package/src/http/bin/gen-api-type/index.ts +2 -0
- package/src/http/bin/index.ts +2 -0
- package/src/http/index.ts +3 -0
- package/src/huawei/README.md +1 -0
- package/src/huawei/index.ts +2 -0
- package/src/huawei/moderation/index.ts +1 -0
- package/src/huawei/moderation/moderation.ts +355 -0
- package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
- package/src/huawei/obs/index.ts +1 -0
- package/src/huawei/obs/obs.ts +42 -0
- package/src/index.ts +21 -2
- package/src/json/README.md +92 -0
- package/src/json/index.ts +1 -0
- package/src/json/repair.ts +18 -0
- package/src/log/logger.ts +15 -4
- package/src/openai/README.md +1 -0
- package/src/openai/index.ts +1 -0
- package/src/openai/openai.ts +509 -0
- package/src/orchestration/README.md +9 -7
- package/src/orchestration/dispatching/dispatcher.ts +83 -0
- package/src/orchestration/dispatching/index.ts +2 -0
- package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
- package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
- package/src/orchestration/dispatching/selector/index.ts +2 -0
- package/src/orchestration/index.ts +2 -0
- package/src/orchestration/scheduling/index.ts +2 -0
- package/src/orchestration/scheduling/scheduler.ts +103 -0
- package/src/orchestration/scheduling/task.ts +32 -0
- package/src/random/README.md +8 -7
- package/src/random/base.ts +66 -0
- package/src/random/index.ts +5 -1
- package/src/random/random-boolean.ts +40 -0
- package/src/random/random-integer.ts +60 -0
- package/src/random/random-number.ts +72 -0
- package/src/random/random-string.ts +66 -0
- package/src/request/README.md +108 -0
- package/src/request/fetch/base.ts +108 -0
- package/src/request/fetch/browser.ts +280 -0
- package/src/request/fetch/general.ts +20 -0
- package/src/request/fetch/index.ts +4 -0
- package/src/request/fetch/nodejs.ts +280 -0
- package/src/request/index.ts +2 -0
- package/src/request/request/base.ts +246 -0
- package/src/request/request/general.ts +63 -0
- package/src/request/request/index.ts +3 -0
- package/src/request/request/resource.ts +68 -0
- package/src/result/README.md +4 -0
- package/src/result/controller.ts +58 -0
- package/src/result/either.ts +363 -0
- package/src/result/generator.ts +168 -0
- package/src/result/index.ts +3 -0
- package/src/route/README.md +105 -0
- package/src/route/adapter/browser.ts +122 -0
- package/src/route/adapter/driver.ts +56 -0
- package/src/route/adapter/index.ts +2 -0
- package/src/route/index.ts +3 -0
- package/src/route/router/index.ts +2 -0
- package/src/route/router/route.ts +630 -0
- package/src/route/router/router.ts +1641 -0
- package/src/route/uri/hash.ts +307 -0
- package/src/route/uri/index.ts +7 -0
- package/src/route/uri/pathname.ts +376 -0
- package/src/route/uri/search.ts +412 -0
- package/src/service/README.md +1 -0
- package/src/service/index.ts +1 -0
- package/src/service/service.ts +110 -0
- package/src/socket/README.md +105 -0
- package/src/socket/client/index.ts +2 -0
- package/src/socket/client/socket-unit.ts +658 -0
- package/src/socket/client/socket.ts +203 -0
- package/src/socket/common/index.ts +2 -0
- package/src/socket/common/socket-unit-common.ts +23 -0
- package/src/socket/common/socket-unit-heartbeat.ts +427 -0
- package/src/socket/index.ts +3 -0
- package/src/socket/server/index.ts +3 -0
- package/src/socket/server/server.ts +183 -0
- package/src/socket/server/socket-unit.ts +448 -0
- package/src/socket/server/socket.ts +264 -0
- package/src/storage/table.ts +3 -3
- package/src/timer/expiration/expiration-manager.ts +3 -3
- package/src/timer/expiration/remaining-manager.ts +3 -3
- package/src/tube/README.md +99 -0
- package/src/tube/helper.ts +137 -0
- package/src/tube/index.ts +2 -0
- package/src/tube/tube.ts +880 -0
- package/src/weixin/README.md +1 -0
- package/src/weixin/index.ts +2 -0
- package/src/weixin/official-account/authorization.ts +157 -0
- package/src/weixin/official-account/index.ts +2 -0
- package/src/weixin/official-account/js-api.ts +132 -0
- package/src/weixin/open/index.ts +1 -0
- package/src/weixin/open/oauth2.ts +131 -0
- package/tests/unit/ai/ai.spec.ts +85 -0
- package/tests/unit/aio/content.spec.ts +105 -0
- package/tests/unit/aio/json.spec.ts +146 -0
- package/tests/unit/aio/prompt.spec.ts +111 -0
- package/tests/unit/basic/error.spec.ts +16 -4
- package/tests/unit/basic/promise.spec.ts +158 -50
- package/tests/unit/basic/schedule.spec.ts +74 -0
- package/tests/unit/basic/stream.spec.ts +90 -37
- package/tests/unit/credential/api-key.spec.ts +36 -0
- package/tests/unit/credential/bearer.spec.ts +23 -0
- package/tests/unit/credential/json-web-token.spec.ts +23 -0
- package/tests/unit/credential/password.spec.ts +40 -0
- package/tests/unit/cron/cron.spec.ts +84 -0
- package/tests/unit/event/class-event-proxy.spec.ts +3 -3
- package/tests/unit/event/event-manager.spec.ts +3 -3
- package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
- package/tests/unit/exception/error/error.spec.ts +83 -0
- package/tests/unit/exception/error/match.spec.ts +81 -0
- package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
- package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
- package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
- package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
- package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
- package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
- package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
- package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
- package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
- package/tests/unit/http/api/api-core-host.spec.ts +207 -0
- package/tests/unit/http/api/api-schema.spec.ts +120 -0
- package/tests/unit/http/api/api-server.spec.ts +363 -0
- package/tests/unit/http/api/api-test.spec.ts +117 -0
- package/tests/unit/http/api/api.spec.ts +121 -0
- package/tests/unit/http/api-adapter/node-http.spec.ts +187 -0
- package/tests/unit/identifier/uuid.spec.ts +0 -1
- package/tests/unit/json/repair.spec.ts +11 -0
- package/tests/unit/log/logger.spec.ts +19 -4
- package/tests/unit/openai/openai.spec.ts +64 -0
- package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
- package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
- package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
- package/tests/unit/random/base.spec.ts +58 -0
- package/tests/unit/random/random-boolean.spec.ts +25 -0
- package/tests/unit/random/random-integer.spec.ts +32 -0
- package/tests/unit/random/random-number.spec.ts +33 -0
- package/tests/unit/random/random-string.spec.ts +22 -0
- package/tests/unit/request/fetch/browser.spec.ts +222 -0
- package/tests/unit/request/fetch/general.spec.ts +43 -0
- package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
- package/tests/unit/request/request/base.spec.ts +382 -0
- package/tests/unit/request/request/general.spec.ts +160 -0
- package/tests/unit/result/controller.spec.ts +82 -0
- package/tests/unit/result/either.spec.ts +377 -0
- package/tests/unit/result/generator.spec.ts +273 -0
- package/tests/unit/route/router/route.spec.ts +430 -0
- package/tests/unit/route/router/router.spec.ts +407 -0
- package/tests/unit/route/uri/hash.spec.ts +72 -0
- package/tests/unit/route/uri/pathname.spec.ts +146 -0
- package/tests/unit/route/uri/search.spec.ts +107 -0
- package/tests/unit/socket/client.spec.ts +208 -0
- package/tests/unit/socket/server.spec.ts +133 -0
- package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
- package/tests/unit/tube/helper.spec.ts +139 -0
- package/tests/unit/tube/tube.spec.ts +501 -0
- package/vite.config.ts +2 -1
- package/dist/index.js +0 -50
- package/dist/index.js.map +0 -209
- package/src/random/string.ts +0 -35
- package/tests/unit/random/string.spec.ts +0 -11
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { ReadableStream } from "node:stream/web"
|
|
2
|
+
|
|
3
|
+
import { afterEach, expect, test, vi } from "vitest"
|
|
4
|
+
|
|
5
|
+
import { streamFromArrayEager } from "#Source/basic/index.ts"
|
|
6
|
+
import {
|
|
7
|
+
connectTube,
|
|
8
|
+
readableStreamToTube,
|
|
9
|
+
Tube,
|
|
10
|
+
tubeToPromise,
|
|
11
|
+
tubeToReadableStream,
|
|
12
|
+
} from "#Source/tube/index.ts"
|
|
13
|
+
|
|
14
|
+
const createTube = (options: Partial<ConstructorParameters<typeof Tube<number, string | Error>>[0]> = {}): Tube<number, string | Error> => {
|
|
15
|
+
return new Tube<number, string | Error>({
|
|
16
|
+
historyCount: 3,
|
|
17
|
+
replayHistory: false,
|
|
18
|
+
...options,
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.useRealTimers()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test("connectTube forwards lifecycle, data and error signals until disconnected", async () => {
|
|
27
|
+
vi.useFakeTimers()
|
|
28
|
+
const upstream = createTube({ autoEndOnError: false, autoCloseOnError: false })
|
|
29
|
+
const downstream = createTube({ autoEndOnError: false, autoCloseOnError: false })
|
|
30
|
+
const downstreamValues: number[] = []
|
|
31
|
+
|
|
32
|
+
downstream.subscribeData({
|
|
33
|
+
subscriber: (value) => {
|
|
34
|
+
downstreamValues.push(value)
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const disconnect = connectTube(upstream, downstream)
|
|
39
|
+
|
|
40
|
+
await upstream.pushData(1)
|
|
41
|
+
await vi.runAllTimersAsync()
|
|
42
|
+
|
|
43
|
+
expect(downstreamValues).toEqual([1])
|
|
44
|
+
expect(downstream.isOpen()).toBe(true)
|
|
45
|
+
expect(downstream.isStart()).toBe(true)
|
|
46
|
+
|
|
47
|
+
await upstream.pushError("boom")
|
|
48
|
+
await vi.runAllTimersAsync()
|
|
49
|
+
|
|
50
|
+
expect(downstream.safeGetLatestError()).toBe("boom")
|
|
51
|
+
|
|
52
|
+
disconnect()
|
|
53
|
+
|
|
54
|
+
await upstream.pushData(2)
|
|
55
|
+
await vi.runAllTimersAsync()
|
|
56
|
+
|
|
57
|
+
expect(downstreamValues).toEqual([1])
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test("tubeToPromise resolves with the latest data on close and rejects on error or empty close", async () => {
|
|
61
|
+
vi.useFakeTimers()
|
|
62
|
+
|
|
63
|
+
const successTube = createTube()
|
|
64
|
+
const successPromise = tubeToPromise(successTube)
|
|
65
|
+
await successTube.pushData(1)
|
|
66
|
+
await successTube.pushData(2)
|
|
67
|
+
await successTube.close()
|
|
68
|
+
await vi.runAllTimersAsync()
|
|
69
|
+
await expect(successPromise).resolves.toBe(2)
|
|
70
|
+
|
|
71
|
+
const errorTube = createTube()
|
|
72
|
+
const errorPromise = tubeToPromise(errorTube)
|
|
73
|
+
await errorTube.pushError(new Error("boom"))
|
|
74
|
+
await vi.runAllTimersAsync()
|
|
75
|
+
await expect(errorPromise).rejects.toThrow("boom")
|
|
76
|
+
|
|
77
|
+
const emptyTube = createTube({ autoStartOnOpen: false, autoEndOnClose: false })
|
|
78
|
+
const emptyPromise = tubeToPromise(emptyTube)
|
|
79
|
+
await emptyTube.open()
|
|
80
|
+
await emptyTube.close()
|
|
81
|
+
await vi.runAllTimersAsync()
|
|
82
|
+
await expect(emptyPromise).rejects.toThrow("No data available")
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test("tubeToReadableStream exposes tube data and propagates stream errors", async () => {
|
|
86
|
+
vi.useFakeTimers()
|
|
87
|
+
|
|
88
|
+
const successTube = createTube()
|
|
89
|
+
const successStream = tubeToReadableStream(successTube)
|
|
90
|
+
const successRead = Array.fromAsync(successStream)
|
|
91
|
+
await successTube.pushData(1)
|
|
92
|
+
await successTube.pushData(2)
|
|
93
|
+
await successTube.close()
|
|
94
|
+
await vi.runAllTimersAsync()
|
|
95
|
+
await expect(successRead).resolves.toEqual([1, 2])
|
|
96
|
+
|
|
97
|
+
const errorTube = createTube()
|
|
98
|
+
const errorStream = tubeToReadableStream(errorTube)
|
|
99
|
+
const errorRead = Array.fromAsync(errorStream)
|
|
100
|
+
await errorTube.pushError(new Error("broken"))
|
|
101
|
+
await vi.runAllTimersAsync()
|
|
102
|
+
await expect(errorRead).rejects.toThrow("broken")
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test("readableStreamToTube consumes readable streams into a tube and records stream errors", async () => {
|
|
106
|
+
vi.useFakeTimers()
|
|
107
|
+
|
|
108
|
+
const values: number[] = []
|
|
109
|
+
const successTube = readableStreamToTube<number, Error>(streamFromArrayEager([1, 2, 3]))
|
|
110
|
+
successTube.subscribeData({
|
|
111
|
+
subscriber: (value) => {
|
|
112
|
+
values.push(value)
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
await vi.runAllTimersAsync()
|
|
117
|
+
|
|
118
|
+
expect(values).toEqual([1, 2, 3])
|
|
119
|
+
expect(successTube.hasClosed()).toBe(true)
|
|
120
|
+
expect(successTube.safeGetLatestData()).toBe(3)
|
|
121
|
+
|
|
122
|
+
const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => undefined)
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const failureTube = readableStreamToTube<number, Error>(new ReadableStream<number>({
|
|
126
|
+
start(controller): void {
|
|
127
|
+
controller.error(new Error("stream-failed"))
|
|
128
|
+
},
|
|
129
|
+
}))
|
|
130
|
+
|
|
131
|
+
await vi.runAllTimersAsync()
|
|
132
|
+
|
|
133
|
+
expect(failureTube.safeGetLatestError()).toBeInstanceOf(Error)
|
|
134
|
+
expect(failureTube.safeGetLatestError().message).toBe("Error: stream-failed")
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
consoleErrorSpy.mockRestore()
|
|
138
|
+
}
|
|
139
|
+
})
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { afterEach, expect, test, vi } from "vitest"
|
|
2
|
+
|
|
3
|
+
import { Tube } from "#Source/tube/index.ts"
|
|
4
|
+
|
|
5
|
+
const createTube = (options: Partial<ConstructorParameters<typeof Tube<number, string | Error>>[0]> = {}): Tube<number, string | Error> => {
|
|
6
|
+
return new Tube<number, string | Error>({
|
|
7
|
+
historyCount: 3,
|
|
8
|
+
replayHistory: false,
|
|
9
|
+
...options,
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const runAllTubeTasks = async (): Promise<void> => {
|
|
14
|
+
await vi.runAllTimersAsync()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
vi.useRealTimers()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test("Tube.safeGetLatestData returns the latest data and throws before any data arrives", async () => {
|
|
22
|
+
const tube = createTube()
|
|
23
|
+
|
|
24
|
+
expect(() => tube.safeGetLatestData()).toThrow("latestData is undefined")
|
|
25
|
+
|
|
26
|
+
await tube.pushData(1)
|
|
27
|
+
await tube.pushData(2)
|
|
28
|
+
|
|
29
|
+
expect(tube.safeGetLatestData()).toBe(2)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("Tube.safeGetLatestError returns the latest error and throws before any error arrives", async () => {
|
|
33
|
+
const tube = createTube()
|
|
34
|
+
|
|
35
|
+
expect(() => tube.safeGetLatestError()).toThrow("latestError is undefined")
|
|
36
|
+
|
|
37
|
+
await tube.pushError("first")
|
|
38
|
+
await tube.pushError("second")
|
|
39
|
+
|
|
40
|
+
expect(tube.safeGetLatestError()).toBe("second")
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test("Tube.isOpen reflects whether the tube is currently open", async () => {
|
|
44
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
45
|
+
|
|
46
|
+
expect(tube.isOpen()).toBe(false)
|
|
47
|
+
|
|
48
|
+
await tube.open()
|
|
49
|
+
|
|
50
|
+
expect(tube.isOpen()).toBe(true)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test("Tube.hasOpened reflects whether the tube has ever been opened", async () => {
|
|
54
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
55
|
+
|
|
56
|
+
expect(tube.hasOpened()).toBe(false)
|
|
57
|
+
|
|
58
|
+
await tube.open()
|
|
59
|
+
|
|
60
|
+
expect(tube.hasOpened()).toBe(true)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("Tube.open opens only once and emits the open event", async () => {
|
|
64
|
+
vi.useFakeTimers()
|
|
65
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
66
|
+
const events: string[] = []
|
|
67
|
+
|
|
68
|
+
tube.subscribeOpenEvent({
|
|
69
|
+
subscriber: () => {
|
|
70
|
+
events.push("open")
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
await tube.open()
|
|
75
|
+
await tube.open()
|
|
76
|
+
await runAllTubeTasks()
|
|
77
|
+
|
|
78
|
+
expect(tube.isOpen()).toBe(true)
|
|
79
|
+
expect(events).toEqual(["open"])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test("Tube.isClose reflects whether the tube is currently closed", async () => {
|
|
83
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
84
|
+
|
|
85
|
+
expect(tube.isClose()).toBe(true)
|
|
86
|
+
|
|
87
|
+
await tube.open()
|
|
88
|
+
|
|
89
|
+
expect(tube.isClose()).toBe(false)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test("Tube.hasClosed reflects whether the tube has ever been closed", async () => {
|
|
93
|
+
const tube = createTube({ autoStartOnOpen: false, autoEndOnClose: false })
|
|
94
|
+
|
|
95
|
+
expect(tube.hasClosed()).toBe(false)
|
|
96
|
+
|
|
97
|
+
await tube.open()
|
|
98
|
+
await tube.close()
|
|
99
|
+
|
|
100
|
+
expect(tube.hasClosed()).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("Tube.close closes only once and emits the close event", async () => {
|
|
104
|
+
vi.useFakeTimers()
|
|
105
|
+
const tube = createTube({ autoStartOnOpen: false, autoEndOnClose: false })
|
|
106
|
+
const events: string[] = []
|
|
107
|
+
|
|
108
|
+
tube.subscribeCloseEvent({
|
|
109
|
+
subscriber: () => {
|
|
110
|
+
events.push("close")
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
await tube.open()
|
|
115
|
+
await tube.close()
|
|
116
|
+
await tube.close()
|
|
117
|
+
await runAllTubeTasks()
|
|
118
|
+
|
|
119
|
+
expect(tube.isClose()).toBe(true)
|
|
120
|
+
expect(events).toEqual(["close"])
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test("Tube.isStart reflects whether the tube is currently started", async () => {
|
|
124
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
125
|
+
|
|
126
|
+
expect(tube.isStart()).toBe(false)
|
|
127
|
+
|
|
128
|
+
await tube.start()
|
|
129
|
+
|
|
130
|
+
expect(tube.isStart()).toBe(true)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test("Tube.hasStarted reflects whether the tube has ever started", async () => {
|
|
134
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
135
|
+
|
|
136
|
+
expect(tube.hasStarted()).toBe(false)
|
|
137
|
+
|
|
138
|
+
await tube.start()
|
|
139
|
+
|
|
140
|
+
expect(tube.hasStarted()).toBe(true)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test("Tube.start starts only once and auto-opens when needed", async () => {
|
|
144
|
+
vi.useFakeTimers()
|
|
145
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
146
|
+
const events: string[] = []
|
|
147
|
+
|
|
148
|
+
tube.subscribeStartEvent({
|
|
149
|
+
subscriber: () => {
|
|
150
|
+
events.push("start")
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
await tube.start()
|
|
155
|
+
await tube.start()
|
|
156
|
+
await runAllTubeTasks()
|
|
157
|
+
|
|
158
|
+
expect(tube.isOpen()).toBe(true)
|
|
159
|
+
expect(tube.isStart()).toBe(true)
|
|
160
|
+
expect(events).toEqual(["start"])
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test("Tube.isEnd reflects whether the tube is currently ended", async () => {
|
|
164
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
165
|
+
|
|
166
|
+
expect(tube.isEnd()).toBe(true)
|
|
167
|
+
|
|
168
|
+
await tube.start()
|
|
169
|
+
|
|
170
|
+
expect(tube.isEnd()).toBe(false)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test("Tube.hasEnded reflects whether the tube has ever ended", async () => {
|
|
174
|
+
const tube = createTube({ autoStartOnOpen: false, autoCloseOnEnd: false })
|
|
175
|
+
|
|
176
|
+
expect(tube.hasEnded()).toBe(false)
|
|
177
|
+
|
|
178
|
+
await tube.start()
|
|
179
|
+
await tube.end()
|
|
180
|
+
|
|
181
|
+
expect(tube.hasEnded()).toBe(true)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test("Tube.end ends only once and closes when configured", async () => {
|
|
185
|
+
vi.useFakeTimers()
|
|
186
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
187
|
+
const events: string[] = []
|
|
188
|
+
|
|
189
|
+
tube.subscribeEndEvent({
|
|
190
|
+
subscriber: () => {
|
|
191
|
+
events.push("end")
|
|
192
|
+
},
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
await tube.start()
|
|
196
|
+
await tube.end()
|
|
197
|
+
await tube.end()
|
|
198
|
+
await runAllTubeTasks()
|
|
199
|
+
|
|
200
|
+
expect(tube.isEnd()).toBe(true)
|
|
201
|
+
expect(tube.hasClosed()).toBe(true)
|
|
202
|
+
expect(events).toEqual(["end"])
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test("Tube.isError reflects whether the tube has seen an error", async () => {
|
|
206
|
+
const tube = createTube()
|
|
207
|
+
|
|
208
|
+
expect(tube.isError()).toBe(false)
|
|
209
|
+
|
|
210
|
+
await tube.pushError("boom")
|
|
211
|
+
|
|
212
|
+
expect(tube.isError()).toBe(true)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
test("Tube.isWet reflects whether the tube has received any data", async () => {
|
|
216
|
+
const tube = createTube()
|
|
217
|
+
|
|
218
|
+
expect(tube.isWet()).toBe(false)
|
|
219
|
+
|
|
220
|
+
await tube.pushData(1)
|
|
221
|
+
|
|
222
|
+
expect(tube.isWet()).toBe(true)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
test("Tube.subscribeOpenEvent returns a stable unsubscribe function and delivers open notifications", async () => {
|
|
226
|
+
vi.useFakeTimers()
|
|
227
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
228
|
+
const subscriber = vi.fn<() => void>(() => undefined)
|
|
229
|
+
|
|
230
|
+
const firstUnsubscribe = tube.subscribeOpenEvent({ subscriber })
|
|
231
|
+
const secondUnsubscribe = tube.subscribeOpenEvent({ subscriber })
|
|
232
|
+
|
|
233
|
+
await tube.open()
|
|
234
|
+
await runAllTubeTasks()
|
|
235
|
+
|
|
236
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
237
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
test("Tube.unsubscribeOpenEvent removes only the specified open subscriber", async () => {
|
|
241
|
+
vi.useFakeTimers()
|
|
242
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
243
|
+
const keptSubscriber = vi.fn<() => void>(() => undefined)
|
|
244
|
+
const removedSubscriber = vi.fn<() => void>(() => undefined)
|
|
245
|
+
|
|
246
|
+
tube.subscribeOpenEvent({ subscriber: keptSubscriber })
|
|
247
|
+
tube.subscribeOpenEvent({ subscriber: removedSubscriber })
|
|
248
|
+
tube.unsubscribeOpenEvent(removedSubscriber)
|
|
249
|
+
|
|
250
|
+
await tube.open()
|
|
251
|
+
await runAllTubeTasks()
|
|
252
|
+
|
|
253
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
254
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
test("Tube.subscribeCloseEvent returns a stable unsubscribe function and delivers close notifications", async () => {
|
|
258
|
+
vi.useFakeTimers()
|
|
259
|
+
const tube = createTube({ autoStartOnOpen: false, autoEndOnClose: false })
|
|
260
|
+
const subscriber = vi.fn<() => void>(() => undefined)
|
|
261
|
+
|
|
262
|
+
const firstUnsubscribe = tube.subscribeCloseEvent({ subscriber })
|
|
263
|
+
const secondUnsubscribe = tube.subscribeCloseEvent({ subscriber })
|
|
264
|
+
|
|
265
|
+
await tube.open()
|
|
266
|
+
await tube.close()
|
|
267
|
+
await runAllTubeTasks()
|
|
268
|
+
|
|
269
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
270
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
test("Tube.unsubscribeCloseEvent removes only the specified close subscriber", async () => {
|
|
274
|
+
vi.useFakeTimers()
|
|
275
|
+
const tube = createTube({ autoStartOnOpen: false, autoEndOnClose: false })
|
|
276
|
+
const keptSubscriber = vi.fn<() => void>(() => undefined)
|
|
277
|
+
const removedSubscriber = vi.fn<() => void>(() => undefined)
|
|
278
|
+
|
|
279
|
+
tube.subscribeCloseEvent({ subscriber: keptSubscriber })
|
|
280
|
+
tube.subscribeCloseEvent({ subscriber: removedSubscriber })
|
|
281
|
+
tube.unsubscribeCloseEvent(removedSubscriber)
|
|
282
|
+
|
|
283
|
+
await tube.open()
|
|
284
|
+
await tube.close()
|
|
285
|
+
await runAllTubeTasks()
|
|
286
|
+
|
|
287
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
288
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
test("Tube.subscribeStartEvent returns a stable unsubscribe function and delivers start notifications", async () => {
|
|
292
|
+
vi.useFakeTimers()
|
|
293
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
294
|
+
const subscriber = vi.fn<() => void>(() => undefined)
|
|
295
|
+
|
|
296
|
+
const firstUnsubscribe = tube.subscribeStartEvent({ subscriber })
|
|
297
|
+
const secondUnsubscribe = tube.subscribeStartEvent({ subscriber })
|
|
298
|
+
|
|
299
|
+
await tube.start()
|
|
300
|
+
await runAllTubeTasks()
|
|
301
|
+
|
|
302
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
303
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
test("Tube.unsubscribeStartEvent removes only the specified start subscriber", async () => {
|
|
307
|
+
vi.useFakeTimers()
|
|
308
|
+
const tube = createTube({ autoStartOnOpen: false })
|
|
309
|
+
const keptSubscriber = vi.fn<() => void>(() => undefined)
|
|
310
|
+
const removedSubscriber = vi.fn<() => void>(() => undefined)
|
|
311
|
+
|
|
312
|
+
tube.subscribeStartEvent({ subscriber: keptSubscriber })
|
|
313
|
+
tube.subscribeStartEvent({ subscriber: removedSubscriber })
|
|
314
|
+
tube.unsubscribeStartEvent(removedSubscriber)
|
|
315
|
+
|
|
316
|
+
await tube.start()
|
|
317
|
+
await runAllTubeTasks()
|
|
318
|
+
|
|
319
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
320
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
test("Tube.subscribeEndEvent returns a stable unsubscribe function and delivers end notifications", async () => {
|
|
324
|
+
vi.useFakeTimers()
|
|
325
|
+
const tube = createTube({ autoStartOnOpen: false, autoCloseOnEnd: false })
|
|
326
|
+
const subscriber = vi.fn<() => void>(() => undefined)
|
|
327
|
+
|
|
328
|
+
const firstUnsubscribe = tube.subscribeEndEvent({ subscriber })
|
|
329
|
+
const secondUnsubscribe = tube.subscribeEndEvent({ subscriber })
|
|
330
|
+
|
|
331
|
+
await tube.start()
|
|
332
|
+
await tube.end()
|
|
333
|
+
await runAllTubeTasks()
|
|
334
|
+
|
|
335
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
336
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
test("Tube.unsubscribeEndEvent removes only the specified end subscriber", async () => {
|
|
340
|
+
vi.useFakeTimers()
|
|
341
|
+
const tube = createTube({ autoStartOnOpen: false, autoCloseOnEnd: false })
|
|
342
|
+
const keptSubscriber = vi.fn<() => void>(() => undefined)
|
|
343
|
+
const removedSubscriber = vi.fn<() => void>(() => undefined)
|
|
344
|
+
|
|
345
|
+
tube.subscribeEndEvent({ subscriber: keptSubscriber })
|
|
346
|
+
tube.subscribeEndEvent({ subscriber: removedSubscriber })
|
|
347
|
+
tube.unsubscribeEndEvent(removedSubscriber)
|
|
348
|
+
|
|
349
|
+
await tube.start()
|
|
350
|
+
await tube.end()
|
|
351
|
+
await runAllTubeTasks()
|
|
352
|
+
|
|
353
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
354
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
test("Tube.subscribeWetEvent returns a stable unsubscribe function and delivers the first wet notification", async () => {
|
|
358
|
+
vi.useFakeTimers()
|
|
359
|
+
const tube = createTube()
|
|
360
|
+
const subscriber = vi.fn<() => void>(() => undefined)
|
|
361
|
+
|
|
362
|
+
const firstUnsubscribe = tube.subscribeWetEvent({ subscriber })
|
|
363
|
+
const secondUnsubscribe = tube.subscribeWetEvent({ subscriber })
|
|
364
|
+
|
|
365
|
+
await tube.pushData(1)
|
|
366
|
+
await tube.pushData(2)
|
|
367
|
+
await runAllTubeTasks()
|
|
368
|
+
|
|
369
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
370
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
test("Tube.unsubscribeWetEvent removes only the specified wet subscriber", async () => {
|
|
374
|
+
vi.useFakeTimers()
|
|
375
|
+
const tube = createTube()
|
|
376
|
+
const keptSubscriber = vi.fn<() => void>(() => undefined)
|
|
377
|
+
const removedSubscriber = vi.fn<() => void>(() => undefined)
|
|
378
|
+
|
|
379
|
+
tube.subscribeWetEvent({ subscriber: keptSubscriber })
|
|
380
|
+
tube.subscribeWetEvent({ subscriber: removedSubscriber })
|
|
381
|
+
tube.unsubscribeWetEvent(removedSubscriber)
|
|
382
|
+
|
|
383
|
+
await tube.pushData(1)
|
|
384
|
+
await runAllTubeTasks()
|
|
385
|
+
|
|
386
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
387
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
test("Tube.pushError records the error, opens the tube when needed and emits error notifications", async () => {
|
|
391
|
+
vi.useFakeTimers()
|
|
392
|
+
const tube = createTube({ autoEndOnError: false, autoCloseOnError: false })
|
|
393
|
+
const errors: Array<string | Error> = []
|
|
394
|
+
|
|
395
|
+
tube.subscribeErrorEvent({
|
|
396
|
+
subscriber: (error) => {
|
|
397
|
+
errors.push(error)
|
|
398
|
+
},
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
await tube.pushError("boom")
|
|
402
|
+
await runAllTubeTasks()
|
|
403
|
+
|
|
404
|
+
expect(tube.isOpen()).toBe(true)
|
|
405
|
+
expect(tube.isError()).toBe(true)
|
|
406
|
+
expect(errors).toEqual(["boom"])
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
test("Tube.subscribeErrorEvent returns a stable unsubscribe function and delivers error notifications", async () => {
|
|
410
|
+
vi.useFakeTimers()
|
|
411
|
+
const tube = createTube({ autoEndOnError: false, autoCloseOnError: false })
|
|
412
|
+
const subscriber = vi.fn<(error: string | Error) => void>(() => undefined)
|
|
413
|
+
|
|
414
|
+
const firstUnsubscribe = tube.subscribeErrorEvent({ subscriber })
|
|
415
|
+
const secondUnsubscribe = tube.subscribeErrorEvent({ subscriber })
|
|
416
|
+
|
|
417
|
+
await tube.pushError("boom")
|
|
418
|
+
await runAllTubeTasks()
|
|
419
|
+
|
|
420
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
421
|
+
expect(subscriber).toHaveBeenCalledTimes(1)
|
|
422
|
+
expect(subscriber).toHaveBeenCalledWith("boom")
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
test("Tube.unsubscribeErrorEvent removes only the specified error subscriber", async () => {
|
|
426
|
+
vi.useFakeTimers()
|
|
427
|
+
const tube = createTube({ autoEndOnError: false, autoCloseOnError: false })
|
|
428
|
+
const keptSubscriber = vi.fn<(error: string | Error) => void>(() => undefined)
|
|
429
|
+
const removedSubscriber = vi.fn<(error: string | Error) => void>(() => undefined)
|
|
430
|
+
|
|
431
|
+
tube.subscribeErrorEvent({ subscriber: keptSubscriber })
|
|
432
|
+
tube.subscribeErrorEvent({ subscriber: removedSubscriber })
|
|
433
|
+
tube.unsubscribeErrorEvent(removedSubscriber)
|
|
434
|
+
|
|
435
|
+
await tube.pushError("boom")
|
|
436
|
+
await runAllTubeTasks()
|
|
437
|
+
|
|
438
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
439
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
test("Tube.pushData records data, auto-starts the tube and trims history by historyCount", async () => {
|
|
443
|
+
vi.useFakeTimers()
|
|
444
|
+
const tube = createTube({ historyCount: 1 })
|
|
445
|
+
const values: number[] = []
|
|
446
|
+
|
|
447
|
+
tube.subscribeData({
|
|
448
|
+
subscriber: (value) => {
|
|
449
|
+
values.push(value)
|
|
450
|
+
},
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
await tube.pushData(1)
|
|
454
|
+
await tube.pushData(2)
|
|
455
|
+
await runAllTubeTasks()
|
|
456
|
+
|
|
457
|
+
expect(tube.isOpen()).toBe(true)
|
|
458
|
+
expect(tube.isStart()).toBe(true)
|
|
459
|
+
expect(tube.isWet()).toBe(true)
|
|
460
|
+
expect(tube.safeGetLatestData()).toBe(2)
|
|
461
|
+
expect(values).toEqual([1, 2])
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
test("Tube.subscribeData returns a stable unsubscribe function and can replay history", async () => {
|
|
465
|
+
vi.useFakeTimers()
|
|
466
|
+
const tube = createTube()
|
|
467
|
+
const values: number[] = []
|
|
468
|
+
const subscriber = vi.fn<(value: number) => void>((value) => {
|
|
469
|
+
values.push(value)
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
await tube.pushData(1)
|
|
473
|
+
await tube.pushData(2)
|
|
474
|
+
|
|
475
|
+
const firstUnsubscribe = tube.subscribeData({ subscriber, replayHistory: true })
|
|
476
|
+
const secondUnsubscribe = tube.subscribeData({ subscriber, replayHistory: true })
|
|
477
|
+
|
|
478
|
+
await tube.pushData(3)
|
|
479
|
+
await runAllTubeTasks()
|
|
480
|
+
|
|
481
|
+
expect(secondUnsubscribe).toBe(firstUnsubscribe)
|
|
482
|
+
expect(values).toEqual([1, 2, 3])
|
|
483
|
+
expect(subscriber).toHaveBeenCalledTimes(3)
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
test("Tube.unsubscribeData removes only the specified data subscriber", async () => {
|
|
487
|
+
vi.useFakeTimers()
|
|
488
|
+
const tube = createTube()
|
|
489
|
+
const keptSubscriber = vi.fn<(value: number) => void>(() => undefined)
|
|
490
|
+
const removedSubscriber = vi.fn<(value: number) => void>(() => undefined)
|
|
491
|
+
|
|
492
|
+
tube.subscribeData({ subscriber: keptSubscriber })
|
|
493
|
+
tube.subscribeData({ subscriber: removedSubscriber })
|
|
494
|
+
tube.unsubscribeData(removedSubscriber)
|
|
495
|
+
|
|
496
|
+
await tube.pushData(1)
|
|
497
|
+
await runAllTubeTasks()
|
|
498
|
+
|
|
499
|
+
expect(keptSubscriber).toHaveBeenCalledTimes(1)
|
|
500
|
+
expect(removedSubscriber).not.toHaveBeenCalled()
|
|
501
|
+
})
|
package/vite.config.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/// <reference types="vitest/config" />
|
|
2
|
+
import type { UserConfig } from "vite"
|
|
2
3
|
import { defineConfig } from "vite";
|
|
3
4
|
|
|
4
|
-
const config = defineConfig({
|
|
5
|
+
const config: UserConfig = defineConfig({
|
|
5
6
|
ssr: {
|
|
6
7
|
resolve: {
|
|
7
8
|
conditions: ["@planet-matrix/mobius-mono"],
|