@appsemble/types
Version:
TypeScript definitions reused within Appsemble internally
1,666 lines (1,665 loc) • 73.4 kB
TypeScript
import { type IconName } from '@fortawesome/fontawesome-common-types';
import { type Schema } from 'jsonschema';
import { type OpenAPIV3 } from 'openapi-types';
import { type JsonObject, type RequireExactlyOne } from 'type-fest';
import { type Action, type LogAction } from './action.js';
import { type AppVisibility } from './app.js';
import { type BulmaColor } from './bulma.js';
import { type HTTPMethods } from './http.js';
import { type AppPermission } from './permissions.js';
import { type AppRole, type PredefinedAppRole, type PredefinedOrganizationRole } from './roles.js';
import { type Theme } from './theme.js';
export * from './action.js';
export * from './app.js';
export * from './asset.js';
export * from './authentication.js';
export * from './author.js';
export * from './bulma.js';
export * from './appCollection.js';
export * from './http.js';
export * from './cli.js';
export * from './snapshot.js';
export * from './resource.js';
export * from './saml.js';
export * from './ssl.js';
export * from './template.js';
export * from './theme.js';
export * from './oauth2.js';
export * from './training.js';
export * from './quota.js';
export * from './permissions.js';
export * from './roles.js';
/**
* A representation of a generated OAuth2 authorization code response.
*/
export interface OAuth2AuthorizationCode {
/**
* The authorization code.
*/
code: string;
}
/**
* A project that is loaded in an app
*/
export interface ControllerDefinition {
/**
* A mapping of actions that can be fired by the project to action handlers.
*
* The exact meaning of the parameters depends on the project.
*/
actions?: Record<string, ActionDefinition>;
/**
* Mapping of the events the project can listen to and emit.
*
* The exact meaning of the parameters depends on the project.
*/
events?: {
listen?: Record<string, string>;
emit?: Record<string, string>;
};
}
/**
* A block that is displayed on a page.
*/
export interface BlockDefinition extends ControllerDefinition {
/**
* The type of the controller.
*
* A block type follow the format `@organization/project`.
* If the organization is _appsemble_, it may be omitted.
*
* Pattern:
* ^(@[a-z]([a-z\d-]{0,30}[a-z\d])?\/)?[a-z]([a-z\d-]{0,30}[a-z\d])$
*
* Examples:
* - `empty`
* - `@amsterdam/empty`
*/
type: string;
/**
* A [semver](https://semver.org) representation of the project version.
*
* Pattern:
* ^\d+\.\d+\.\d+$
*/
version: string;
/**
* An optional header to render above the block.
*/
header?: Remapper;
/**
* An override of the block’s default layout.
*/
layout?: 'float' | 'grow' | 'static';
/**
* For floating blocks this property defines where the block should float.
*/
position?: 'bottom left' | 'bottom right' | 'bottom' | 'left' | 'right' | 'top left' | 'top right' | 'top';
/**
* Whether to render the block or not.
*/
hide?: Remapper;
/**
* The theme of the block.
*/
theme?: Partial<Theme>;
/**
* A list of roles that are allowed to view this block.
*/
roles?: ViewRole[];
/**
* A free form mapping of named parameters.
*
* The exact meaning of the parameters depends on the project type.
*/
parameters?: JsonObject;
}
/**
* OpenID Connect specifies a set of standard claims about the end-user, which cover common profile
* information such as name, contact details, date of birth and locale.
*
* The Connect2id server can be set up to provide additional custom claims, such as roles and
* permissions.
*/
export interface BaseUserInfo {
/**
* The subject (end-user) identifier. This member is always present in a claims set.
*/
sub: string;
/**
* The full name of the end-user, with optional language tag.
*/
name: string;
/**
* The end-user's preferred email address.
*/
email: string;
/**
* True if the end-user's email address has been verified, else false.
*/
email_verified: boolean;
/**
* The URL of the profile picture for the end-user.
*/
picture?: string;
/**
* The end-user’s locale, represented as a BCP47 language tag.
*/
locale?: string;
/**
* The end-user’s time zone.
*/
zoneinfo?: string;
}
export interface UserInfo extends BaseUserInfo {
/**
* If the user is subscribed to the newsletter
*/
subscribed?: boolean;
hasPassword?: boolean;
}
export interface AppMemberInfo extends BaseUserInfo {
/**
* The role of the app member.
*/
role: AppRole;
/**
* The end-user's additional properties
*/
properties?: Record<string, any>;
/**
* Whether this app member is used for demonstration purposes
*/
demo: boolean;
}
export interface SSOConfiguration {
type: 'oauth2' | 'saml';
url: string;
icon: IconName;
name: string;
}
export interface AppAccount {
app: App;
appMemberInfo: AppMemberInfo;
sso: SSOConfiguration[];
}
export interface EmailAuthorization {
email: string;
verified: boolean;
}
/**
* The payload stored in our JSON web tokens
*/
export interface JwtPayload {
aud: string;
exp: number;
iat: string;
iss: string;
scope: string;
sub: string;
}
/**
* A response for a login token request
*/
export interface TokenResponse {
/**
* The bearer access token to use for authenticating requests.
*/
access_token: string;
/**
* How long until the access token expires in seconds from now.
*/
expires_in?: number;
/**
* The OpenID ID token as a JWT.
*
* This field is only present on OpenID connect providers.
*/
id_token?: string;
/**
* A refresh token for getting a new access token.
*/
refresh_token?: string;
token_type: 'bearer';
}
/**
* A type to represent the app lock.
*/
export type AppLock = 'fullLock' | 'studioLock' | 'unlocked';
interface BaseICSRemapper {
/**
* The start of the icalendar event.
*/
start: Remapper;
/**
* The title of the event.
*/
title: Remapper;
/**
* An optional description of the event.
*/
description?: Remapper;
/**
* An optional link to attach to the event.
*/
url?: Remapper;
/**
* An optional location description to attach to the event.
*/
location?: Remapper;
/**
* An optional geolocation description to attach to the event.
*
* This must be an object with the properties `lat` or `latitude`, and `lon`, `lng` or
* `longitude`.
*/
coordinates?: Remapper;
}
interface DurationICSRemapper extends BaseICSRemapper {
/**
* The duration of the event.
*
* @example '1w 3d 10h 30m'
*/
duration: Remapper;
}
interface EndTimeICSRemapper extends BaseICSRemapper {
/**
* The end time of the event as a date or a date string.
*/
end: Remapper;
}
export interface SubstringCaseType {
/**
* Whether to match the case of the substring.
*/
strict?: boolean;
/**
* Substring to match.
*/
substring: string;
}
type FilterParams = Record<string, {
type: 'Boolean' | 'Date' | 'Guid' | 'Number' | 'String';
value: Remapper;
comparator: 'eq' | 'ge' | 'gt' | 'le' | 'lt' | 'ne';
}>;
type OrderParams = Record<string, 'asc' | 'desc'>;
export interface Remappers {
/**
* Get app metadata.
*
* Supported properties:
*
* - `id`: Get the app id.
* - `locale`: Get the current locale of the app.
* - `url`: Get the base URL of the app.
*/
app: 'id' | 'locale' | 'url';
/**
* Get property of the AppMember object.
*
* Supported properties:
*
* - `sub`: Get the id of the app member.
* - `name`: Get the name of the app member.
* - `email`: Get the email of the app member.
* - `email_verified`: Whether the email of the app member is verified.
* - `picture`: Get the picture of the app member.
* - `locale`: Get the locale of the app member.
* - `zoneinfo`: Get the zoneinfo of the app member.
* - `role`: Get the role of the app member.
* - `properties`: Get the custom properties of the app member.
*/
'app.member': keyof AppMemberInfo;
/**
* Get a predefined app variable by name.
*/
variable: string;
/**
* Get page metadata.
*
* Supported properties:
*
* - `data`: Get the current page data.
* - `url`: Get the URL of the current page.
*/
page: 'data' | 'url';
/**
* Get a property from the context.
*/
context: string;
/**
* Get the title of current page.
*/
'tab.name': string;
/**
* Convert a string to a number.
*/
'number.parse': Remapper;
/**
* Convert a string to a date using a given format.
*/
'date.parse': string;
/**
* Returns the current date.
*/
'date.now': unknown;
/**
* Adds to a date.
*/
'date.add': string;
/**
* Formats a date to an iso8601 / rfc3339 compatible string.
*
* An argument can also be specified to use a different output format.
*
* Please refer to https://date-fns.org/docs/format for the supported patterns.
*/
'date.format'?: string;
/**
* Compare all computed remapper values against each other.
*
* Returns `true` if all entries are equal, otherwise `false`.
*/
equals: Remapper[];
/**
* Compare all computed remapper values against the first.
*
* Returns `false` if all entries are equal to the first entry, otherwise `true`.
*
* If only one remapper or none is passed, the remapper value gets computed and then inverted.
*/
not: Remapper[];
/**
* Compare all computed remapper values against each other.
*
* Returns `true` if all entries are true, otherwise `false`.
*
* If only one remapper is passed, the remapper is returned.
*/
and: Remapper[];
/**
* Compare all computed remapper values against each other.
*
* Returns `false` if all entries are false, otherwise `true`.
*
* If only one remapper is passed, the remapper is returned.
*/
or: Remapper[];
/**
* Get data stored at the current flow page step
*/
step: string;
/**
* Compares the first computed remapper value with the second computed remapper value.
*
* Returns `true` of the first entry is greater than the second entry.
*/
gt: [Remapper, Remapper];
/**
* Compares the first computed remapper value with the second computed remapper value.
*
* Returns `true` of the first entry is less than the second entry.
*/
lt: [Remapper, Remapper];
/**
* Logs its input data (returns it) and its context.
*
* The value to set is the log level.
*/
log: 'error' | 'info' | 'warn';
/**
* Get input object type.
*/
type: null;
/**
* Builds an array based on the given data and remappers.
*
* The remappers gets applied to each item in the array.
*
* Always returns an array, can be empty if supplied data isn’t an array.
*/
'array.map': Remapper;
/**
* Filters out unique entries from an array.
*
* The value Remapper is applied to each entry in the array,
* using its result to determine uniqueness.
*
* If the value Remapper result in `undefined` or `null`, the entire entry is used for uniqueness.
*
* If the input is not an array, the input is returned without any modifications.
*/
'array.unique': Remapper;
/**
* Flattens an array.
*
* The value of the remapper is used for the flattening depth.
*
* If the value Remapper result in `undefined` or `null`, the array will be flattened until
* the last layer.
*
* If the input is not an array, the input is returned without any modifications.
*/
'array.flatten': Remapper;
/**
* Create an icalendar event.
*/
ics: DurationICSRemapper | EndTimeICSRemapper;
/**
* Checks if condition results in a truthy value.
*
* Returns value of then if condition is truthy, otherwise it returns the value of else.
*/
if: {
condition: Remapper;
then: Remapper;
else: Remapper;
};
/**
* Check if any case results in a truthy value.
*
* Returns the value of the first case where the condition equals true, otherwise returns null.
*/
match: {
case: Remapper;
value: Remapper;
}[];
/**
* Get the current array.map’s index or length.
*
* Returns nothing if array.map’s context isn’t set.
*/
array: 'index' | 'item' | 'length' | 'nextItem' | 'prevItem';
/**
*
* Returns an array containing the items matching the specified conditions.
*/
'array.filter': Remapper;
/**
* Returns an object based on the specified condition
*/
'array.find': Remapper;
/**
* Create a new array with an array of predefined remappers.
*/
'array.from': Remapper[];
/**
* Append new values to the end of an array.
*
* If the input is not an array an empty array is returned.
*/
'array.append': Remapper[];
/**
* Remove item(s) from an array given a predefined array of remappable indices.
*
* Only the remapped values that are turned into numbers are applied.
*
* If the input is not an array an empty array is returned.
*/
'array.omit': Remapper[];
/**
* Create a new object given some predefined mapper keys.
*/
'object.from': Record<string, Remapper>;
/**
* Assign properties to an existing object given some predefined mapper keys.
*/
'object.assign': Record<string, Remapper>;
/**
* Remove properties from an existing object based on the given the object keys.
*
* Nested properties can be removed using arrays of keys.
*
* @example
* ```yaml
* object.omit:
* - foo # Removes the property foo
* - - bar # Removes the property baz inside of bar
* - baz
* ```
*/
'object.omit': (string[] | string)[];
/**
* Compare two objects to each other and get an array of differences
*
* Nested object keys are returned as a path array.
*
* @example
* ```yaml
* object.compare:
* - object.from:
* name: Alice
* age: 25
* address:
* object.from:
* city: Paris
* zip: 7500
* - object.from:
* name: Alice
* age: 26
* address:
* object.from:
* city: Lyon
* country: France
* ```
*
* Returns:
* ```javascript
* [
* { path: ['age'], type: 'changed', from: 25, to: 26 },
* { path: ['address', 'city'], type: 'changed', from: 'Paris', to: 'Lyon' },
* { path: ['address', 'zip'], type: 'removed', value: 7500 },
* { path: ['address', 'country'], type: 'added', value: 'France' }
* ]
* ```
*/
'object.compare': [Remapper, Remapper];
/**
* Takes an object with an array property and transforms it into an array of objects.
*
* Each object in the resulting array contains all the entries of the original object
* plus all the entries of the corresponding array item from the array property.
*
* > **Note**
* > If one of the items in the array contains a key, which exists in the original object
* > it will overwrite the original key
*
* > **Note**
* > Nested arrays or objects are not exploded
*
* @example
* Input:
* ```javascript
* {
* ownerName: 'John',
* country: 'USA',
* pets: [
* { name: 'Milka' },
* { name: 'Sven', country: 'Sweden' },
* { name: 'Tom', likes: ['mice', 'fish'] },
* { name: 'Jerry', looks: { color: 'brown' } }
* ]
* }
* ```
*
* Remapper:
* ```yaml
* object.explode: pets
* ```
*
* Returns:
* ```javascript
* [
* { ownerName: 'John', name: 'Milka', country: 'USA' },
* { ownerName: 'John', name: 'Sven', country: 'Sweden' },
* { ownerName: 'John', name: 'Tom', country: 'USA', likes: ['mice', 'fish'] },
* { ownerName: 'John', name: 'Jerry', country: 'USA', looks: { color: 'brown' } }
* ]
* ```
*/
'object.explode': string;
/**
* Use a static value.
*/
static: any;
/**
* Get a property from an object.
*
* If the prop is an array, nested properties will be retrieved in sequence.
*/
prop: number[] | Remapper | string[];
/**
* Recursively strip all nullish values from an object or array.
*/
'null.strip': {
depth: number;
} | null;
/**
* Pick and return a random entry from an array.
*
* If the input is not an array, the input is returned as-is.
*/
'random.choice': null;
/**
* Pick and return a random entry from an array.
*
* If the input is not an array, the input is returned as-is.
*/
'random.integer': [number, number];
/**
* Pick and return a random entry from an array.
*
* If the input is not an array, the input is returned as-is.
*/
'random.float': [number, number];
/**
* Pick and return a random entry from an array.
*
* If the input is not an array, the input is returned as-is.
*/
'random.string': {
choice: string;
length: number;
};
/**
* This remapper returns the length of the input array or a string, this remapper
* doesn't require array to be in the context unlike `{ array: length }` remapper.
*/
len: null;
/**
* Get the input data as it was initially passed to the remap function.
*/
root: null;
/**
* Get the data at a certain index from the history stack prior to an action.
*
* 0 is the index of the first item in the history stack.
*/
history: number;
/**
* Create a new object with properties from the history stack at a certain index.
*/
'from.history': {
/**
* The index of the history stack item to apply.
*
* 0 is the index of the first item in the history stack.
*/
index: number;
/**
* Predefined mapper keys to choose what properties to apply.
*/
props: Record<string, Remapper>;
};
/**
* Assign properties from the history stack at a certain index to an existing object.
*/
'assign.history': {
/**
* The index of the history stack item to assign.
*
* 0 is the index of the first item in the history stack.
*/
index: number;
/**
* Predefined mapper keys to choose what properties to assign.
*/
props: Record<string, Remapper>;
};
/**
* Assign properties from the history stack at a certain index and exclude the unwanted.
*/
'omit.history': {
/**
* The index of the history stack item to assign.
*
* 0 is the index of the first item in the history stack.
*/
index: number;
/**
* Exclude properties from the history stack item, based on the given object keys.
*
* Nested properties can be excluded using arrays of keys.
*
* @example
* ```yaml
* omit.history:
* index: 0
* keys:
* - foo # Excludes the property foo
* - - bar # Excludes the property baz inside of bar
* - baz
* ```
*/
keys: (string[] | string)[];
};
/**
* Convert an input to lower or upper case.
*/
'string.case': 'lower' | 'upper';
/**
* Check if the initial characters of the string matches with the input string.
*/
'string.startsWith': SubstringCaseType | string;
/**
* Check if the last characters of the string matches with the input string.
*/
'string.endsWith': SubstringCaseType | string;
/**
* Extract a section of the string or an array.
*/
slice: number | [number, number];
/**
* Format a string using remapped input variables.
*/
'string.format': {
/**
* The message id pointing to the template string to format.
*/
messageId?: Remapper;
/**
* The template default string to format.
*/
template?: string;
/**
* A set of remappers to convert the input to usable values.
*/
values?: Record<string, Remapper>;
};
/**
* Match the content with the regex in the key, and replace it with its value.
*/
'string.replace': Record<string, string>;
/**
* Translate using a messageID.
*
* This does not support parameters, for more nuanced translations use `string.format`.
*/
translate: string;
container: string;
/**
* Construct an OData $filter
*/
'filter.from': FilterParams;
/**
* Construct an OData $orderby
*/
'order.from': OrderParams;
/**
* Parse an xml string to a JavaScript object
*/
'xml.parse': Remapper;
/**
* Check if the value is defined
*
* @example
* "" -> true
* 0 -> true
* null -> false
* undefined -> false
*/
defined: Remapper;
/**
* Perform the specified mathematical operation on the two numbers.
*
* Where the position matters, `a` is the first input.
*
* If one of the inputs is not a number, or the operation is invalid, `-1` is returned.
*/
maths: {
a: Remapper;
b: Remapper;
operation: 'add' | 'divide' | 'mod' | 'multiply' | 'subtract';
};
}
export type ObjectRemapper = RequireExactlyOne<Remappers>;
export type ArrayRemapper = (ArrayRemapper | ObjectRemapper)[];
export type Remapper = ArrayRemapper | ObjectRemapper | boolean | number | string | null;
export interface SubscriptionResponseResource {
create: boolean;
update: boolean;
delete: boolean;
subscriptions?: Record<string, {
create?: boolean;
update: boolean;
delete: boolean;
}>;
}
export type SubscriptionResponse = Record<string, SubscriptionResponseResource>;
export declare const resourceSubscribableAction: readonly ["create", "update", "delete"];
export type ResourceSubscribableAction = (typeof resourceSubscribableAction)[number];
export type ResourceViewAction = 'get' | 'query';
export type OwnResourceAction = ResourceViewAction | 'delete' | 'patch' | 'update';
export type ResourceAction = ResourceViewAction | 'create' | 'delete' | 'history.get' | 'patch' | 'update.positions' | 'update';
export type CustomAppResourcePermission = `$resource:${string}:${ResourceAction}`;
export type CustomAppOwnResourcePermission = `$resource:${string}:own:${OwnResourceAction}`;
export type CustomAppResourceViewPermission = `$resource:${string}:${ResourceViewAction}:${string}`;
export type CustomAppGuestPermission = AppPermission | CustomAppResourcePermission | CustomAppResourceViewPermission;
export type CustomAppPermission = CustomAppGuestPermission | CustomAppOwnResourcePermission;
export interface GuestDefinition {
permissions?: CustomAppPermission[];
inherits?: AppRole[];
}
export interface CronSecurityDefinition {
permissions?: CustomAppPermission[];
inherits?: AppRole[];
}
export interface RoleDefinition {
description?: string;
defaultPage?: string;
inherits?: AppRole[];
permissions?: CustomAppPermission[];
}
export type SecurityPolicy = 'everyone' | 'invite' | 'organization';
export interface MinimalSecurity {
guest: GuestDefinition;
cron?: CronSecurityDefinition;
default?: {
role: AppRole;
policy?: SecurityPolicy;
};
roles?: Record<Exclude<string, PredefinedAppRole>, RoleDefinition>;
}
export interface StrictSecurity {
guest?: GuestDefinition;
cron?: CronSecurityDefinition;
default: {
role: AppRole;
policy?: SecurityPolicy;
};
roles: Record<string, RoleDefinition>;
}
export type Security = MinimalSecurity | StrictSecurity;
export type Navigation = 'bottom' | 'hidden' | 'left-menu';
export type LayoutPosition = 'hidden' | 'navbar' | 'navigation';
export interface NotificationDefinition {
to?: string[];
subscribe?: 'all' | 'both' | 'single';
data?: {
title: string;
content: string;
link: string;
};
}
/**
* A collection of hooks that are triggered upon calling a resource actions.
*/
export interface ResourceHooks {
notification: NotificationDefinition;
}
export interface ResourceCall {
/**
* The HTTP method to use for making the HTTP request.
*/
method?: HTTPMethods;
/**
* The URL to which to make the resource request.
*/
url?: string;
/**
* The associated hooks with the resource action.
*/
hooks?: ResourceHooks;
/**
* Query parameters to pass along with the request.
*/
query?: Remapper;
}
export interface ResourceReferenceActionTrigger {
type: 'create' | 'delete' | 'update';
cascade?: 'delete' | 'update';
}
interface ResourceReferenceAction {
triggers: ResourceReferenceActionTrigger[];
}
export interface ResourceReference {
/**
* The name of the referenced resource.
*/
resource: string;
create?: ResourceReferenceAction;
update?: ResourceReferenceAction;
delete?: ResourceReferenceAction;
}
export interface ResourceHistoryDefinition {
/**
* If set to `false`, edits are still tracked, but exactly what changed is lost.
*/
data: boolean;
}
export interface ResourceView {
/**
* The remappers used to transform the output.
*/
remap: Remapper;
}
export interface AppMemberPropertyDefinition {
/**
* The JSON schema to validate user properties against before sending it to the backend.
*/
schema: OpenAPIV3.SchemaObject;
/**
* The resource that is referenced by this user property.
*/
reference?: {
resource: string;
};
}
export interface ResourceDefinition {
/**
* A definition of how versioning should happen for instances of this resource.
*/
history?: ResourceHistoryDefinition | boolean;
/**
* Whether to enable position column for the instances of this resource. This is used for keeping
* an ordered list to enable custom sorting of the data using drag and drop features.
*/
positioning?: boolean;
/**
* Enforce Custom Ordering By the fields.
*/
enforceOrderingGroupByFields?: string[];
/**
* The definition for the `resource.create` action.
*/
create?: ResourceCall;
/**
* The definition for the `resource.delete` action.
*/
delete?: ResourceCall;
/**
* The definition for the `resource.get` action.
*/
get?: ResourceCall;
/**
* The definition for the `resource.query` action.
*/
query?: ResourceCall;
/**
* The definition for the `resource.count` action.
*/
count?: ResourceCall;
/**
* The definition for the `resource.update` action.
*/
update?: ResourceCall;
/**
* The definition for the `resource.patch` action.
*/
patch?: ResourceCall;
/**
* The property to use as the id.
*
* @default `id`
*/
id?: string;
/**
* The JSON schema to validate resources against before sending it to the backend.
*/
schema: OpenAPIV3.SchemaObject;
/**
* The URL to post the resource to.
*
* @default autogenerated for use with the Appsemble resource API.
*/
url?: string;
/**
* The alternate views of this resource.
*/
views?: Record<string, ResourceView>;
/**
* The references this resources has to other resources.
*/
references?: Record<string, ResourceReference>;
/**
* A time string representing when a resource should expire.
*
* @example '1d 8h 30m'
*/
expires?: string;
/**
* Whether the resource should be able to be transferred when cloning the app it belongs to.
*/
clonable?: boolean;
}
export interface BaseActionDefinition<T extends Action['type']> {
/**
* The type of the action.
*/
type: T;
/**
* A remapper function. This may be used to remap data before it is passed into the action
* function.
*
* @deprecated Since 0.20.10, use {@link remapBefore} instead.
*/
remap?: Remapper;
/**
* A remapper function. This may be used to remap data before it is passed into the action
* function.
*/
remapBefore?: Remapper;
/**
* The remapper used to transform the output before passing it to the next action.
*/
remapAfter?: Remapper;
/**
* Another action that is dispatched when the action has been dispatched successfully.
*/
onSuccess?: ActionDefinition;
/**
* Another action that is dispatched when the action has failed to dispatch successfully.
*/
onError?: ActionDefinition;
}
export interface AnalyticsAction extends BaseActionDefinition<'analytics'> {
/**
* The analytics event target name.
*/
target: string;
/**
* Additional config to pass to analytics.
*/
config?: Remapper;
}
export interface ConditionActionDefinition extends BaseActionDefinition<'condition'> {
/**
* The condition to check for.
*/
if: Remapper;
/**
* The action to run if the condition is true.
*/
then: ActionDefinition;
/**
* The action to run if the condition is false.
*/
else: ActionDefinition;
}
export interface MatchActionDefinition extends BaseActionDefinition<'match'> {
/**
* Run another action if one of the cases is true.
*
* Only the first case that equals true is called.
*/
match: {
/**
* The case to be matched.
*/
case: Remapper;
/**
* Action to be called if the case equals true.
*/
action: ActionDefinition;
}[];
}
export interface DialogActionDefinition extends BaseActionDefinition<'dialog'> {
/**
* If false, the dialog cannot be closed by clicking outside of the dialog or on the close button.
*/
closable?: boolean;
/**
* If true, the dialog will be displayed full screen.
*/
fullscreen?: boolean;
/**
* Blocks to render on the dialog.
*/
blocks: BlockDefinition[];
/**
* The title to show in the dialog.
*/
title?: Remapper;
}
export interface DownloadActionDefinition extends BaseActionDefinition<'download'> {
/**
* The filename to download the file as. It must include a file extension.
*/
filename: string;
}
export interface EachActionDefinition extends BaseActionDefinition<'each'> {
/**
* Run the actions in series instead of parallel.
*/
serial?: boolean;
/**
* Run an action for each entry in an array.
*
* The actions are run in parallel.
*
* If the input is not an array, the action will be applied to the input instead.
*/
do: ActionDefinition;
}
export interface EmailActionDefinition extends BaseActionDefinition<'email'> {
/**
* The recipient of the email.
*/
to?: Remapper;
/**
* The name of the sender.
*
* The default value depends on the email server.
*/
from?: Remapper;
/**
* The recipients to CC the email to.
*/
cc?: Remapper;
/**
* The recipients to BCC the email to.
*/
bcc?: Remapper;
/**
* The subject of the email.
*/
subject: Remapper;
/**
* The body of the email.
*/
body: Remapper;
/**
* The attachments to include in the email.
*
* The remapper must resolve to an object containing the following properties:
*
* - \`target\`: The asset ID or link to download contents from to add as an attachment. This is
* mutually exclusive with \`content\`.
* - \`content\`: The raw content to include as the file content. This is mutually exclusive with
* \`target\`.
* - \`filename\`: The filename to include the attachment as.
* - \`accept\` If the target is a URL, this will be set as the HTTP \`Accept\` header when
* downloading the file.
*
* If the attachment is a string, it will be treated as the target.
*/
attachments?: Remapper;
}
export interface FlowToActionDefinition extends BaseActionDefinition<'flow.to'> {
/**
* The flow step to go to.
*/
step: Remapper;
}
export interface LinkActionDefinition extends BaseActionDefinition<'link'> {
/**
* Where to link to.
*
* This should be a page name.
*/
to: Remapper | string[] | string;
}
export interface NotifyActionDefinition extends BaseActionDefinition<'notify'> {
/**
* The title of the notification.
*/
title: Remapper;
/**
* The description of the notification.
*/
body: Remapper;
/**
* To whom the notification should be sent.
*
* Use `all` to send the notification to all app subscribed users.
* Or notify specific users by passing either a single user id or an array of user ids.
*
* Nothing is sent if the value is **not** a valid user id.
*/
to: Remapper;
}
export interface LogActionDefinition extends BaseActionDefinition<'log'> {
/**
* The logging level on which to log.
*
* @default `info`.
*/
level?: LogAction['level'];
}
export interface ShareActionDefinition extends BaseActionDefinition<'share'> {
/**
* The URL that is being shared.
*/
url?: Remapper;
/**
* The main body that is being shared.
*/
text?: Remapper;
/**
* The title that is being shared, if supported.
*/
title?: Remapper;
}
export type StorageType = 'appStorage' | 'indexedDB' | 'localStorage' | 'sessionStorage';
export interface StorageAppendActionDefinition extends BaseActionDefinition<'storage.append'> {
/**
* The key of the entry to write to the app’s storage.
*/
key: Remapper;
/**
* The data to write to the app’s storage.
*/
value: Remapper;
/**
* The mechanism used to read the data from.
*
* @default 'indexedDB'
*/
storage?: StorageType;
}
export interface StorageDeleteActionDefinition extends BaseActionDefinition<'storage.delete'> {
/**
* The key of the entry to delete from the app’s storage.
*/
key: Remapper;
/**
* The mechanism used to delete the data from.
*
* @default 'indexedDB'
*/
storage?: StorageType;
}
export interface StorageSubtractActionDefinition extends BaseActionDefinition<'storage.subtract'> {
/**
* The key of the entry to subtract the last entry from
*/
key: Remapper;
/**
* The mechanism used to read the data from.
*
* @default 'indexedDB'
*/
storage?: StorageType;
}
export interface StorageUpdateActionDefinition extends BaseActionDefinition<'storage.update'> {
/**
* The key of the entry to write to the app’s storage.
*/
key: Remapper;
/**
* The key of the item to update.
*/
item: Remapper;
/**
* The data to update the specified item with.
*/
value: Remapper;
/**
* The mechanism used to read the data from.
*
* @default 'indexedDB'
*/
storage?: StorageType;
}
export interface StorageReadActionDefinition extends BaseActionDefinition<'storage.read'> {
/**
* The key of the entry to read from the app’s storage.
*/
key: Remapper;
/**
* The mechanism used to read the data from.
*
* @default 'indexedDB'
*/
storage?: StorageType;
}
export interface StorageWriteActionDefinition extends BaseActionDefinition<'storage.write'> {
/**
* The key of the entry to write to the app’s storage.
*/
key: Remapper;
/**
* The data to write to the app’s storage.
*/
value: Remapper;
/**
* The mechanism used to read the data from.
*
* @default 'indexedDB'
*/
storage?: StorageType;
/**
* Expiry of the data stored, to be used with `localStorage`.
*/
expiry?: '1d' | '3d' | '7d' | '12h';
}
export interface GroupMemberInviteActionDefinition extends BaseActionDefinition<'group.member.invite'> {
/**
* The ID of the group to invite the user to.
*/
id: Remapper;
/**
* The email address of the user to invite.
*/
email: Remapper;
/**
* The role of the invited group member.
*/
role: Remapper;
}
export interface GroupMemberQueryActionDefinition extends BaseActionDefinition<'group.member.query'> {
/**
* The ID of the group to query the members of.
*/
id: Remapper;
}
export interface GroupMemberDeleteActionDefinition extends BaseActionDefinition<'group.member.delete'> {
/**
* The ID of the group member to delete.
*/
id: Remapper;
}
export interface GroupMemberRoleUpdateActionDefinition extends BaseActionDefinition<'group.member.role.update'> {
/**
* The ID of the group member to update the role of.
*/
id: Remapper;
/**
* The role to invite the app member with.
*/
role: Remapper;
}
export interface AppMemberLoginAction extends BaseActionDefinition<'app.member.login'> {
/**
* The email address to log in with.
*/
email: Remapper;
/**
* The password to log in with.
*/
password: Remapper;
}
export interface AppMemberRegisterAction extends BaseActionDefinition<'app.member.register'> {
/**
* The email address to register with.
*/
email: Remapper;
/**
* The password to login with.
*/
password: Remapper;
/**
* The full name of the app member.
*/
name: Remapper;
/**
* The profile picture to use.
*
* This must be a file, otherwise it’s discarded.
*/
picture?: Remapper;
/**
* Custom properties that can be assigned freely.
*
* Every value will be converted to a string.
*/
properties?: Remapper;
/**
* Whether to login after registering.
*
* @default true
*/
login?: boolean;
}
export interface AppMemberInviteAction extends BaseActionDefinition<'app.member.invite'> {
/**
* The email address to invite the app member with.
*/
email: Remapper;
/**
* The role to invite the app member with.
*/
role: Remapper;
}
export interface AppMemberQueryAction extends BaseActionDefinition<'app.member.query'> {
/**
* The roles of the users to fetch.
*/
roles?: Remapper;
}
export interface AppMemberRoleUpdateAction extends BaseActionDefinition<'app.member.role.update'> {
/**
* The id of the app member to update.
*/
sub: Remapper;
/**
* The role of the updated app member
*/
role: Remapper;
}
export interface AppMemberPropertiesPatchAction extends BaseActionDefinition<'app.member.properties.patch'> {
/**
* The id of the app member to update.
*/
sub: Remapper;
/**
* Custom properties that can be assigned freely.
*
* Every value will be converted to a string.
*/
properties: Remapper;
}
export interface AppMemberCurrentPatchAction extends BaseActionDefinition<'app.member.current.patch'> {
/**
* The display name to update.
*/
name?: Remapper;
/**
* Custom properties that can be assigned freely.
*
* Every value will be converted to a string.
*/
properties?: Remapper;
/**
* The profile picture to use.
*
* This must be a file, otherwise it’s discarded.
*/
picture?: Remapper;
}
export interface AppMemberDeleteAction extends BaseActionDefinition<'app.member.delete'> {
/**
* The id of the app member to remove.
*/
sub: Remapper;
}
interface RequestActionHeaders {
'Content-Type': 'application/x-www-form-urlencoded' | 'application/xml' | 'multipart/form-data' | 'text/plain';
}
export interface RequestLikeActionDefinition<T extends Action['type'] = Action['type']> extends BaseActionDefinition<T> {
/**
* The HTTP method to use for making a request.
*/
method?: HTTPMethods;
/**
* Whether or not to proxy the request through the Appsemble proxy endpoint.
*
* @default true
*/
proxy?: boolean;
/**
* A JSON schema against which to validate data before uploading.
*/
schema?: OpenAPIV3.SchemaObject;
/**
* Query parameters to pass along with the request.
*/
query?: Remapper;
/**
* The URL to which to make the request.
*/
url?: Remapper;
/**
* A remapper for the request body.
*
* If this isn’t specified, the raw input data is used.
*/
body?: Remapper;
/**
* Headers for the outgoing request.
*/
headers?: RequestActionHeaders;
}
export interface ResourceActionDefinition<T extends Action['type']> extends RequestLikeActionDefinition<T> {
/**
* The name of the resource.
*/
resource: string;
}
interface ViewResourceDefinition {
/**
* The view to use for the request.
*/
view?: string;
}
interface OwnResourceDefinition {
/**
* If only the resources created by the authenticated app member should be included
*/
own?: boolean;
}
interface ResourceActionWithIdDefinition {
/**
* Id of the resource to fetch
*/
id?: Remapper;
}
export interface ControllerActionDefinition extends BaseActionDefinition<'controller'> {
handler: string;
}
export type RequestActionDefinition = RequestLikeActionDefinition<'request'>;
export type ResourceCreateActionDefinition = ResourceActionDefinition<'resource.create'>;
export type ResourceDeleteActionDefinition = ResourceActionDefinition<'resource.delete'>;
export type ResourceDeleteAllActionDefinition = ResourceActionDefinition<'resource.delete.all'>;
export type ResourceDeleteBulkActionDefinition = ResourceActionDefinition<'resource.delete.bulk'>;
export type ResourceHistoryGetActionDefinition = ResourceActionDefinition<'resource.history.get'>;
export type ResourceGetActionDefinition = ResourceActionDefinition<'resource.get'> & ResourceActionWithIdDefinition & ViewResourceDefinition;
export type ResourceQueryActionDefinition = OwnResourceDefinition & ResourceActionDefinition<'resource.query'> & ViewResourceDefinition;
export type ResourceCountActionDefinition = OwnResourceDefinition & ResourceActionDefinition<'resource.count'>;
export type ResourceUpdateActionDefinition = ResourceActionDefinition<'resource.update'>;
export type ResourceUpdatePositionsActionDefinition = ResourceActionDefinition<'resource.update.positions'> & ResourceActionWithIdDefinition;
export type ResourcePatchActionDefinition = ResourceActionDefinition<'resource.patch'> & ResourceActionWithIdDefinition;
export type AppMemberLogoutAction = BaseActionDefinition<'app.member.logout'>;
export interface BaseResourceSubscribeActionDefinition<T extends Action['type']> extends BaseActionDefinition<T> {
/**
* The name of the resource.
*/
resource: string;
/**
* The action to subscribe to. Defaults to `update` if not specified.
*/
action?: 'create' | 'delete' | 'update';
}
export type ResourceSubscriptionSubscribeActionDefinition = BaseResourceSubscribeActionDefinition<'resource.subscription.subscribe'>;
export type ResourceSubscriptionUnsubscribeActionDefinition = BaseResourceSubscribeActionDefinition<'resource.subscription.unsubscribe'>;
export type ResourceSubscriptionToggleActionDefinition = BaseResourceSubscribeActionDefinition<'resource.subscription.toggle'>;
export type ResourceSubscriptionStatusActionDefinition = Omit<BaseResourceSubscribeActionDefinition<'resource.subscription.status'>, 'action'>;
export interface EventActionDefinition extends BaseActionDefinition<'event'> {
/**
* The name of the event to emit to.
*/
event: string;
/**
* An event to wait for before resolving.
*
* If this is unspecified, the action will resolve with the input data.
*/
waitFor?: string;
}
export interface StaticActionDefinition extends BaseActionDefinition<'static'> {
/**
* The value to return.
*/
value: any;
}
export interface BaseMessage {
/**
* The color to use for the message.
*
* @default 'info'
*/
color?: BulmaColor;
/**
* The timeout period for this message (in milliseconds).
*
* @default 5000
*/
timeout?: number;
/**
* Whether or not to show the dismiss button.
*
* @default false
*/
dismissable?: boolean;
/**
* The position of the message on the screen.
*
* @default 'bottom'
*/
layout?: 'bottom' | 'top';
}
export type MessageActionDefinition = BaseActionDefinition<'message'> & BaseMessage & {
/**
* The content of the message to display.
*/
body: Remapper;
};
export type ActionDefinition = AnalyticsAction | AppMemberCurrentPatchAction | AppMemberDeleteAction | AppMemberInviteAction | AppMemberLoginAction | AppMemberLogoutAction | AppMemberPropertiesPatchAction | AppMemberQueryAction | AppMemberRegisterAction | AppMemberRoleUpdateAction | BaseActionDefinition<'dialog.error'> | BaseActionDefinition<'dialog.ok'> | BaseActionDefinition<'flow.back'> | BaseActionDefinition<'flow.cancel'> | BaseActionDefinition<'flow.finish'> | BaseActionDefinition<'flow.next'> | BaseActionDefinition<'group.query'> | BaseActionDefinition<'link.back'> | BaseActionDefinition<'link.next'> | BaseActionDefinition<'noop'> | BaseActionDefinition<'throw'> | ConditionActionDefinition | ControllerActionDefinition | DialogActionDefinition | DownloadActionDefinition | EachActionDefinition | EmailActionDefinition | EventActionDefinition | FlowToActionDefinition | GroupMemberDeleteActionDefinition | GroupMemberInviteActionDefinition | GroupMemberQueryActionDefinition | GroupMemberRoleUpdateActionDefinition | LinkActionDefinition | LogActionDefinition | MatchActionDefinition | MessageActionDefinition | NotifyActionDefinition | RequestActionDefinition | ResourceCountActionDefinition | ResourceCreateActionDefinition | ResourceDeleteActionDefinition | ResourceDeleteAllActionDefinition | ResourceDeleteBulkActionDefinition | ResourceGetActionDefinition | ResourceHistoryGetActionDefinition | ResourcePatchActionDefinition | ResourceQueryActionDefinition | ResourceSubscriptionStatusActionDefinition | ResourceSubscriptionSubscribeActionDefinition | ResourceSubscriptionToggleActionDefinition | ResourceSubscriptionUnsubscribeActionDefinition | ResourceUpdateActionDefinition | ResourceUpdatePositionsActionDefinition | ShareActionDefinition | StaticActionDefinition | StorageAppendActionDefinition | StorageDeleteActionDefinition | StorageReadActionDefinition | StorageSubtractActionDefinition | StorageUpdateActionDefinition | StorageWriteActionDefinition;
export interface ActionType {
/**
* Whether or not app creators are required to define this action.
*/
required?: boolean;
/**
* The description of the action.
*/
description?: string;
}
export interface EventType {
/**
* The description of the action.
*/
description?: string;
}
export type ViewRole = AppRole | '$guest';
/**
* This describes what a page will look like in the app.
*/
export interface BasePageDefinition {
/**
* The name of the page.
*
* This will be displayed at the *app bar* of each page and in the side menu,
* unless @see navTitle is set.
*
* The name of the page is used to determine the URL path of the page.
*/
name: string;
/**
* Whether or not the page name should be displayed in the *app bar*.
*/
hideName?: boolean;
/**
* The name of the page when displayed in the navigation menu.
*
* Context property `name` can be used to access the name of the page.
*/
navTitle?: Remapper;
/**
* Whether or not the page should be displayed in navigational menus.
*/
hideNavTitle?: boolean;
/**
* The navigation type to use for the page.
* Setting this will override the default navigation for the app.
*/
navigation?: Navigation;
/**
* A list of roles that may view the page.
*/
roles?: ViewRole[];
/**
* An optional icon from the fontawesome icon set
*
* This will be displayed in the navigation menu.
*/
icon?: IconName;
/**
* Page parameters can be used for linking to a page that should display a single resource.
*/
parameters?: string[];
/**
* The global theme for the page.
*/
theme?: Partial<Theme>;
/**
* A Remapper that resolves to a number to be visible in the side-menu.
*/
badgeCount?: Remapper;
/**
* A mapping of actions that can be fired by the page to action handlers.
*/
actions?: {
onLoad?: ActionDefinition;