@softr/sdk 0.0.69 → 0.0.70
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/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/package.js +1 -1
- package/dist/visibility/page.d.ts +72 -0
- package/dist/visibility/page.js +79 -0
- package/dist/visibility/route.d.ts +12 -6
- package/dist/visibility/route.js +12 -8
- package/dist/visibility/visibility.d.ts +4 -9
- package/dist/visibility/visibility.js +11 -12
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { DateOptions, DateParts, DateSeparator, DateValue, FixedDateFormat, Form
|
|
|
6
6
|
import { SoftrContext } from "./auth/context.js";
|
|
7
7
|
import { AuthSettings } from "./auth/platform.js";
|
|
8
8
|
import { checkAccess, defineVisibility, isAuthorized } from "./visibility/visibility.js";
|
|
9
|
+
import { Page, PageSettings, definePage, pageHead } from "./visibility/page.js";
|
|
9
10
|
import { assertRouteAccess, guardRoute, isAccessError, isAlreadyAuthenticatedError, isForbiddenError, isUnauthenticatedError } from "./visibility/route.js";
|
|
10
11
|
import { toReturnPath } from "./auth/returnPath.js";
|
|
11
12
|
import { AuthOptions, AuthSettingsProvider, getAuthSettings, getSoftrContext, initialSoftrContext, softrAuthMiddleware, useAuthSettings, useCurrentUser } from "./auth/isomorphic.js";
|
|
@@ -16,4 +17,4 @@ import { useUserTimezone } from "./timezone.js";
|
|
|
16
17
|
import { PwaInstall, PwaPlatform, SoftrPwaHead, usePwaInstall } from "./pwa.js";
|
|
17
18
|
import { DefaultErrorOverlay } from "./default-error-overlay.js";
|
|
18
19
|
import { Audience } from "./visibility/audience.js";
|
|
19
|
-
export { type ActionPermissions, Audience, type AuthOptions, type AuthSettings, AuthSettingsProvider, type DateOptions, type DateParts, type DateSeparator, type DateValue, DefaultErrorOverlay, type FieldShape, type FileAttachment, type FileItem, type FixedDateFormat, FormattedDate, type Formatting, FormattingScope, type PwaInstall, type PwaPlatform, type SoftrContext, type SoftrDatasources, type SoftrFieldRegistry, SoftrPwaHead, type SoftrUserGroupId, type SoftrUserGroups, type User, type WeekDay, assertRouteAccess, checkAccess, defineIntegration, defineMutation, defineQuery, defineVisibility, defineWorkflow, fieldShape, formatDate, formatDateTime, formatDuration, formatField, formatNumber, formatValue, getAuthSettings, getSoftrContext, guardRoute, initialSoftrContext, isAccessError, isAlreadyAuthenticatedError, isAuthorized, isForbiddenError, isUnauthenticatedError, registerSoftrFields, softrAuthMiddleware, softrMcpMiddleware, toReturnPath, useAuthSettings, useCurrentUser, useFileUpload, useFormatting, useOverrides, usePwaInstall, useUserTimezone };
|
|
20
|
+
export { type ActionPermissions, Audience, type AuthOptions, type AuthSettings, AuthSettingsProvider, type DateOptions, type DateParts, type DateSeparator, type DateValue, DefaultErrorOverlay, type FieldShape, type FileAttachment, type FileItem, type FixedDateFormat, FormattedDate, type Formatting, FormattingScope, type Page, type PageSettings, type PwaInstall, type PwaPlatform, type SoftrContext, type SoftrDatasources, type SoftrFieldRegistry, SoftrPwaHead, type SoftrUserGroupId, type SoftrUserGroups, type User, type WeekDay, assertRouteAccess, checkAccess, defineIntegration, defineMutation, definePage, defineQuery, defineVisibility, defineWorkflow, fieldShape, formatDate, formatDateTime, formatDuration, formatField, formatNumber, formatValue, getAuthSettings, getSoftrContext, guardRoute, initialSoftrContext, isAccessError, isAlreadyAuthenticatedError, isAuthorized, isForbiddenError, isUnauthenticatedError, pageHead, registerSoftrFields, softrAuthMiddleware, softrMcpMiddleware, toReturnPath, useAuthSettings, useCurrentUser, useFileUpload, useFormatting, useOverrides, usePwaInstall, useUserTimezone };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { useFileUpload } from "./core/use-file-upload.js";
|
|
|
2
2
|
import { defineIntegration, defineMutation, defineQuery, defineWorkflow } from "./action.js";
|
|
3
3
|
import { checkAccess, defineVisibility, isAuthorized } from "./visibility/visibility.js";
|
|
4
4
|
import { assertRouteAccess, guardRoute, isAccessError, isAlreadyAuthenticatedError, isForbiddenError, isUnauthenticatedError } from "./visibility/route.js";
|
|
5
|
+
import { definePage, pageHead } from "./visibility/page.js";
|
|
5
6
|
import { toReturnPath } from "./auth/returnPath.js";
|
|
6
7
|
import { FormattedDate, FormattingScope, formatDate, formatDateTime, formatNumber, useFormatting } from "./formatting.js";
|
|
7
8
|
import { SoftrPwaHead, usePwaInstall } from "./pwa.js";
|
|
@@ -13,4 +14,4 @@ import { useUserTimezone } from "./timezone.js";
|
|
|
13
14
|
import { DefaultErrorOverlay } from "./default-error-overlay.js";
|
|
14
15
|
import { Audience } from "./visibility/audience.js";
|
|
15
16
|
|
|
16
|
-
export { Audience, AuthSettingsProvider, DefaultErrorOverlay, FormattedDate, FormattingScope, SoftrPwaHead, assertRouteAccess, checkAccess, defineIntegration, defineMutation, defineQuery, defineVisibility, defineWorkflow, fieldShape, formatDate, formatDateTime, formatDuration, formatField, formatNumber, formatValue, getAuthSettings, getSoftrContext, guardRoute, initialSoftrContext, isAccessError, isAlreadyAuthenticatedError, isAuthorized, isForbiddenError, isUnauthenticatedError, registerSoftrFields, softrAuthMiddleware, softrMcpMiddleware, toReturnPath, useAuthSettings, useCurrentUser, useFileUpload, useFormatting, useOverrides, usePwaInstall, useUserTimezone };
|
|
17
|
+
export { Audience, AuthSettingsProvider, DefaultErrorOverlay, FormattedDate, FormattingScope, SoftrPwaHead, assertRouteAccess, checkAccess, defineIntegration, defineMutation, definePage, defineQuery, defineVisibility, defineWorkflow, fieldShape, formatDate, formatDateTime, formatDuration, formatField, formatNumber, formatValue, getAuthSettings, getSoftrContext, guardRoute, initialSoftrContext, isAccessError, isAlreadyAuthenticatedError, isAuthorized, isForbiddenError, isUnauthenticatedError, pageHead, registerSoftrFields, softrAuthMiddleware, softrMcpMiddleware, toReturnPath, useAuthSettings, useCurrentUser, useFileUpload, useFormatting, useOverrides, usePwaInstall, useUserTimezone };
|
package/dist/package.js
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { VisibilityRule } from "./visibility.js";
|
|
2
|
+
import { AnyRouteMatch } from "@tanstack/react-router";
|
|
3
|
+
|
|
4
|
+
//#region src/visibility/page.d.ts
|
|
5
|
+
/** The part of TanStack's `head` context a page setting can read. */
|
|
6
|
+
type HeadContext = {
|
|
7
|
+
match: {
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
10
|
+
matches: ReadonlyArray<{
|
|
11
|
+
id: string;
|
|
12
|
+
}>;
|
|
13
|
+
loaderData?: AnyRouteMatch["loaderData"];
|
|
14
|
+
};
|
|
15
|
+
type HeadSetting<T> = T | ((ctx: HeadContext) => T | undefined);
|
|
16
|
+
type PageSettings = {
|
|
17
|
+
visibility?: VisibilityRule;
|
|
18
|
+
title?: HeadSetting<string>;
|
|
19
|
+
description?: HeadSetting<string>;
|
|
20
|
+
searchEngineIndexing?: HeadSetting<boolean>;
|
|
21
|
+
canonicalUrl?: HeadSetting<string>;
|
|
22
|
+
socialTitle?: HeadSetting<string>;
|
|
23
|
+
socialDescription?: HeadSetting<string>;
|
|
24
|
+
socialImage?: HeadSetting<string>;
|
|
25
|
+
};
|
|
26
|
+
declare const pageBrand: unique symbol;
|
|
27
|
+
/** The settings {@link definePage} has produced. */
|
|
28
|
+
type Page<S extends PageSettings = PageSettings> = S & {
|
|
29
|
+
readonly [pageBrand]: "page";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Declares a route's settings: who may open it, its title and its SEO tags.
|
|
33
|
+
*
|
|
34
|
+
* One call per route file, at module scope, with an object literal. Studio
|
|
35
|
+
* reads and rewrites each setting written out as a literal; a computed one is
|
|
36
|
+
* changed in the code. A head setting that depends on the route's data is a
|
|
37
|
+
* function of its head context. The route's `beforeLoad` and `head` apply it.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const pageSettings = definePage({
|
|
41
|
+
* visibility: { userGroupTypes: ["LOGGED_IN_USERS"] },
|
|
42
|
+
* title: ({ loaderData }) => loaderData?.name,
|
|
43
|
+
* })
|
|
44
|
+
*
|
|
45
|
+
* export const Route = createFileRoute("/_app/projects/$projectId")({
|
|
46
|
+
* beforeLoad: guardRoute(pageSettings),
|
|
47
|
+
* loader: ({ params }) => loadProject({ data: params.projectId }),
|
|
48
|
+
* head: pageHead(pageSettings),
|
|
49
|
+
* component: Project,
|
|
50
|
+
* })
|
|
51
|
+
*/
|
|
52
|
+
declare function definePage<const S extends PageSettings>(settings: S & { [K in Exclude<keyof S, keyof PageSettings>]: never }): Page<S>;
|
|
53
|
+
type Meta = NonNullable<AnyRouteMatch["meta"]>;
|
|
54
|
+
type Links = NonNullable<AnyRouteMatch["links"]>;
|
|
55
|
+
/**
|
|
56
|
+
* The router keeps the deepest route's tag for each title, name and property,
|
|
57
|
+
* so a layout's settings reach every page under it that does not state its own.
|
|
58
|
+
* A canonical URL names one page, so only the page the visitor is on renders
|
|
59
|
+
* its own.
|
|
60
|
+
*
|
|
61
|
+
* Returned rather than called with the route's context: a `head` written as
|
|
62
|
+
* `(ctx) => …` before `loader` stops TypeScript inferring the loader's types.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* head: pageHead(pageSettings)
|
|
66
|
+
*/
|
|
67
|
+
declare function pageHead(page: Page): (ctx: HeadContext) => {
|
|
68
|
+
meta: Meta;
|
|
69
|
+
links: Links;
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { Page, PageSettings, definePage, pageHead };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
//#region src/visibility/page.ts
|
|
2
|
+
/**
|
|
3
|
+
* Declares a route's settings: who may open it, its title and its SEO tags.
|
|
4
|
+
*
|
|
5
|
+
* One call per route file, at module scope, with an object literal. Studio
|
|
6
|
+
* reads and rewrites each setting written out as a literal; a computed one is
|
|
7
|
+
* changed in the code. A head setting that depends on the route's data is a
|
|
8
|
+
* function of its head context. The route's `beforeLoad` and `head` apply it.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const pageSettings = definePage({
|
|
12
|
+
* visibility: { userGroupTypes: ["LOGGED_IN_USERS"] },
|
|
13
|
+
* title: ({ loaderData }) => loaderData?.name,
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* export const Route = createFileRoute("/_app/projects/$projectId")({
|
|
17
|
+
* beforeLoad: guardRoute(pageSettings),
|
|
18
|
+
* loader: ({ params }) => loadProject({ data: params.projectId }),
|
|
19
|
+
* head: pageHead(pageSettings),
|
|
20
|
+
* component: Project,
|
|
21
|
+
* })
|
|
22
|
+
*/
|
|
23
|
+
function definePage(settings) {
|
|
24
|
+
return settings;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The router keeps the deepest route's tag for each title, name and property,
|
|
28
|
+
* so a layout's settings reach every page under it that does not state its own.
|
|
29
|
+
* A canonical URL names one page, so only the page the visitor is on renders
|
|
30
|
+
* its own.
|
|
31
|
+
*
|
|
32
|
+
* Returned rather than called with the route's context: a `head` written as
|
|
33
|
+
* `(ctx) => …` before `loader` stops TypeScript inferring the loader's types.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* head: pageHead(pageSettings)
|
|
37
|
+
*/
|
|
38
|
+
function pageHead(page) {
|
|
39
|
+
return (ctx) => {
|
|
40
|
+
const resolve = (setting) => typeof setting === "function" ? setting(ctx) : setting;
|
|
41
|
+
const tag = (setting, make) => {
|
|
42
|
+
const value = resolve(setting);
|
|
43
|
+
return typeof value === "string" && value !== "" ? [make(value)] : [];
|
|
44
|
+
};
|
|
45
|
+
const indexing = resolve(page.searchEngineIndexing);
|
|
46
|
+
return {
|
|
47
|
+
meta: [
|
|
48
|
+
...tag(page.title, (title) => ({ title })),
|
|
49
|
+
...tag(page.description, (content) => ({
|
|
50
|
+
name: "description",
|
|
51
|
+
content
|
|
52
|
+
})),
|
|
53
|
+
...tag(page.socialTitle, (content) => ({
|
|
54
|
+
property: "og:title",
|
|
55
|
+
content
|
|
56
|
+
})),
|
|
57
|
+
...tag(page.socialDescription, (content) => ({
|
|
58
|
+
property: "og:description",
|
|
59
|
+
content
|
|
60
|
+
})),
|
|
61
|
+
...tag(page.socialImage, (content) => ({
|
|
62
|
+
property: "og:image",
|
|
63
|
+
content
|
|
64
|
+
})),
|
|
65
|
+
...typeof indexing === "boolean" ? [{
|
|
66
|
+
name: "robots",
|
|
67
|
+
content: indexing ? "index" : "noindex"
|
|
68
|
+
}] : []
|
|
69
|
+
],
|
|
70
|
+
links: ctx.matches.at(-1)?.id === ctx.match.id ? tag(page.canonicalUrl, (href) => ({
|
|
71
|
+
rel: "canonical",
|
|
72
|
+
href
|
|
73
|
+
})) : []
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { definePage, pageHead };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { AccessContext, AccessReason, Narrowed,
|
|
1
|
+
import { AccessContext, AccessReason, Narrowed, VisibilityRule } from "./visibility.js";
|
|
2
|
+
import { Page, PageSettings } from "./page.js";
|
|
2
3
|
|
|
3
4
|
//#region src/visibility/route.d.ts
|
|
4
5
|
|
|
@@ -42,8 +43,11 @@ declare function isUnauthenticatedError(error: unknown): error is AccessError;
|
|
|
42
43
|
declare function isForbiddenError(error: unknown): error is AccessError;
|
|
43
44
|
/** True for an access error thrown because a signed-out-only route saw a user. */
|
|
44
45
|
declare function isAlreadyAuthenticatedError(error: unknown): error is AccessError;
|
|
46
|
+
type GuardedPage = Page<PageSettings & {
|
|
47
|
+
visibility: VisibilityRule;
|
|
48
|
+
}>;
|
|
45
49
|
/**
|
|
46
|
-
* A `beforeLoad` handler that denies a visitor
|
|
50
|
+
* A `beforeLoad` handler that denies a visitor the page's rule does not admit.
|
|
47
51
|
*
|
|
48
52
|
* Each reason falls back to the app's configured behaviour. Pass `overrides` to
|
|
49
53
|
* change what any one reason does. A redirected signed-out visitor carries the
|
|
@@ -52,9 +56,9 @@ declare function isAlreadyAuthenticatedError(error: unknown): error is AccessErr
|
|
|
52
56
|
* Throws a router redirect, so it belongs in `beforeLoad` and nowhere else.
|
|
53
57
|
*
|
|
54
58
|
* @example
|
|
55
|
-
* beforeLoad: guardRoute(
|
|
59
|
+
* beforeLoad: guardRoute(pageSettings, { unauthenticated: "/sign-in" })
|
|
56
60
|
*/
|
|
57
|
-
declare function guardRoute(
|
|
61
|
+
declare function guardRoute(page: GuardedPage, overrides?: GuardOverrides): (opts: {
|
|
58
62
|
context: AccessContext;
|
|
59
63
|
location: {
|
|
60
64
|
href: string;
|
|
@@ -66,7 +70,7 @@ declare function guardRoute(visibility: Visibility, overrides?: GuardOverrides):
|
|
|
66
70
|
*
|
|
67
71
|
* @example
|
|
68
72
|
* beforeLoad: (opts) => {
|
|
69
|
-
* assertRouteAccess(
|
|
73
|
+
* assertRouteAccess(pageSettings, opts)
|
|
70
74
|
* if (opts.params.projectId === "demo") throw redirect({ to: "/projects" })
|
|
71
75
|
* }
|
|
72
76
|
*/
|
|
@@ -75,7 +79,9 @@ declare function assertRouteAccess<R extends VisibilityRule, O extends {
|
|
|
75
79
|
location: {
|
|
76
80
|
href: string;
|
|
77
81
|
};
|
|
78
|
-
}>(
|
|
82
|
+
}>(page: Page<PageSettings & {
|
|
83
|
+
visibility: R;
|
|
84
|
+
}>, opts: O): asserts opts is O & {
|
|
79
85
|
context: Narrowed<R>;
|
|
80
86
|
};
|
|
81
87
|
//#endregion
|
package/dist/visibility/route.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { panic } from "../assertions.js";
|
|
2
|
+
import { ACCESS_REASONS, checkRule } from "./visibility.js";
|
|
2
3
|
import { softrConfig } from "../softr-config.js";
|
|
3
4
|
import { redirect } from "@tanstack/react-router";
|
|
4
5
|
|
|
@@ -52,8 +53,11 @@ function thrownFor(reason, overrides, location) {
|
|
|
52
53
|
reason
|
|
53
54
|
};
|
|
54
55
|
}
|
|
56
|
+
function ruleOf(page) {
|
|
57
|
+
return page.visibility ?? panic("the page states no visibility rule to guard it with");
|
|
58
|
+
}
|
|
55
59
|
/**
|
|
56
|
-
* A `beforeLoad` handler that denies a visitor
|
|
60
|
+
* A `beforeLoad` handler that denies a visitor the page's rule does not admit.
|
|
57
61
|
*
|
|
58
62
|
* Each reason falls back to the app's configured behaviour. Pass `overrides` to
|
|
59
63
|
* change what any one reason does. A redirected signed-out visitor carries the
|
|
@@ -62,11 +66,11 @@ function thrownFor(reason, overrides, location) {
|
|
|
62
66
|
* Throws a router redirect, so it belongs in `beforeLoad` and nowhere else.
|
|
63
67
|
*
|
|
64
68
|
* @example
|
|
65
|
-
* beforeLoad: guardRoute(
|
|
69
|
+
* beforeLoad: guardRoute(pageSettings, { unauthenticated: "/sign-in" })
|
|
66
70
|
*/
|
|
67
|
-
function guardRoute(
|
|
71
|
+
function guardRoute(page, overrides) {
|
|
68
72
|
return ({ context, location }) => {
|
|
69
|
-
const result =
|
|
73
|
+
const result = checkRule(ruleOf(page), context);
|
|
70
74
|
if (result.ok) return;
|
|
71
75
|
throw thrownFor(result.reason, overrides, location);
|
|
72
76
|
};
|
|
@@ -77,12 +81,12 @@ function guardRoute(visibility, overrides) {
|
|
|
77
81
|
*
|
|
78
82
|
* @example
|
|
79
83
|
* beforeLoad: (opts) => {
|
|
80
|
-
* assertRouteAccess(
|
|
84
|
+
* assertRouteAccess(pageSettings, opts)
|
|
81
85
|
* if (opts.params.projectId === "demo") throw redirect({ to: "/projects" })
|
|
82
86
|
* }
|
|
83
87
|
*/
|
|
84
|
-
function assertRouteAccess(
|
|
85
|
-
const result =
|
|
88
|
+
function assertRouteAccess(page, opts) {
|
|
89
|
+
const result = checkRule(ruleOf(page), opts.context);
|
|
86
90
|
if (result.ok) return;
|
|
87
91
|
throw thrownFor(result.reason, void 0, opts.location);
|
|
88
92
|
}
|
|
@@ -48,18 +48,13 @@ type Narrowed<R extends VisibilityRule> = R["userGroupTypes"] extends ReadonlyAr
|
|
|
48
48
|
user: null;
|
|
49
49
|
} : AccessContext : AccessContext;
|
|
50
50
|
/**
|
|
51
|
-
* Declares who may see a
|
|
52
|
-
*
|
|
53
|
-
* At module scope in a route file, with a literal rule: the build reads these
|
|
54
|
-
* declarations out of the source to publish the app's route visibility.
|
|
51
|
+
* Declares who may see a region of the page. A route's own rule is the
|
|
52
|
+
* `visibility` of its `definePage`.
|
|
55
53
|
*
|
|
56
54
|
* @example
|
|
57
|
-
* const
|
|
55
|
+
* const staffOnly = defineVisibility({ userGroupTypes: ["LOGGED_IN_USERS"], customGroups: ["…"] })
|
|
58
56
|
*
|
|
59
|
-
*
|
|
60
|
-
* beforeLoad: guardRoute(visibility),
|
|
61
|
-
* component: About,
|
|
62
|
-
* })
|
|
57
|
+
* <Audience visibility={staffOnly} fallback={null}>…</Audience>
|
|
63
58
|
*/
|
|
64
59
|
declare function defineVisibility<const R extends VisibilityRule>(rule: R): Visibility<R>;
|
|
65
60
|
/**
|
|
@@ -13,8 +13,12 @@ const ACCESS_REASONS = [
|
|
|
13
13
|
];
|
|
14
14
|
/** The decision and, when a visitor is denied, the reason. Throws nothing. */
|
|
15
15
|
function checkAccess(visibility, context) {
|
|
16
|
+
return checkRule(visibility, context);
|
|
17
|
+
}
|
|
18
|
+
/** {@link checkAccess} for a page's rule, which {@link defineVisibility} has not produced. */
|
|
19
|
+
function checkRule(rule, context) {
|
|
16
20
|
const { user } = context;
|
|
17
|
-
const audiences =
|
|
21
|
+
const audiences = rule.userGroupTypes;
|
|
18
22
|
if (user === null) return audiences.includes("NON_LOGGED_IN_USERS") ? { ok: true } : {
|
|
19
23
|
ok: false,
|
|
20
24
|
reason: "unauthenticated"
|
|
@@ -23,7 +27,7 @@ function checkAccess(visibility, context) {
|
|
|
23
27
|
ok: false,
|
|
24
28
|
reason: "alreadyAuthenticated"
|
|
25
29
|
};
|
|
26
|
-
const required =
|
|
30
|
+
const required = rule.customGroups ?? [];
|
|
27
31
|
if (required.length === 0) return { ok: true };
|
|
28
32
|
return required.some((id) => user.userGroupIds.includes(id)) ? { ok: true } : {
|
|
29
33
|
ok: false,
|
|
@@ -31,18 +35,13 @@ function checkAccess(visibility, context) {
|
|
|
31
35
|
};
|
|
32
36
|
}
|
|
33
37
|
/**
|
|
34
|
-
* Declares who may see a
|
|
35
|
-
*
|
|
36
|
-
* At module scope in a route file, with a literal rule: the build reads these
|
|
37
|
-
* declarations out of the source to publish the app's route visibility.
|
|
38
|
+
* Declares who may see a region of the page. A route's own rule is the
|
|
39
|
+
* `visibility` of its `definePage`.
|
|
38
40
|
*
|
|
39
41
|
* @example
|
|
40
|
-
* const
|
|
42
|
+
* const staffOnly = defineVisibility({ userGroupTypes: ["LOGGED_IN_USERS"], customGroups: ["…"] })
|
|
41
43
|
*
|
|
42
|
-
*
|
|
43
|
-
* beforeLoad: guardRoute(visibility),
|
|
44
|
-
* component: About,
|
|
45
|
-
* })
|
|
44
|
+
* <Audience visibility={staffOnly} fallback={null}>…</Audience>
|
|
46
45
|
*/
|
|
47
46
|
function defineVisibility(rule) {
|
|
48
47
|
return rule;
|
|
@@ -56,4 +55,4 @@ function isAuthorized(visibility, context) {
|
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
//#endregion
|
|
59
|
-
export { ACCESS_REASONS, checkAccess, defineVisibility, isAuthorized };
|
|
58
|
+
export { ACCESS_REASONS, checkAccess, checkRule, defineVisibility, isAuthorized };
|