@powerhousedao/switchboard 6.2.3-dev.32 → 6.2.3-dev.33

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/dist/server.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ILogger } from "document-model";
2
- import { ChannelScheme, IDocumentModelLoader, IReactorClient, InProcessReactorClientModule, JwtHandler, ReactorBuilder, ReactorClientBuilder, ReactorFeatureFlags, SignerConfig } from "@powerhousedao/reactor";
2
+ import { ChannelScheme, IDocumentModelLoader, IReactorClient, InProcessReactorClientModule, JwtHandler, ReactorBuilder, ReactorClientBuilder, ReactorFeatureFlags, SignerConfig, UnsupportedStoredDocuments, UnsupportedStoredProtocolError } from "@powerhousedao/reactor";
3
3
  import { AttachmentReferenceProjectionCapability } from "@powerhousedao/reactor-api";
4
4
  import { IAttachmentService } from "@powerhousedao/reactor-attachments";
5
5
  import { IRenown } from "@renown/sdk/node";
@@ -170,6 +170,14 @@ export type StartServerOptions = {
170
170
  enabled?: boolean;
171
171
  dbPoolSize?: number;
172
172
  };
173
+ /**
174
+ * Stored documents at protocol versions this build does not run: "refuse"
175
+ * (the default) fails the boot with a StoredDocumentsRefusedError;
176
+ * "read-only" starts with a warning and keeps those documents read-only.
177
+ * Unset falls back to the REACTOR_UNSUPPORTED_STORED_DOCUMENTS env var.
178
+ * Ignored when `reactor` is passed.
179
+ */
180
+ unsupportedStoredDocuments?: UnsupportedStoredDocuments;
173
181
  };
174
182
  export type SwitchboardReactor = {
175
183
  defaultDriveUrl: string | undefined;
@@ -244,6 +252,20 @@ type SwitchboardReactorDefaultsOptions = {
244
252
  };
245
253
  export declare function applySwitchboardReactorDefaults(reactorBuilder: ReactorBuilder, clientBuilder: ReactorClientBuilder, options?: SwitchboardReactorDefaultsOptions): void;
246
254
  //#endregion
255
+ //#region src/unsupported-stored-documents.d.mts
256
+ /** From REACTOR_UNSUPPORTED_STORED_DOCUMENTS; `input` wins when defined. */
257
+ export declare function resolveUnsupportedStoredDocuments(input: UnsupportedStoredDocuments | undefined, env: NodeJS.ProcessEnv): UnsupportedStoredDocuments;
258
+ /** The reactor refused to start over documents this build does not run. */
259
+ export declare class StoredDocumentsRefusedError extends Error {
260
+ readonly versions: readonly {
261
+ protocol: string;
262
+ version: number;
263
+ }[];
264
+ readonly documents: number;
265
+ constructor(cause: UnsupportedStoredProtocolError);
266
+ static isError(error: unknown): error is StoredDocumentsRefusedError;
267
+ }
268
+ //#endregion
247
269
  //#region src/server.d.mts
248
270
  /**
249
271
  * Attempt to bind a throwaway TCP server to the given port. Resolves true if
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../src/workflow-runtime.mts","../src/types.ts","../src/builder-defaults.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;;KA2DY;EACN;;EAEA;EACA;;;;;;;;;;YC7CM;;YAKA,wBAAwB;EAClC,eAAe;;YAGL;EACV;EACA;EACA;;YAGU;;EAEV;;;;;EAKA;;EAGA;;YAGU;;;;;;;;;;;;;;;;;;;;;EAqBV,UAAU;;;;;;;;EAQV;;;;;;;EAOA;EACA;EACA;;;;;;EAMA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;IAEM;IACA;;;;;;;EASN,WAAW;;EAEX;EACA;;;EAGA;IACE;;EAEF,kBAAkB;EAClB;EACA;;;;;;EAMA;EACA,SAAS;;;;;;;;;;EAUT;;;;;;;;;;EAUA;;;;;;;;;EASA;IACE;IACA;IACA;;;;;;;;;;;EAWF;IACE;IACA;;;YAIQ;EACV;EACA,SAAS;;EAET,mBAAmB;;EAEnB,+BAA+B;;;EAG/B,mBAAmB;;EAEnB;;EAEA,QAAQ;;;;;EAKR;;;;;;;;;;;;;EAaA,gBAAgB;;;;KCzLN;EAIV,iBAAiB;;EAEjB,mBAAmB;;EAEnB;;;;;;EAMA,gBAAgB;;EAEhB;;EAEA;IACE;IACA,eAAe,QAAQ;;;EAGzB,sBAAsB;EACtB,SAAS;;;;;;EAMT,SAAS;;;;;EAKT,cAAc,KAAK;;EAEnB,wBAAwB;;wBAsBV,gCACd,gBAAgB,gBAChB,eAAe,sBACf,UAAS;;;;;;;;wBC6DK,gBAAgB,eAAe;;wBAoI/B,8BACd,SAAS,KAAK,uDACd,oBACA,QAAQ;EACL;EAAmB,YAAY;;;;;;;;;;;;;;;;;;;qBAu5BvB,mBAAgB,UAClB,uBACR,QAAQ"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/workflow-runtime.mts","../src/types.ts","../src/builder-defaults.mts","../src/unsupported-stored-documents.mts","../src/server.mts"],"mappings":";;;;;;;;;;;;;KA2DY;EACN;;EAEA;EACA;;;;;;;;;;YC5CM;;YAKA,wBAAwB;EAClC,eAAe;;YAGL;EACV;EACA;EACA;;YAGU;;EAEV;;;;;EAKA;;EAGA;;YAGU;;;;;;;;;;;;;;;;;;;;;EAqBV,UAAU;;;;;;;;EAQV;;;;;;;EAOA;EACA;EACA;;;;;;EAMA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;IAEM;IACA;;;;;;;EASN,WAAW;;EAEX;EACA;;;EAGA;IACE;;EAEF,kBAAkB;EAClB;EACA;;;;;;EAMA;EACA,SAAS;;;;;;;;;;EAUT;;;;;;;;;;EAUA;;;;;;;;;EASA;IACE;IACA;IACA;;;;;;;;;;;EAWF;IACE;IACA;;;;;;;;;EASF,6BAA6B;;YAGnB;EACV;EACA,SAAS;;EAET,mBAAmB;;EAEnB,+BAA+B;;;EAG/B,mBAAmB;;EAEnB;;EAEA,QAAQ;;;;;EAKR;;;;;;;;;;;;;EAaA,gBAAgB;;;;KClMN;EAIV,iBAAiB;;EAEjB,mBAAmB;;EAEnB;;;;;;EAMA,gBAAgB;;EAEhB;;EAEA;IACE;IACA,eAAe,QAAQ;;;EAGzB,sBAAsB;EACtB,SAAS;;;;;;EAMT,SAAS;;;;;EAKT,cAAc,KAAK;;EAEnB,wBAAwB;;wBAsBV,gCACd,gBAAgB,gBAChB,eAAe,sBACf,UAAS;;;;wBC3EK,kCACd,OAAO,wCACP,KAAK,OAAO,aACX;;qBAaU,oCAAoC;WACtC;IAAqB;IAAkB;;WACvC;EAET,YAAY,OAAO;SAcZ,QAAQ,iBAAiB,SAAS;;;;;;;;;wBC2G3B,gBAAgB,eAAe;;wBAoI/B,8BACd,SAAS,KAAK,uDACd,oBACA,QAAQ;EACL;EAAmB,YAAY;;;;;;;;;;;;;;;;;;;qBAi7BvB,mBAAgB,UAClB,uBACR,QAAQ"}
package/dist/server.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as applySwitchboardReactorDefaults, n as isPortAvailable, r as startSwitchboard, t as deriveAttachmentServiceConfig } from "./server-CKKn0aXV.mjs";
3
- export { applySwitchboardReactorDefaults, deriveAttachmentServiceConfig, isPortAvailable, startSwitchboard };
4
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fe3a107a-4dd4-530b-b8d9-ef36656e688e")}catch(e){}}();
5
- //# debugId=fe3a107a-4dd4-530b-b8d9-ef36656e688e
2
+ import { a as resolveUnsupportedStoredDocuments, i as StoredDocumentsRefusedError, n as isPortAvailable, o as applySwitchboardReactorDefaults, r as startSwitchboard, t as deriveAttachmentServiceConfig } from "./server-DAgJkmvH.mjs";
3
+ export { StoredDocumentsRefusedError, applySwitchboardReactorDefaults, deriveAttachmentServiceConfig, isPortAvailable, resolveUnsupportedStoredDocuments, startSwitchboard };
4
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="631cf56c-74d8-5495-a51e-94daa58b7193")}catch(e){}}();
5
+ //# debugId=631cf56c-74d8-5495-a51e-94daa58b7193
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/switchboard",
3
3
  "type": "module",
4
- "version": "6.2.3-dev.32",
4
+ "version": "6.2.3-dev.33",
5
5
  "main": "dist/index.mjs",
6
6
  "exports": {
7
7
  ".": {
@@ -41,7 +41,7 @@
41
41
  "@openfeature/core": "1.9.1",
42
42
  "@openfeature/env-var-provider": "0.3.1",
43
43
  "@openfeature/server-sdk": "1.19.0",
44
- "@powerhousedao/config": "6.2.3-dev.32",
44
+ "@powerhousedao/config": "6.2.3-dev.33",
45
45
  "@opentelemetry/api": "^1.9.0",
46
46
  "@opentelemetry/exporter-metrics-otlp-http": "^0.218.0",
47
47
  "@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
@@ -55,22 +55,22 @@
55
55
  "@opentelemetry/sdk-node": "^0.218.0",
56
56
  "@opentelemetry/sdk-trace-base": "^2.7.1",
57
57
  "@opentelemetry/semantic-conventions": "^1.41.1",
58
- "@powerhousedao/opentelemetry-instrumentation-reactor": "6.2.3-dev.32",
59
- "@powerhousedao/reactor": "6.2.3-dev.32",
60
- "@powerhousedao/shared": "6.2.3-dev.32",
61
- "@powerhousedao/vetra": "6.2.3-dev.32",
62
- "@powerhousedao/reactor-api": "6.2.3-dev.32",
63
- "@powerhousedao/reactor-attachments": "6.2.3-dev.32",
64
- "@powerhousedao/reactor-drive": "6.2.3-dev.32",
65
- "@powerhousedao/reactor-group": "6.2.3-dev.32",
66
- "@powerhousedao/reactor-workflow": "6.2.3-dev.32",
67
- "@powerhousedao/workflow": "6.2.3-dev.32",
68
- "@powerhousedao/pglite-fs": "6.2.3-dev.32",
58
+ "@powerhousedao/opentelemetry-instrumentation-reactor": "6.2.3-dev.33",
59
+ "@powerhousedao/reactor": "6.2.3-dev.33",
60
+ "@powerhousedao/shared": "6.2.3-dev.33",
61
+ "@powerhousedao/vetra": "6.2.3-dev.33",
62
+ "@powerhousedao/reactor-api": "6.2.3-dev.33",
63
+ "@powerhousedao/reactor-attachments": "6.2.3-dev.33",
64
+ "@powerhousedao/reactor-drive": "6.2.3-dev.33",
65
+ "@powerhousedao/reactor-group": "6.2.3-dev.33",
66
+ "@powerhousedao/reactor-workflow": "6.2.3-dev.33",
67
+ "@powerhousedao/workflow": "6.2.3-dev.33",
68
+ "@powerhousedao/pglite-fs": "6.2.3-dev.33",
69
69
  "@pyroscope/nodejs": "^0.4.5",
70
- "@renown/sdk": "6.2.3-dev.32",
70
+ "@renown/sdk": "6.2.3-dev.33",
71
71
  "@sentry/node": "^10.53.1",
72
72
  "@sentry/opentelemetry": "^10.53.1",
73
- "document-model": "6.2.3-dev.32",
73
+ "document-model": "6.2.3-dev.33",
74
74
  "dotenv": "^16.4.7",
75
75
  "express": "^4.22.1",
76
76
  "graphql": "^16",
@@ -0,0 +1,210 @@
1
+ import { PGlite } from "@electric-sql/pglite";
2
+ import { AtomicNodeFs } from "@powerhousedao/pglite-fs";
3
+ import {
4
+ JobStatus,
5
+ ReactorBuilder,
6
+ type Database,
7
+ } from "@powerhousedao/reactor";
8
+ import { driveDocumentModelModule } from "@powerhousedao/shared/document-drive";
9
+ import {
10
+ withSignaturePolicy,
11
+ type PeerCapability,
12
+ } from "@powerhousedao/shared/document-model";
13
+ import type { ILogger } from "document-model";
14
+ import { Kysely } from "kysely";
15
+ import { cp, mkdtemp, rm } from "node:fs/promises";
16
+ import { tmpdir } from "node:os";
17
+ import { join } from "node:path";
18
+ import {
19
+ afterAll,
20
+ afterEach,
21
+ beforeAll,
22
+ beforeEach,
23
+ describe,
24
+ expect,
25
+ it,
26
+ vi,
27
+ } from "vitest";
28
+ import { ClosablePGliteDialect } from "../src/pglite-dialect.js";
29
+ import { startSwitchboard } from "../src/server.mjs";
30
+ import { StoredDocumentsRefusedError } from "../src/unsupported-stored-documents.mjs";
31
+
32
+ const ENV_KEYS = [
33
+ "PH_REACTOR_DATABASE_URL",
34
+ "DATABASE_URL",
35
+ "REACTOR_UNSUPPORTED_STORED_DOCUMENTS",
36
+ ] as const;
37
+
38
+ const BASE_REDUCER_7: PeerCapability = {
39
+ kind: "protocol",
40
+ name: "base-reducer",
41
+ baseline: [1, 2],
42
+ supported: () => [1, 2, 7],
43
+ preferred: () => 2,
44
+ optional: false,
45
+ };
46
+
47
+ type StubLogger = ILogger & {
48
+ warn: ReturnType<typeof vi.fn>;
49
+ error: ReturnType<typeof vi.fn>;
50
+ };
51
+
52
+ function stubLogger(): StubLogger {
53
+ const logger = {
54
+ verbose: vi.fn(),
55
+ debug: vi.fn(),
56
+ info: vi.fn(),
57
+ warn: vi.fn(),
58
+ error: vi.fn(),
59
+ child: vi.fn(),
60
+ };
61
+ logger.child.mockReturnValue(logger);
62
+ return logger as unknown as StubLogger;
63
+ }
64
+
65
+ /** A reactor store holding one drive created at base-reducer 7. */
66
+ async function seedStore(dir: string): Promise<void> {
67
+ const db = new Kysely<Database>({
68
+ dialect: new ClosablePGliteDialect(
69
+ new PGlite({ fs: new AtomicNodeFs(dir) }),
70
+ ),
71
+ });
72
+ const module = await new ReactorBuilder()
73
+ .withKysely(db)
74
+ .withDocumentModelSources([driveDocumentModelModule as never])
75
+ .withPeerCapabilities([BASE_REDUCER_7])
76
+ .buildModule();
77
+ const created = await module.reactor.create(
78
+ withSignaturePolicy(
79
+ driveDocumentModelModule.utils.createDocument(),
80
+ "legacy",
81
+ {
82
+ id: "br7-stored",
83
+ protocolVersions: { "base-reducer": 7 },
84
+ },
85
+ ),
86
+ );
87
+ await vi.waitUntil(
88
+ async () => {
89
+ const { status } = await module.reactor.getJobStatus(created.id);
90
+ return status === JobStatus.READ_READY || status === JobStatus.FAILED;
91
+ },
92
+ { timeout: 10_000, interval: 5 },
93
+ );
94
+ expect((await module.reactor.getJobStatus(created.id)).status).toBe(
95
+ JobStatus.READ_READY,
96
+ );
97
+ await module.reactor.kill().completed;
98
+ await db.destroy();
99
+ }
100
+
101
+ // PGlite boots are several times slower on Windows runners.
102
+ const BOOT_TIMEOUT = 120_000;
103
+
104
+ describe("booting over documents this build does not run", () => {
105
+ let seeded: string;
106
+ let tempRoot: string;
107
+ let previous: Partial<Record<(typeof ENV_KEYS)[number], string>>;
108
+
109
+ beforeAll(async () => {
110
+ seeded = await mkdtemp(join(tmpdir(), "switchboard-stored-protocol-seed-"));
111
+ await seedStore(join(seeded, "reactor-storage"));
112
+ }, BOOT_TIMEOUT);
113
+
114
+ afterAll(async () => {
115
+ await rm(seeded, { recursive: true, force: true });
116
+ });
117
+
118
+ beforeEach(async () => {
119
+ tempRoot = await mkdtemp(join(tmpdir(), "switchboard-stored-protocol-"));
120
+ previous = Object.fromEntries(ENV_KEYS.map((k) => [k, process.env[k]]));
121
+ process.env.PH_REACTOR_DATABASE_URL = join(tempRoot, "reactor-storage");
122
+ process.env.DATABASE_URL = join(tempRoot, "read-model");
123
+ delete process.env.REACTOR_UNSUPPORTED_STORED_DOCUMENTS;
124
+ await cp(
125
+ join(seeded, "reactor-storage"),
126
+ process.env.PH_REACTOR_DATABASE_URL,
127
+ { recursive: true },
128
+ );
129
+ });
130
+
131
+ afterEach(async () => {
132
+ for (const key of ENV_KEYS) {
133
+ if (previous[key] === undefined) {
134
+ delete process.env[key];
135
+ } else {
136
+ process.env[key] = previous[key];
137
+ }
138
+ }
139
+ await rm(tempRoot, { recursive: true, force: true });
140
+ });
141
+
142
+ function boot(logger: ILogger) {
143
+ return startSwitchboard({
144
+ workflows: { enabled: false },
145
+ port: 0,
146
+ mcp: false,
147
+ disableLocalPackages: true,
148
+ identity: { keypairPath: join(tempRoot, "identity.json") },
149
+ logger,
150
+ });
151
+ }
152
+
153
+ it(
154
+ "refuses by default and tells the operator both ways forward",
155
+ async () => {
156
+ const logger = stubLogger();
157
+
158
+ const booted = boot(logger);
159
+
160
+ await expect(booted).rejects.toSatisfy(
161
+ (error) =>
162
+ StoredDocumentsRefusedError.isError(error) &&
163
+ error.documents === 1 &&
164
+ error.versions.some(
165
+ ({ protocol, version }) =>
166
+ protocol === "base-reducer" && version === 7,
167
+ ),
168
+ );
169
+ const message = (await booted.catch((error: Error) => error)) as Error;
170
+ expect(message.message).toMatch(
171
+ /1 stored document\(s\) require base-reducer 7/,
172
+ );
173
+ expect(message.message).toMatch(
174
+ /switchboard build that runs base-reducer 7/,
175
+ );
176
+ expect(message.message).toMatch(
177
+ /REACTOR_UNSUPPORTED_STORED_DOCUMENTS=read-only/,
178
+ );
179
+ expect(logger.error).toHaveBeenCalledWith(message.message);
180
+ expect(logger.error).not.toHaveBeenCalledWith(
181
+ "App crashed: @error",
182
+ expect.anything(),
183
+ );
184
+ },
185
+ BOOT_TIMEOUT,
186
+ );
187
+
188
+ it(
189
+ "starts read-only when REACTOR_UNSUPPORTED_STORED_DOCUMENTS says so",
190
+ async () => {
191
+ process.env.REACTOR_UNSUPPORTED_STORED_DOCUMENTS = "read-only";
192
+ const logger = stubLogger();
193
+
194
+ const switchboard = await boot(logger);
195
+ try {
196
+ expect(logger.warn).toHaveBeenCalledWith(
197
+ expect.stringContaining("read-only"),
198
+ expect.stringContaining(
199
+ "1 stored document(s) require base-reducer 7",
200
+ ),
201
+ );
202
+ const stored = await switchboard.reactor.get("br7-stored");
203
+ expect(stored.header.id).toBe("br7-stored");
204
+ } finally {
205
+ await switchboard.shutdown();
206
+ }
207
+ },
208
+ BOOT_TIMEOUT,
209
+ );
210
+ });
@@ -0,0 +1,72 @@
1
+ import { UnsupportedStoredProtocolError } from "@powerhousedao/reactor";
2
+ import { describe, expect, it } from "vitest";
3
+ import {
4
+ StoredDocumentsRefusedError,
5
+ resolveUnsupportedStoredDocuments,
6
+ } from "../src/unsupported-stored-documents.mjs";
7
+
8
+ describe("resolveUnsupportedStoredDocuments", () => {
9
+ it("refuses by default", () => {
10
+ expect(resolveUnsupportedStoredDocuments(undefined, {})).toBe("refuse");
11
+ expect(
12
+ resolveUnsupportedStoredDocuments(undefined, {
13
+ REACTOR_UNSUPPORTED_STORED_DOCUMENTS: " ",
14
+ }),
15
+ ).toBe("refuse");
16
+ });
17
+
18
+ it("reads REACTOR_UNSUPPORTED_STORED_DOCUMENTS", () => {
19
+ expect(
20
+ resolveUnsupportedStoredDocuments(undefined, {
21
+ REACTOR_UNSUPPORTED_STORED_DOCUMENTS: " read-only ",
22
+ }),
23
+ ).toBe("read-only");
24
+ expect(
25
+ resolveUnsupportedStoredDocuments(undefined, {
26
+ REACTOR_UNSUPPORTED_STORED_DOCUMENTS: "refuse",
27
+ }),
28
+ ).toBe("refuse");
29
+ });
30
+
31
+ it("lets the option win over the env var", () => {
32
+ expect(
33
+ resolveUnsupportedStoredDocuments("refuse", {
34
+ REACTOR_UNSUPPORTED_STORED_DOCUMENTS: "read-only",
35
+ }),
36
+ ).toBe("refuse");
37
+ });
38
+
39
+ it("refuses an unknown value", () => {
40
+ expect(() =>
41
+ resolveUnsupportedStoredDocuments(undefined, {
42
+ REACTOR_UNSUPPORTED_STORED_DOCUMENTS: "readonly",
43
+ }),
44
+ ).toThrow(
45
+ 'REACTOR_UNSUPPORTED_STORED_DOCUMENTS must be "refuse" or "read-only", got "readonly"',
46
+ );
47
+ });
48
+ });
49
+
50
+ describe("StoredDocumentsRefusedError", () => {
51
+ it("names the versions, the count and both ways forward", () => {
52
+ const cause = new UnsupportedStoredProtocolError(
53
+ [
54
+ { protocol: "base-reducer", version: 3 },
55
+ { protocol: "base-reducer", version: 7 },
56
+ ],
57
+ 4,
58
+ );
59
+
60
+ const error = new StoredDocumentsRefusedError(cause);
61
+
62
+ expect(error.message).toBe(
63
+ "Refusing to start: 4 stored document(s) require base-reducer 3, base-reducer 7, which this switchboard does not run. " +
64
+ "Either start a switchboard build that runs base-reducer 3, base-reducer 7, or set REACTOR_UNSUPPORTED_STORED_DOCUMENTS=read-only to start with those documents read-only.",
65
+ );
66
+ expect(error.documents).toBe(4);
67
+ expect(error.versions).toBe(cause.versions);
68
+ expect(error.cause).toBe(cause);
69
+ expect(StoredDocumentsRefusedError.isError(error)).toBe(true);
70
+ expect(StoredDocumentsRefusedError.isError(cause)).toBe(false);
71
+ });
72
+ });