@reventlessdev/reventless-local 3.0.0-alpha.276 → 3.0.0-alpha.277
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 +7 -0
- package/package.json +11 -11
- package/src/Platform.res +7 -6
- package/src/Platform.res.mjs +4 -4
- package/src/adapter/Auth/UserStore.res +24 -1
- package/src/adapter/Auth/UserStore.res.mjs +15 -0
- package/tests/adapter/LocalAuthUserStoreTest.res +73 -0
- package/tests/adapter/LocalAuthUserStoreTest.res.mjs +92 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.277 (2026-10-01)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* check a plugin's roles against the user pool's groups ([ddb3c42](https://github.com/ReventlessDev/reventless-core/commit/ddb3c422b7226a19800e781abd5f03af18867007))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 3.0.0-alpha.276 (2026-10-01)
|
|
7
14
|
|
|
8
15
|
* feat!: roles a plugin declares, groups a platform provides ([43daace](https://github.com/ReventlessDev/reventless-core/commit/43daace6ca588afe22562d079af1e6f1da81942e))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-local",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.277",
|
|
4
4
|
"description": "Local platform for Reventless (in-memory or SQLite backend, for development and testing without AWS)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
"graphql-yoga": "^5.21.0",
|
|
35
35
|
"sury": "11.0.0",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
|
-
"@reventlessdev/rescript-effect": "0.1.0-alpha.34",
|
|
38
37
|
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.29",
|
|
38
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.34",
|
|
39
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.20",
|
|
39
40
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.11",
|
|
40
41
|
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.23",
|
|
41
|
-
"@reventlessdev/rescript-
|
|
42
|
-
"@reventlessdev/
|
|
43
|
-
"@reventlessdev/reventless-gwt": "1.0.0-alpha.
|
|
44
|
-
"@reventlessdev/reventless-
|
|
45
|
-
"@reventlessdev/reventless-
|
|
46
|
-
"@reventlessdev/reventless-
|
|
47
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
48
|
-
"@reventlessdev/reventless-seed": "1.0.0-alpha.31"
|
|
49
|
-
"@reventlessdev/reventless-postgres": "3.0.0-alpha.150"
|
|
42
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.23",
|
|
43
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.287",
|
|
44
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.234",
|
|
45
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.151",
|
|
46
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.185",
|
|
47
|
+
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.135",
|
|
48
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.157",
|
|
49
|
+
"@reventlessdev/reventless-seed": "1.0.0-alpha.31"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"rescript": "12.3.1",
|
package/src/Platform.res
CHANGED
|
@@ -107,12 +107,9 @@ module MakeWithConfig = (
|
|
|
107
107
|
let _ = Config.commandHandlerConfig
|
|
108
108
|
|
|
109
109
|
// What this platform provides for the roles its plugins need: every account it
|
|
110
|
-
// can sign in as, built-in and
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
Reventless.Role.provideGroupsFrom(() =>
|
|
114
|
-
LocalAuth.knownGroups()->Array.concat(Reventless.AccountsManifest.declaredGroups())
|
|
115
|
-
)
|
|
110
|
+
// can sign in as, built-in and loaded alike, or the file the store will load
|
|
111
|
+
// when the servers start — after the plugins are built and checked.
|
|
112
|
+
Reventless.Role.provideGroupsFrom(UserStore.providedGroups)
|
|
116
113
|
// Activate Pulumi mock mode — must happen before any component creation.
|
|
117
114
|
// Idempotent, so safe to call even if TestRunner.setup() was already called.
|
|
118
115
|
let _ = TestRunner.setup()
|
|
@@ -2448,6 +2445,10 @@ module MakeWithConfig = (
|
|
|
2448
2445
|
}}`,
|
|
2449
2446
|
)
|
|
2450
2447
|
|
|
2448
|
+
// The role check below reads the accounts as they stand; a user store
|
|
2449
|
+
// loaded from elsewhere after this would leave it compared with the wrong ones.
|
|
2450
|
+
UserStore.pluginChecked := true
|
|
2451
|
+
|
|
2451
2452
|
// Set the active deploy target so resolveTargetGraphQL/MCP() and QueryDb serverRef/relayRef
|
|
2452
2453
|
// route registrations to the correct server. Mirrors AWS resolveTargetApi() pattern.
|
|
2453
2454
|
currentDeployTarget.contents = apiTarget
|
package/src/Platform.res.mjs
CHANGED
|
@@ -26,12 +26,10 @@ import * as UiSlots$ReventlessLocal from "./UiSlots.res.mjs";
|
|
|
26
26
|
import * as Component$ReventlessCore from "@reventlessdev/reventless-core/src/components/Component.res.mjs";
|
|
27
27
|
import * as LocalBus$ReventlessLocal from "./adapter/LocalBus.res.mjs";
|
|
28
28
|
import * as Api_Naming$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/Api_Naming.res.mjs";
|
|
29
|
-
import * as LocalAuth$ReventlessLocal from "./adapter/Auth/LocalAuth.res.mjs";
|
|
30
29
|
import * as PluginSpec$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginSpec.res.mjs";
|
|
31
30
|
import * as UserStore$ReventlessLocal from "./adapter/Auth/UserStore.res.mjs";
|
|
32
31
|
import * as TestRunner$ReventlessLocal from "./test/TestRunner.res.mjs";
|
|
33
32
|
import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateView/UiFragments.res.mjs";
|
|
34
|
-
import * as AccountsManifest$Reventless from "@reventlessdev/reventless-spec/src/types/AccountsManifest.res.mjs";
|
|
35
33
|
import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
|
|
36
34
|
import * as EffectLogger$ReventlessCore from "@reventlessdev/reventless-core/src/util/EffectLogger.res.mjs";
|
|
37
35
|
import * as ShellConfig$ReventlessLocal from "./ShellConfig.res.mjs";
|
|
@@ -143,7 +141,7 @@ function decodeUiFragmentRegistryEventEnvelope(eventJson) {
|
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
function MakeWithConfig(Config) {
|
|
146
|
-
Role$Reventless.provideGroupsFrom(
|
|
144
|
+
Role$Reventless.provideGroupsFrom(UserStore$ReventlessLocal.providedGroups);
|
|
147
145
|
TestRunner$ReventlessLocal.setup();
|
|
148
146
|
let match = Config.backend;
|
|
149
147
|
if (typeof match !== "object") {
|
|
@@ -1757,6 +1755,7 @@ function MakeWithConfig(Config) {
|
|
|
1757
1755
|
let tmp;
|
|
1758
1756
|
tmp = apiTarget === "Domain" ? "Domain" : "Platform";
|
|
1759
1757
|
log.info("Platform", undefined, `deployPlugin target=` + tmp);
|
|
1758
|
+
UserStore$ReventlessLocal.pluginChecked.contents = true;
|
|
1760
1759
|
currentDeployTarget.contents = apiTarget;
|
|
1761
1760
|
StateViewSliceMaker.QueryDbResolvers.serverRef.contents = resolveTargetGraphQL();
|
|
1762
1761
|
let tmp$1;
|
|
@@ -1909,7 +1908,7 @@ function MakeWithConfig(Config) {
|
|
|
1909
1908
|
|
|
1910
1909
|
function Make($star) {
|
|
1911
1910
|
let backend = Backend$ReventlessLocal.fromEnv();
|
|
1912
|
-
Role$Reventless.provideGroupsFrom(
|
|
1911
|
+
Role$Reventless.provideGroupsFrom(UserStore$ReventlessLocal.providedGroups);
|
|
1913
1912
|
TestRunner$ReventlessLocal.setup();
|
|
1914
1913
|
if (typeof backend !== "object") {
|
|
1915
1914
|
BackendState$ReventlessLocal.setMemory();
|
|
@@ -3502,6 +3501,7 @@ function Make($star) {
|
|
|
3502
3501
|
let tmp;
|
|
3503
3502
|
tmp = apiTarget === "Domain" ? "Domain" : "Platform";
|
|
3504
3503
|
log.info("Platform", undefined, `deployPlugin target=` + tmp);
|
|
3504
|
+
UserStore$ReventlessLocal.pluginChecked.contents = true;
|
|
3505
3505
|
currentDeployTarget.contents = apiTarget;
|
|
3506
3506
|
StateViewSliceMaker.QueryDbResolvers.serverRef.contents = resolveTargetGraphQL();
|
|
3507
3507
|
let tmp$1;
|
|
@@ -56,12 +56,35 @@ type resolution =
|
|
|
56
56
|
// auto-discovery before `Platform.startServers`.
|
|
57
57
|
let resolved: ref<bool> = ref(false)
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
/** Set once a plugin has been built, and with it the check that every role it
|
|
60
|
+
needs has a group among these accounts. */
|
|
61
|
+
let pluginChecked: ref<bool> = ref(false)
|
|
62
|
+
|
|
63
|
+
let resetResolution = (): unit => {
|
|
64
|
+
resolved := false
|
|
65
|
+
pluginChecked := false
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
The groups the store's accounts will belong to, for the role check, which runs
|
|
70
|
+
before the servers start and load it: the loaded accounts once `load` has run,
|
|
71
|
+
otherwise the default file `autoLoadOnce` will read (or the template `setup`
|
|
72
|
+
makes it from). Never the working directory once another source was loaded.
|
|
73
|
+
*/
|
|
74
|
+
let providedGroups = (): array<string> =>
|
|
75
|
+
LocalAuth.knownGroups()->Array.concat(resolved.contents ? [] : AccountsManifest.declaredGroups())
|
|
60
76
|
|
|
61
77
|
let load = (~users: option<array<entry>>=?, ~usersFile: option<string>=?, ()): result<
|
|
62
78
|
resolution,
|
|
63
79
|
string,
|
|
64
80
|
> => {
|
|
81
|
+
// The default file is what the check already read; any other source arrives
|
|
82
|
+
// after it, and the check would have compared the plugins with other accounts.
|
|
83
|
+
if pluginChecked.contents && (users->Option.isSome || usersFile->Option.isSome) {
|
|
84
|
+
JsError.throwWithMessage(
|
|
85
|
+
"UserStore.load(~users / ~usersFile) after a plugin was built — the check that every role it needs has a group read other accounts. Call UserStore.load before deploying plugins.",
|
|
86
|
+
)
|
|
87
|
+
}
|
|
65
88
|
resolved := true
|
|
66
89
|
switch users {
|
|
67
90
|
| Some(entries) =>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as Nodefs from "node:fs";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
5
|
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
6
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
6
7
|
import * as LocalAuth$ReventlessLocal from "./LocalAuth.res.mjs";
|
|
7
8
|
import * as AccountsManifest$Reventless from "@reventlessdev/reventless-spec/src/types/AccountsManifest.res.mjs";
|
|
8
9
|
|
|
@@ -25,11 +26,23 @@ let resolved = {
|
|
|
25
26
|
contents: false
|
|
26
27
|
};
|
|
27
28
|
|
|
29
|
+
let pluginChecked = {
|
|
30
|
+
contents: false
|
|
31
|
+
};
|
|
32
|
+
|
|
28
33
|
function resetResolution() {
|
|
29
34
|
resolved.contents = false;
|
|
35
|
+
pluginChecked.contents = false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function providedGroups() {
|
|
39
|
+
return LocalAuth$ReventlessLocal.knownGroups().concat(resolved.contents ? [] : AccountsManifest$Reventless.declaredGroups());
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
function load(users, usersFile, param) {
|
|
43
|
+
if (pluginChecked.contents && (Stdlib_Option.isSome(users) || Stdlib_Option.isSome(usersFile))) {
|
|
44
|
+
Stdlib_JsError.throwWithMessage("UserStore.load(~users / ~usersFile) after a plugin was built — the check that every role it needs has a group read other accounts. Call UserStore.load before deploying plugins.");
|
|
45
|
+
}
|
|
33
46
|
resolved.contents = true;
|
|
34
47
|
if (users !== undefined) {
|
|
35
48
|
_registerEntries(users);
|
|
@@ -84,7 +97,9 @@ export {
|
|
|
84
97
|
_registerEntries,
|
|
85
98
|
_defaultPath,
|
|
86
99
|
resolved,
|
|
100
|
+
pluginChecked,
|
|
87
101
|
resetResolution,
|
|
102
|
+
providedGroups,
|
|
88
103
|
load,
|
|
89
104
|
autoLoadOnce,
|
|
90
105
|
}
|
|
@@ -160,3 +160,76 @@ testPromise("autoLoadOnce is a no-op after an explicit load", async () => {
|
|
|
160
160
|
| None => JsError.throwWithMessage("autoLoadOnce wiped explicit registration")
|
|
161
161
|
}
|
|
162
162
|
})
|
|
163
|
+
|
|
164
|
+
// What the role check counts as provided, before the servers load the store.
|
|
165
|
+
describe("UserStore.providedGroups", () => {
|
|
166
|
+
// Runs `f` in a directory holding `files` (path relative to it → contents).
|
|
167
|
+
let inDir = (files: array<(string, string)>, f) => {
|
|
168
|
+
let dir = NodeFs.mkdtempSync(NodePath.join([NodeOs.tmpdir(), "reventless-provided-"]))
|
|
169
|
+
files->Array.forEach(((file, contents)) => {
|
|
170
|
+
let path = NodePath.join([dir, file])
|
|
171
|
+
NodeFs.mkdirSync(NodePath.dirname(path), {recursive: true})
|
|
172
|
+
NodeFs.writeFileSync(path, contents)
|
|
173
|
+
})
|
|
174
|
+
let cwd = NodeProcess.cwd()
|
|
175
|
+
NodeProcess.chdir(dir)
|
|
176
|
+
let result = try f() catch {
|
|
177
|
+
| exn =>
|
|
178
|
+
NodeProcess.chdir(cwd)
|
|
179
|
+
throw(exn)
|
|
180
|
+
}
|
|
181
|
+
NodeProcess.chdir(cwd)
|
|
182
|
+
NodeFs.rmSync(dir, {recursive: true, force: true})
|
|
183
|
+
result
|
|
184
|
+
}
|
|
185
|
+
let manifest = group => `- username: m\n password: m\n groups: [${group}]\n`
|
|
186
|
+
let has = (group, groups) => groups->Array.includes(group)
|
|
187
|
+
|
|
188
|
+
testSync("counts the default file the servers will load", () => {
|
|
189
|
+
resetAll()
|
|
190
|
+
let groups = inDir(
|
|
191
|
+
[(".reventless/users.yaml", manifest("Merchandiser"))],
|
|
192
|
+
() => UserStore.providedGroups(),
|
|
193
|
+
)
|
|
194
|
+
expect(has("Merchandiser", groups))->toBe(true)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
testSync("counts the template where setup has not made the file yet", () => {
|
|
198
|
+
resetAll()
|
|
199
|
+
let groups = inDir(
|
|
200
|
+
[("users.example.yaml", manifest("Fulfilment"))],
|
|
201
|
+
() => UserStore.providedGroups(),
|
|
202
|
+
)
|
|
203
|
+
expect(has("Fulfilment", groups))->toBe(true)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
testSync("once loaded from elsewhere, counts those accounts and not the directory's", () => {
|
|
207
|
+
resetAll()
|
|
208
|
+
let _ = UserStore.load(~users=[{username: "i", password: "i", groups: ["Inline"]}], ())
|
|
209
|
+
let groups = inDir(
|
|
210
|
+
[(".reventless/users.yaml", manifest("Merchandiser"))],
|
|
211
|
+
() => UserStore.providedGroups(),
|
|
212
|
+
)
|
|
213
|
+
expect((has("Inline", groups), has("Merchandiser", groups)))->toEqual((true, false))
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
testSync("loading other accounts after a plugin was checked is refused", () => {
|
|
217
|
+
resetAll()
|
|
218
|
+
UserStore.pluginChecked := true
|
|
219
|
+
let refused = switch UserStore.load(
|
|
220
|
+
~users=[{username: "late", password: "l", groups: ["Late"]}],
|
|
221
|
+
(),
|
|
222
|
+
) {
|
|
223
|
+
| _ => false
|
|
224
|
+
| exception JsExn(_) => true
|
|
225
|
+
}
|
|
226
|
+
expect(refused)->toBe(true)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
testSync("the default load after a plugin was checked is the one the check read", () => {
|
|
230
|
+
resetAll()
|
|
231
|
+
UserStore.pluginChecked := true
|
|
232
|
+
let loaded = inDir([], () => UserStore.load()->Result.isOk)
|
|
233
|
+
expect(loaded)->toBe(true)
|
|
234
|
+
})
|
|
235
|
+
})
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import * as Nodefs from "node:fs";
|
|
4
4
|
import * as Nodeos from "node:os";
|
|
5
5
|
import * as Nodepath from "node:path";
|
|
6
|
+
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
6
7
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
7
9
|
import * as LocalAuth$ReventlessLocal from "../../src/adapter/Auth/LocalAuth.res.mjs";
|
|
8
10
|
import * as UserStore$ReventlessLocal from "../../src/adapter/Auth/UserStore.res.mjs";
|
|
9
11
|
|
|
@@ -201,6 +203,96 @@ globalThis.test("autoLoadOnce is a no-op after an explicit load", async () => {
|
|
|
201
203
|
}
|
|
202
204
|
});
|
|
203
205
|
|
|
206
|
+
globalThis.describe("UserStore.providedGroups", () => {
|
|
207
|
+
let inDir = (files, f) => {
|
|
208
|
+
let dir = Nodefs.mkdtempSync(Nodepath.join(Nodeos.tmpdir(), "reventless-provided-"));
|
|
209
|
+
files.forEach(param => {
|
|
210
|
+
let path = Nodepath.join(dir, param[0]);
|
|
211
|
+
Nodefs.mkdirSync(Nodepath.dirname(path), {
|
|
212
|
+
recursive: true
|
|
213
|
+
});
|
|
214
|
+
Nodefs.writeFileSync(path, param[1], "utf8");
|
|
215
|
+
});
|
|
216
|
+
let cwd = process.cwd();
|
|
217
|
+
process.chdir(dir);
|
|
218
|
+
let result;
|
|
219
|
+
try {
|
|
220
|
+
result = f();
|
|
221
|
+
} catch (exn) {
|
|
222
|
+
process.chdir(cwd);
|
|
223
|
+
throw exn;
|
|
224
|
+
}
|
|
225
|
+
process.chdir(cwd);
|
|
226
|
+
Nodefs.rmSync(dir, {
|
|
227
|
+
recursive: true,
|
|
228
|
+
force: true
|
|
229
|
+
});
|
|
230
|
+
return result;
|
|
231
|
+
};
|
|
232
|
+
globalThis.test("counts the default file the servers will load", () => {
|
|
233
|
+
resetAll();
|
|
234
|
+
let groups = inDir([[
|
|
235
|
+
".reventless/users.yaml",
|
|
236
|
+
`- username: m\n password: m\n groups: [` + "Merchandiser" + `]\n`
|
|
237
|
+
]], () => UserStore$ReventlessLocal.providedGroups());
|
|
238
|
+
globalThis.expect(groups.includes("Merchandiser")).toBe(true);
|
|
239
|
+
});
|
|
240
|
+
globalThis.test("counts the template where setup has not made the file yet", () => {
|
|
241
|
+
resetAll();
|
|
242
|
+
let groups = inDir([[
|
|
243
|
+
"users.example.yaml",
|
|
244
|
+
`- username: m\n password: m\n groups: [` + "Fulfilment" + `]\n`
|
|
245
|
+
]], () => UserStore$ReventlessLocal.providedGroups());
|
|
246
|
+
globalThis.expect(groups.includes("Fulfilment")).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
globalThis.test("once loaded from elsewhere, counts those accounts and not the directory's", () => {
|
|
249
|
+
resetAll();
|
|
250
|
+
UserStore$ReventlessLocal.load([{
|
|
251
|
+
username: "i",
|
|
252
|
+
password: "i",
|
|
253
|
+
groups: ["Inline"]
|
|
254
|
+
}], undefined, undefined);
|
|
255
|
+
let groups = inDir([[
|
|
256
|
+
".reventless/users.yaml",
|
|
257
|
+
`- username: m\n password: m\n groups: [` + "Merchandiser" + `]\n`
|
|
258
|
+
]], () => UserStore$ReventlessLocal.providedGroups());
|
|
259
|
+
globalThis.expect([
|
|
260
|
+
groups.includes("Inline"),
|
|
261
|
+
groups.includes("Merchandiser")
|
|
262
|
+
]).toEqual([
|
|
263
|
+
true,
|
|
264
|
+
false
|
|
265
|
+
]);
|
|
266
|
+
});
|
|
267
|
+
globalThis.test("loading other accounts after a plugin was checked is refused", () => {
|
|
268
|
+
resetAll();
|
|
269
|
+
UserStore$ReventlessLocal.pluginChecked.contents = true;
|
|
270
|
+
let refused;
|
|
271
|
+
try {
|
|
272
|
+
UserStore$ReventlessLocal.load([{
|
|
273
|
+
username: "late",
|
|
274
|
+
password: "l",
|
|
275
|
+
groups: ["Late"]
|
|
276
|
+
}], undefined, undefined);
|
|
277
|
+
refused = false;
|
|
278
|
+
} catch (raw_exn) {
|
|
279
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
280
|
+
if (exn.RE_EXN_ID === "JsExn") {
|
|
281
|
+
refused = true;
|
|
282
|
+
} else {
|
|
283
|
+
throw exn;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
globalThis.expect(refused).toBe(true);
|
|
287
|
+
});
|
|
288
|
+
globalThis.test("the default load after a plugin was checked is the one the check read", () => {
|
|
289
|
+
resetAll();
|
|
290
|
+
UserStore$ReventlessLocal.pluginChecked.contents = true;
|
|
291
|
+
let loaded = inDir([], () => Stdlib_Result.isOk(UserStore$ReventlessLocal.load(undefined, undefined, undefined)));
|
|
292
|
+
globalThis.expect(loaded).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
204
296
|
export {
|
|
205
297
|
resetAll,
|
|
206
298
|
_writeYamlFile,
|