diff --git a/packages/apps-engine/.prettierrc b/packages/apps-engine/.prettierrc deleted file mode 100644 index 9b77117b35c00..0000000000000 --- a/packages/apps-engine/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "tabWidth": 4, - "useTabs": false, - "singleQuote": true, - "trailingComma": "all", - "printWidth": 160 -} diff --git a/packages/apps-engine/deno-runtime/AppObjectRegistry.ts b/packages/apps-engine/deno-runtime/AppObjectRegistry.ts index 9069c17eaac5b..c9c05137a4a3d 100644 --- a/packages/apps-engine/deno-runtime/AppObjectRegistry.ts +++ b/packages/apps-engine/deno-runtime/AppObjectRegistry.ts @@ -1,26 +1,25 @@ export type Maybe = T | null | undefined; export const AppObjectRegistry = new class { - registry: Record = {}; + registry: Record = {}; - public get(key: string): Maybe { - return this.registry[key] as Maybe; - } + public get(key: string): Maybe { + return this.registry[key] as Maybe; + } - public set(key: string, value: unknown): void { - this.registry[key] = value; - } + public set(key: string, value: unknown): void { + this.registry[key] = value; + } - public has(key: string): boolean { - return key in this.registry; - } + public has(key: string): boolean { + return key in this.registry; + } - public delete(key: string): void { - delete this.registry[key]; - } - - public clear(): void { - this.registry = {}; - } -} + public delete(key: string): void { + delete this.registry[key]; + } + public clear(): void { + this.registry = {}; + } +}(); diff --git a/packages/apps-engine/deno-runtime/acorn-walk.d.ts b/packages/apps-engine/deno-runtime/acorn-walk.d.ts index 25861f3bce0fb..56db3bc38e9d2 100644 --- a/packages/apps-engine/deno-runtime/acorn-walk.d.ts +++ b/packages/apps-engine/deno-runtime/acorn-walk.d.ts @@ -1,51 +1,56 @@ -import type acorn from "./acorn.d.ts"; +import type acorn from './acorn.d.ts'; export type FullWalkerCallback = ( - node: acorn.AnyNode, - state: TState, - type: string -) => void + node: acorn.AnyNode, + state: TState, + type: string, +) => void; export type FullAncestorWalkerCallback = ( - node: acorn.AnyNode, - state: TState, - ancestors: acorn.AnyNode[], - type: string -) => void + node: acorn.AnyNode, + state: TState, + ancestors: acorn.AnyNode[], + type: string, +) => void; type AggregateType = { - Expression: acorn.Expression, - Statement: acorn.Statement, - Pattern: acorn.Pattern, - ForInit: acorn.VariableDeclaration | acorn.Expression -} - -export type SimpleVisitors = { - [type in acorn.AnyNode["type"]]?: (node: Extract, state: TState) => void -} & { - [type in keyof AggregateType]?: (node: AggregateType[type], state: TState) => void -} - -export type AncestorVisitors = { - [type in acorn.AnyNode["type"]]?: ( node: Extract, state: TState, ancestors: acorn.Node[] -) => void -} & { - [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, ancestors: acorn.Node[]) => void -} - -export type WalkerCallback = (node: acorn.Node, state: TState) => void - -export type RecursiveVisitors = { - [type in acorn.AnyNode["type"]]?: ( node: Extract, state: TState, callback: WalkerCallback) => void -} & { - [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, callback: WalkerCallback) => void -} - -export type FindPredicate = (type: string, node: acorn.Node) => boolean + Expression: acorn.Expression; + Statement: acorn.Statement; + Pattern: acorn.Pattern; + ForInit: acorn.VariableDeclaration | acorn.Expression; +}; + +export type SimpleVisitors = + & { + [type in acorn.AnyNode['type']]?: (node: Extract, state: TState) => void; + } + & { + [type in keyof AggregateType]?: (node: AggregateType[type], state: TState) => void; + }; + +export type AncestorVisitors = + & { + [type in acorn.AnyNode['type']]?: (node: Extract, state: TState, ancestors: acorn.Node[]) => void; + } + & { + [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, ancestors: acorn.Node[]) => void; + }; + +export type WalkerCallback = (node: acorn.Node, state: TState) => void; + +export type RecursiveVisitors = + & { + [type in acorn.AnyNode['type']]?: (node: Extract, state: TState, callback: WalkerCallback) => void; + } + & { + [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, callback: WalkerCallback) => void; + }; + +export type FindPredicate = (type: string, node: acorn.Node) => boolean; export interface Found { - node: acorn.Node, - state: TState + node: acorn.Node; + state: TState; } /** @@ -56,11 +61,11 @@ export interface Found { * @param state a start state. The default walker will simply visit all statements and expressions and not produce a meaningful state. (An example of a use of state is to track scope at each point in the tree.) */ export function simple( - node: acorn.Node, - visitors: SimpleVisitors, - base?: RecursiveVisitors, - state?: TState -): void + node: acorn.Node, + visitors: SimpleVisitors, + base?: RecursiveVisitors, + state?: TState, +): void; /** * does a 'simple' walk over a tree, building up an array of ancestor nodes (including the current node) and passing the array to the callbacks as a third parameter. @@ -70,11 +75,11 @@ export function simple( * @param state */ export function ancestor( - node: acorn.Node, - visitors: AncestorVisitors, - base?: RecursiveVisitors, - state?: TState - ): void + node: acorn.Node, + visitors: AncestorVisitors, + base?: RecursiveVisitors, + state?: TState, +): void; /** * does a 'recursive' walk, where the walker functions are responsible for continuing the walk on the child nodes of their target node. @@ -84,11 +89,11 @@ export function ancestor( * @param base provides the fallback walker functions for node types that aren't handled in the {@link functions} object. If not given, the default walkers will be used. */ export function recursive( - node: acorn.Node, - state: TState, - functions: RecursiveVisitors, - base?: RecursiveVisitors -): void + node: acorn.Node, + state: TState, + functions: RecursiveVisitors, + base?: RecursiveVisitors, +): void; /** * does a 'full' walk over a tree, calling the {@link callback} with the arguments (node, state, type) for each node @@ -98,11 +103,11 @@ export function recursive( * @param state */ export function full( - node: acorn.Node, - callback: FullWalkerCallback, - base?: RecursiveVisitors, - state?: TState -): void + node: acorn.Node, + callback: FullWalkerCallback, + base?: RecursiveVisitors, + state?: TState, +): void; /** * does a 'full' walk over a tree, building up an array of ancestor nodes (including the current node) and passing the array to the callbacks as a third parameter. @@ -112,11 +117,11 @@ export function full( * @param state */ export function fullAncestor( - node: acorn.AnyNode, - callback: FullAncestorWalkerCallback, - base?: RecursiveVisitors, - state?: TState -): void + node: acorn.AnyNode, + callback: FullAncestorWalkerCallback, + base?: RecursiveVisitors, + state?: TState, +): void; /** * builds a new walker object by using the walker functions in {@link functions} and filling in the missing ones by taking defaults from {@link base}. @@ -124,9 +129,9 @@ export function fullAncestor( * @param base */ export function make( - functions: RecursiveVisitors, - base?: RecursiveVisitors -): RecursiveVisitors + functions: RecursiveVisitors, + base?: RecursiveVisitors, +): RecursiveVisitors; /** * tries to locate a node in a tree at the given start and/or end offsets, which satisfies the predicate test. {@link start} and {@link end} can be either `null` (as wildcard) or a `number`. {@link test} may be a string (indicating a node type) or a function that takes (nodeType, node) arguments and returns a boolean indicating whether this node is interesting. {@link base} and {@link state} are optional, and can be used to specify a custom walker. Nodes are tested from inner to outer, so if two nodes match the boundaries, the inner one will be preferred. @@ -138,13 +143,13 @@ export function make( * @param state */ export function findNodeAt( - node: acorn.AnyNode, - start: number | undefined, - end?: number | undefined, - type?: FindPredicate | string, - base?: RecursiveVisitors, - state?: TState -): Found | undefined + node: acorn.AnyNode, + start: number | undefined, + end?: number | undefined, + type?: FindPredicate | string, + base?: RecursiveVisitors, + state?: TState, +): Found | undefined; /** * like {@link findNodeAt}, but will match any node that exists 'around' (spanning) the given position. @@ -155,16 +160,16 @@ export function findNodeAt( * @param state */ export function findNodeAround( - node: acorn.AnyNode, - start: number | undefined, - type?: FindPredicate | string, - base?: RecursiveVisitors, - state?: TState -): Found | undefined + node: acorn.AnyNode, + start: number | undefined, + type?: FindPredicate | string, + base?: RecursiveVisitors, + state?: TState, +): Found | undefined; /** * similar to {@link findNodeAround}, but will match all nodes after the given position (testing outer nodes before inner nodes). */ -export const findNodeAfter: typeof findNodeAround +export const findNodeAfter: typeof findNodeAround; -export const base: RecursiveVisitors +export const base: RecursiveVisitors; diff --git a/packages/apps-engine/deno-runtime/acorn.d.ts b/packages/apps-engine/deno-runtime/acorn.d.ts index 0b5bc6b407b20..7ba007d999b11 100644 --- a/packages/apps-engine/deno-runtime/acorn.d.ts +++ b/packages/apps-engine/deno-runtime/acorn.d.ts @@ -1,857 +1,915 @@ export interface Node { - start?: number - end?: number - type: string - range?: [number, number] - loc?: SourceLocation | null + start?: number; + end?: number; + type: string; + range?: [number, number]; + loc?: SourceLocation | null; } export interface SourceLocation { - source?: string | null - start: Position - end: Position + source?: string | null; + start: Position; + end: Position; } export interface Position { - /** 1-based */ - line: number - /** 0-based */ - column: number + /** 1-based */ + line: number; + /** 0-based */ + column: number; } export interface Identifier extends Node { - type: "Identifier" - name: string + type: 'Identifier'; + name: string; } export interface Literal extends Node { - type: "Literal" - value?: string | boolean | null | number | RegExp | bigint - raw?: string - regex?: { - pattern: string - flags: string - } - bigint?: string + type: 'Literal'; + value?: string | boolean | null | number | RegExp | bigint; + raw?: string; + regex?: { + pattern: string; + flags: string; + }; + bigint?: string; } export interface Program extends Node { - type: "Program" - body: Array - sourceType: "script" | "module" + type: 'Program'; + body: Array; + sourceType: 'script' | 'module'; } export interface Function extends Node { - id?: Identifier | null - params: Array - body: BlockStatement | Expression - generator: boolean - expression: boolean - async: boolean + id?: Identifier | null; + params: Array; + body: BlockStatement | Expression; + generator: boolean; + expression: boolean; + async: boolean; } export interface ExpressionStatement extends Node { - type: "ExpressionStatement" - expression: Expression | Literal - directive?: string + type: 'ExpressionStatement'; + expression: Expression | Literal; + directive?: string; } export interface BlockStatement extends Node { - type: "BlockStatement" - body: Array + type: 'BlockStatement'; + body: Array; } export interface EmptyStatement extends Node { - type: "EmptyStatement" + type: 'EmptyStatement'; } export interface DebuggerStatement extends Node { - type: "DebuggerStatement" + type: 'DebuggerStatement'; } export interface WithStatement extends Node { - type: "WithStatement" - object: Expression - body: Statement + type: 'WithStatement'; + object: Expression; + body: Statement; } export interface ReturnStatement extends Node { - type: "ReturnStatement" - argument?: Expression | null + type: 'ReturnStatement'; + argument?: Expression | null; } export interface LabeledStatement extends Node { - type: "LabeledStatement" - label: Identifier - body: Statement + type: 'LabeledStatement'; + label: Identifier; + body: Statement; } export interface BreakStatement extends Node { - type: "BreakStatement" - label?: Identifier | null + type: 'BreakStatement'; + label?: Identifier | null; } export interface ContinueStatement extends Node { - type: "ContinueStatement" - label?: Identifier | null + type: 'ContinueStatement'; + label?: Identifier | null; } export interface IfStatement extends Node { - type: "IfStatement" - test: Expression - consequent: Statement - alternate?: Statement | null + type: 'IfStatement'; + test: Expression; + consequent: Statement; + alternate?: Statement | null; } export interface SwitchStatement extends Node { - type: "SwitchStatement" - discriminant: Expression - cases: Array + type: 'SwitchStatement'; + discriminant: Expression; + cases: Array; } export interface SwitchCase extends Node { - type: "SwitchCase" - test?: Expression | null - consequent: Array + type: 'SwitchCase'; + test?: Expression | null; + consequent: Array; } export interface ThrowStatement extends Node { - type: "ThrowStatement" - argument: Expression + type: 'ThrowStatement'; + argument: Expression; } export interface TryStatement extends Node { - type: "TryStatement" - block: BlockStatement - handler?: CatchClause | null - finalizer?: BlockStatement | null + type: 'TryStatement'; + block: BlockStatement; + handler?: CatchClause | null; + finalizer?: BlockStatement | null; } export interface CatchClause extends Node { - type: "CatchClause" - param?: Pattern | null - body: BlockStatement + type: 'CatchClause'; + param?: Pattern | null; + body: BlockStatement; } export interface WhileStatement extends Node { - type: "WhileStatement" - test: Expression - body: Statement + type: 'WhileStatement'; + test: Expression; + body: Statement; } export interface DoWhileStatement extends Node { - type: "DoWhileStatement" - body: Statement - test: Expression + type: 'DoWhileStatement'; + body: Statement; + test: Expression; } export interface ForStatement extends Node { - type: "ForStatement" - init?: VariableDeclaration | Expression | null - test?: Expression | null - update?: Expression | null - body: Statement + type: 'ForStatement'; + init?: VariableDeclaration | Expression | null; + test?: Expression | null; + update?: Expression | null; + body: Statement; } export interface ForInStatement extends Node { - type: "ForInStatement" - left: VariableDeclaration | Pattern - right: Expression - body: Statement + type: 'ForInStatement'; + left: VariableDeclaration | Pattern; + right: Expression; + body: Statement; } export interface FunctionDeclaration extends Function { - type: "FunctionDeclaration" - id: Identifier - body: BlockStatement + type: 'FunctionDeclaration'; + id: Identifier; + body: BlockStatement; } export interface VariableDeclaration extends Node { - type: "VariableDeclaration" - declarations: Array - kind: "var" | "let" | "const" + type: 'VariableDeclaration'; + declarations: Array; + kind: 'var' | 'let' | 'const'; } export interface VariableDeclarator extends Node { - type: "VariableDeclarator" - id: Pattern - init?: Expression | null + type: 'VariableDeclarator'; + id: Pattern; + init?: Expression | null; } export interface ThisExpression extends Node { - type: "ThisExpression" + type: 'ThisExpression'; } export interface ArrayExpression extends Node { - type: "ArrayExpression" - elements: Array + type: 'ArrayExpression'; + elements: Array; } export interface ObjectExpression extends Node { - type: "ObjectExpression" - properties: Array + type: 'ObjectExpression'; + properties: Array; } export interface Property extends Node { - type: "Property" - key: Expression - value: Expression - kind: "init" | "get" | "set" - method: boolean - shorthand: boolean - computed: boolean + type: 'Property'; + key: Expression; + value: Expression; + kind: 'init' | 'get' | 'set'; + method: boolean; + shorthand: boolean; + computed: boolean; } export interface FunctionExpression extends Function { - type: "FunctionExpression" - body: BlockStatement + type: 'FunctionExpression'; + body: BlockStatement; } export interface UnaryExpression extends Node { - type: "UnaryExpression" - operator: UnaryOperator - prefix: boolean - argument: Expression + type: 'UnaryExpression'; + operator: UnaryOperator; + prefix: boolean; + argument: Expression; } -export type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" +export type UnaryOperator = '-' | '+' | '!' | '~' | 'typeof' | 'void' | 'delete'; export interface UpdateExpression extends Node { - type: "UpdateExpression" - operator: UpdateOperator - argument: Expression - prefix: boolean + type: 'UpdateExpression'; + operator: UpdateOperator; + argument: Expression; + prefix: boolean; } -export type UpdateOperator = "++" | "--" +export type UpdateOperator = '++' | '--'; export interface BinaryExpression extends Node { - type: "BinaryExpression" - operator: BinaryOperator - left: Expression | PrivateIdentifier - right: Expression -} - -export type BinaryOperator = "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | "in" | "instanceof" | "**" + type: 'BinaryExpression'; + operator: BinaryOperator; + left: Expression | PrivateIdentifier; + right: Expression; +} + +export type BinaryOperator = + | '==' + | '!=' + | '===' + | '!==' + | '<' + | '<=' + | '>' + | '>=' + | '<<' + | '>>' + | '>>>' + | '+' + | '-' + | '*' + | '/' + | '%' + | '|' + | '^' + | '&' + | 'in' + | 'instanceof' + | '**'; export interface AssignmentExpression extends Node { - type: "AssignmentExpression" - operator: AssignmentOperator - left: Pattern - right: Expression + type: 'AssignmentExpression'; + operator: AssignmentOperator; + left: Pattern; + right: Expression; } -export type AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" | "**=" | "||=" | "&&=" | "??=" +export type AssignmentOperator = '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '<<=' | '>>=' | '>>>=' | '|=' | '^=' | '&=' | '**=' | '||=' | '&&=' | '??='; export interface LogicalExpression extends Node { - type: "LogicalExpression" - operator: LogicalOperator - left: Expression - right: Expression + type: 'LogicalExpression'; + operator: LogicalOperator; + left: Expression; + right: Expression; } -export type LogicalOperator = "||" | "&&" | "??" +export type LogicalOperator = '||' | '&&' | '??'; export interface MemberExpression extends Node { - type: "MemberExpression" - object: Expression | Super - property: Expression | PrivateIdentifier - computed: boolean - optional: boolean + type: 'MemberExpression'; + object: Expression | Super; + property: Expression | PrivateIdentifier; + computed: boolean; + optional: boolean; } export interface ConditionalExpression extends Node { - type: "ConditionalExpression" - test: Expression - alternate: Expression - consequent: Expression + type: 'ConditionalExpression'; + test: Expression; + alternate: Expression; + consequent: Expression; } export interface CallExpression extends Node { - type: "CallExpression" - callee: Expression | Super - arguments: Array - optional: boolean + type: 'CallExpression'; + callee: Expression | Super; + arguments: Array; + optional: boolean; } export interface NewExpression extends Node { - type: "NewExpression" - callee: Expression - arguments: Array + type: 'NewExpression'; + callee: Expression; + arguments: Array; } export interface SequenceExpression extends Node { - type: "SequenceExpression" - expressions: Array + type: 'SequenceExpression'; + expressions: Array; } export interface ForOfStatement extends Node { - type: "ForOfStatement" - left: VariableDeclaration | Pattern - right: Expression - body: Statement - await: boolean + type: 'ForOfStatement'; + left: VariableDeclaration | Pattern; + right: Expression; + body: Statement; + await: boolean; } export interface Super extends Node { - type: "Super" + type: 'Super'; } export interface SpreadElement extends Node { - type: "SpreadElement" - argument: Expression + type: 'SpreadElement'; + argument: Expression; } export interface ArrowFunctionExpression extends Function { - type: "ArrowFunctionExpression" + type: 'ArrowFunctionExpression'; } export interface YieldExpression extends Node { - type: "YieldExpression" - argument?: Expression | null - delegate: boolean + type: 'YieldExpression'; + argument?: Expression | null; + delegate: boolean; } export interface TemplateLiteral extends Node { - type: "TemplateLiteral" - quasis: Array - expressions: Array + type: 'TemplateLiteral'; + quasis: Array; + expressions: Array; } export interface TaggedTemplateExpression extends Node { - type: "TaggedTemplateExpression" - tag: Expression - quasi: TemplateLiteral + type: 'TaggedTemplateExpression'; + tag: Expression; + quasi: TemplateLiteral; } export interface TemplateElement extends Node { - type: "TemplateElement" - tail: boolean - value: { - cooked?: string | null - raw: string - } + type: 'TemplateElement'; + tail: boolean; + value: { + cooked?: string | null; + raw: string; + }; } export interface AssignmentProperty extends Node { - type: "Property" - key: Expression - value: Pattern - kind: "init" - method: false - shorthand: boolean - computed: boolean + type: 'Property'; + key: Expression; + value: Pattern; + kind: 'init'; + method: false; + shorthand: boolean; + computed: boolean; } export interface ObjectPattern extends Node { - type: "ObjectPattern" - properties: Array + type: 'ObjectPattern'; + properties: Array; } export interface ArrayPattern extends Node { - type: "ArrayPattern" - elements: Array + type: 'ArrayPattern'; + elements: Array; } export interface RestElement extends Node { - type: "RestElement" - argument: Pattern + type: 'RestElement'; + argument: Pattern; } export interface AssignmentPattern extends Node { - type: "AssignmentPattern" - left: Pattern - right: Expression + type: 'AssignmentPattern'; + left: Pattern; + right: Expression; } export interface Class extends Node { - id?: Identifier | null - superClass?: Expression | null - body: ClassBody + id?: Identifier | null; + superClass?: Expression | null; + body: ClassBody; } export interface ClassBody extends Node { - type: "ClassBody" - body: Array + type: 'ClassBody'; + body: Array; } export interface MethodDefinition extends Node { - type: "MethodDefinition" - key: Expression | PrivateIdentifier - value: FunctionExpression - kind: "constructor" | "method" | "get" | "set" - computed: boolean - static: boolean + type: 'MethodDefinition'; + key: Expression | PrivateIdentifier; + value: FunctionExpression; + kind: 'constructor' | 'method' | 'get' | 'set'; + computed: boolean; + static: boolean; } export interface ClassDeclaration extends Class { - type: "ClassDeclaration" - id: Identifier + type: 'ClassDeclaration'; + id: Identifier; } export interface ClassExpression extends Class { - type: "ClassExpression" + type: 'ClassExpression'; } export interface MetaProperty extends Node { - type: "MetaProperty" - meta: Identifier - property: Identifier + type: 'MetaProperty'; + meta: Identifier; + property: Identifier; } export interface ImportDeclaration extends Node { - type: "ImportDeclaration" - specifiers: Array - source: Literal + type: 'ImportDeclaration'; + specifiers: Array; + source: Literal; } export interface ImportSpecifier extends Node { - type: "ImportSpecifier" - imported: Identifier | Literal - local: Identifier + type: 'ImportSpecifier'; + imported: Identifier | Literal; + local: Identifier; } export interface ImportDefaultSpecifier extends Node { - type: "ImportDefaultSpecifier" - local: Identifier + type: 'ImportDefaultSpecifier'; + local: Identifier; } export interface ImportNamespaceSpecifier extends Node { - type: "ImportNamespaceSpecifier" - local: Identifier + type: 'ImportNamespaceSpecifier'; + local: Identifier; } export interface ExportNamedDeclaration extends Node { - type: "ExportNamedDeclaration" - declaration?: Declaration | null - specifiers: Array - source?: Literal | null + type: 'ExportNamedDeclaration'; + declaration?: Declaration | null; + specifiers: Array; + source?: Literal | null; } export interface ExportSpecifier extends Node { - type: "ExportSpecifier" - exported: Identifier | Literal - local: Identifier | Literal + type: 'ExportSpecifier'; + exported: Identifier | Literal; + local: Identifier | Literal; } export interface AnonymousFunctionDeclaration extends Function { - type: "FunctionDeclaration" - id: null - body: BlockStatement + type: 'FunctionDeclaration'; + id: null; + body: BlockStatement; } export interface AnonymousClassDeclaration extends Class { - type: "ClassDeclaration" - id: null + type: 'ClassDeclaration'; + id: null; } export interface ExportDefaultDeclaration extends Node { - type: "ExportDefaultDeclaration" - declaration: AnonymousFunctionDeclaration | FunctionDeclaration | AnonymousClassDeclaration | ClassDeclaration | Expression + type: 'ExportDefaultDeclaration'; + declaration: AnonymousFunctionDeclaration | FunctionDeclaration | AnonymousClassDeclaration | ClassDeclaration | Expression; } export interface ExportAllDeclaration extends Node { - type: "ExportAllDeclaration" - source: Literal - exported?: Identifier | Literal | null + type: 'ExportAllDeclaration'; + source: Literal; + exported?: Identifier | Literal | null; } export interface AwaitExpression extends Node { - type: "AwaitExpression" - argument: Expression + type: 'AwaitExpression'; + argument: Expression; } export interface ChainExpression extends Node { - type: "ChainExpression" - expression: MemberExpression | CallExpression + type: 'ChainExpression'; + expression: MemberExpression | CallExpression; } export interface ImportExpression extends Node { - type: "ImportExpression" - source: Expression + type: 'ImportExpression'; + source: Expression; } export interface ParenthesizedExpression extends Node { - type: "ParenthesizedExpression" - expression: Expression + type: 'ParenthesizedExpression'; + expression: Expression; } export interface PropertyDefinition extends Node { - type: "PropertyDefinition" - key: Expression | PrivateIdentifier - value?: Expression | null - computed: boolean - static: boolean + type: 'PropertyDefinition'; + key: Expression | PrivateIdentifier; + value?: Expression | null; + computed: boolean; + static: boolean; } export interface PrivateIdentifier extends Node { - type: "PrivateIdentifier" - name: string + type: 'PrivateIdentifier'; + name: string; } export interface StaticBlock extends Node { - type: "StaticBlock" - body: Array + type: 'StaticBlock'; + body: Array; } export type Statement = -| ExpressionStatement -| BlockStatement -| EmptyStatement -| DebuggerStatement -| WithStatement -| ReturnStatement -| LabeledStatement -| BreakStatement -| ContinueStatement -| IfStatement -| SwitchStatement -| ThrowStatement -| TryStatement -| WhileStatement -| DoWhileStatement -| ForStatement -| ForInStatement -| ForOfStatement -| Declaration + | ExpressionStatement + | BlockStatement + | EmptyStatement + | DebuggerStatement + | WithStatement + | ReturnStatement + | LabeledStatement + | BreakStatement + | ContinueStatement + | IfStatement + | SwitchStatement + | ThrowStatement + | TryStatement + | WhileStatement + | DoWhileStatement + | ForStatement + | ForInStatement + | ForOfStatement + | Declaration; export type Declaration = -| FunctionDeclaration -| VariableDeclaration -| ClassDeclaration + | FunctionDeclaration + | VariableDeclaration + | ClassDeclaration; export type Expression = -| Identifier -| Literal -| ThisExpression -| ArrayExpression -| ObjectExpression -| FunctionExpression -| UnaryExpression -| UpdateExpression -| BinaryExpression -| AssignmentExpression -| LogicalExpression -| MemberExpression -| ConditionalExpression -| CallExpression -| NewExpression -| SequenceExpression -| ArrowFunctionExpression -| YieldExpression -| TemplateLiteral -| TaggedTemplateExpression -| ClassExpression -| MetaProperty -| AwaitExpression -| ChainExpression -| ImportExpression -| ParenthesizedExpression + | Identifier + | Literal + | ThisExpression + | ArrayExpression + | ObjectExpression + | FunctionExpression + | UnaryExpression + | UpdateExpression + | BinaryExpression + | AssignmentExpression + | LogicalExpression + | MemberExpression + | ConditionalExpression + | CallExpression + | NewExpression + | SequenceExpression + | ArrowFunctionExpression + | YieldExpression + | TemplateLiteral + | TaggedTemplateExpression + | ClassExpression + | MetaProperty + | AwaitExpression + | ChainExpression + | ImportExpression + | ParenthesizedExpression; export type Pattern = -| Identifier -| MemberExpression -| ObjectPattern -| ArrayPattern -| RestElement -| AssignmentPattern + | Identifier + | MemberExpression + | ObjectPattern + | ArrayPattern + | RestElement + | AssignmentPattern; export type ModuleDeclaration = -| ImportDeclaration -| ExportNamedDeclaration -| ExportDefaultDeclaration -| ExportAllDeclaration - -export type AnyNode = Statement | Expression | Declaration | ModuleDeclaration | Literal | Program | SwitchCase | CatchClause | Property | Super | SpreadElement | TemplateElement | AssignmentProperty | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | ClassBody | MethodDefinition | MetaProperty | ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ExportSpecifier | AnonymousFunctionDeclaration | AnonymousClassDeclaration | PropertyDefinition | PrivateIdentifier | StaticBlock | VariableDeclaration | VariableDeclarator - -export function parse(input: string, options: Options): Program - -export function parseExpressionAt(input: string, pos: number, options: Options): Expression + | ImportDeclaration + | ExportNamedDeclaration + | ExportDefaultDeclaration + | ExportAllDeclaration; + +export type AnyNode = + | Statement + | Expression + | Declaration + | ModuleDeclaration + | Literal + | Program + | SwitchCase + | CatchClause + | Property + | Super + | SpreadElement + | TemplateElement + | AssignmentProperty + | ObjectPattern + | ArrayPattern + | RestElement + | AssignmentPattern + | ClassBody + | MethodDefinition + | MetaProperty + | ImportSpecifier + | ImportDefaultSpecifier + | ImportNamespaceSpecifier + | ExportSpecifier + | AnonymousFunctionDeclaration + | AnonymousClassDeclaration + | PropertyDefinition + | PrivateIdentifier + | StaticBlock + | VariableDeclaration + | VariableDeclarator; + +export function parse(input: string, options: Options): Program; + +export function parseExpressionAt(input: string, pos: number, options: Options): Expression; export function tokenizer(input: string, options: Options): { - getToken(): Token - [Symbol.iterator](): Iterator -} + getToken(): Token; + [Symbol.iterator](): Iterator; +}; -export type ecmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | "latest" +export type ecmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 'latest'; export interface Options { - /** - * `ecmaVersion` indicates the ECMAScript version to parse. Must be - * either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10 - * (2019), 11 (2020), 12 (2021), 13 (2022), 14 (2023), or `"latest"` - * (the latest version the library supports). This influences - * support for strict mode, the set of reserved words, and support - * for new syntax features. - */ - ecmaVersion: ecmaVersion - - /** - * `sourceType` indicates the mode the code should be parsed in. - * Can be either `"script"` or `"module"`. This influences global - * strict mode and parsing of `import` and `export` declarations. - */ - sourceType?: "script" | "module" - - /** - * a callback that will be called when a semicolon is automatically inserted. - * @param lastTokEnd the position of the comma as an offset - * @param lastTokEndLoc location if {@link locations} is enabled - */ - onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void - - /** - * similar to `onInsertedSemicolon`, but for trailing commas - * @param lastTokEnd the position of the comma as an offset - * @param lastTokEndLoc location if `locations` is enabled - */ - onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void - - /** - * By default, reserved words are only enforced if ecmaVersion >= 5. - * Set `allowReserved` to a boolean value to explicitly turn this on - * an off. When this option has the value "never", reserved words - * and keywords can also not be used as property names. - */ - allowReserved?: boolean | "never" - - /** - * When enabled, a return at the top level is not considered an error. - */ - allowReturnOutsideFunction?: boolean - - /** - * When enabled, import/export statements are not constrained to - * appearing at the top of the program, and an import.meta expression - * in a script isn't considered an error. - */ - allowImportExportEverywhere?: boolean - - /** - * By default, `await` identifiers are allowed to appear at the top-level scope only if {@link ecmaVersion} >= 2022. - * When enabled, await identifiers are allowed to appear at the top-level scope, - * but they are still not allowed in non-async functions. - */ - allowAwaitOutsideFunction?: boolean - - /** - * When enabled, super identifiers are not constrained to - * appearing in methods and do not raise an error when they appear elsewhere. - */ - allowSuperOutsideMethod?: boolean - - /** - * When enabled, hashbang directive in the beginning of file is - * allowed and treated as a line comment. Enabled by default when - * {@link ecmaVersion} >= 2023. - */ - allowHashBang?: boolean - - /** - * By default, the parser will verify that private properties are - * only used in places where they are valid and have been declared. - * Set this to false to turn such checks off. - */ - checkPrivateFields?: boolean - - /** - * When `locations` is on, `loc` properties holding objects with - * `start` and `end` properties as {@link Position} objects will be attached to the - * nodes. - */ - locations?: boolean - - /** - * a callback that will cause Acorn to call that export function with object in the same - * format as tokens returned from `tokenizer().getToken()`. Note - * that you are not allowed to call the parser from the - * callback—that will corrupt its internal state. - */ - onToken?: ((token: Token) => void) | Token[] - - - /** - * This takes a export function or an array. - * - * When a export function is passed, Acorn will call that export function with `(block, text, start, - * end)` parameters whenever a comment is skipped. `block` is a - * boolean indicating whether this is a block (`/* *\/`) comment, - * `text` is the content of the comment, and `start` and `end` are - * character offsets that denote the start and end of the comment. - * When the {@link locations} option is on, two more parameters are - * passed, the full locations of {@link Position} export type of the start and - * end of the comments. - * - * When a array is passed, each found comment of {@link Comment} export type is pushed to the array. - * - * Note that you are not allowed to call the - * parser from the callback—that will corrupt its internal state. - */ - onComment?: (( - isBlock: boolean, text: string, start: number, end: number, startLoc?: Position, - endLoc?: Position - ) => void) | Comment[] - - /** - * Nodes have their start and end characters offsets recorded in - * `start` and `end` properties (directly on the node, rather than - * the `loc` object, which holds line/column data. To also add a - * [semi-standardized][range] `range` property holding a `[start, - * end]` array with the same numbers, set the `ranges` option to - * `true`. - */ - ranges?: boolean - - /** - * It is possible to parse multiple files into a single AST by - * passing the tree produced by parsing the first file as - * `program` option in subsequent parses. This will add the - * toplevel forms of the parsed file to the `Program` (top) node - * of an existing parse tree. - */ - program?: Node - - /** - * When {@link locations} is on, you can pass this to record the source - * file in every node's `loc` object. - */ - sourceFile?: string - - /** - * This value, if given, is stored in every node, whether {@link locations} is on or off. - */ - directSourceFile?: string - - /** - * When enabled, parenthesized expressions are represented by - * (non-standard) ParenthesizedExpression nodes - */ - preserveParens?: boolean + /** + * `ecmaVersion` indicates the ECMAScript version to parse. Must be + * either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10 + * (2019), 11 (2020), 12 (2021), 13 (2022), 14 (2023), or `"latest"` + * (the latest version the library supports). This influences + * support for strict mode, the set of reserved words, and support + * for new syntax features. + */ + ecmaVersion: ecmaVersion; + + /** + * `sourceType` indicates the mode the code should be parsed in. + * Can be either `"script"` or `"module"`. This influences global + * strict mode and parsing of `import` and `export` declarations. + */ + sourceType?: 'script' | 'module'; + + /** + * a callback that will be called when a semicolon is automatically inserted. + * @param lastTokEnd the position of the comma as an offset + * @param lastTokEndLoc location if {@link locations} is enabled + */ + onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void; + + /** + * similar to `onInsertedSemicolon`, but for trailing commas + * @param lastTokEnd the position of the comma as an offset + * @param lastTokEndLoc location if `locations` is enabled + */ + onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void; + + /** + * By default, reserved words are only enforced if ecmaVersion >= 5. + * Set `allowReserved` to a boolean value to explicitly turn this on + * an off. When this option has the value "never", reserved words + * and keywords can also not be used as property names. + */ + allowReserved?: boolean | 'never'; + + /** + * When enabled, a return at the top level is not considered an error. + */ + allowReturnOutsideFunction?: boolean; + + /** + * When enabled, import/export statements are not constrained to + * appearing at the top of the program, and an import.meta expression + * in a script isn't considered an error. + */ + allowImportExportEverywhere?: boolean; + + /** + * By default, `await` identifiers are allowed to appear at the top-level scope only if {@link ecmaVersion} >= 2022. + * When enabled, await identifiers are allowed to appear at the top-level scope, + * but they are still not allowed in non-async functions. + */ + allowAwaitOutsideFunction?: boolean; + + /** + * When enabled, super identifiers are not constrained to + * appearing in methods and do not raise an error when they appear elsewhere. + */ + allowSuperOutsideMethod?: boolean; + + /** + * When enabled, hashbang directive in the beginning of file is + * allowed and treated as a line comment. Enabled by default when + * {@link ecmaVersion} >= 2023. + */ + allowHashBang?: boolean; + + /** + * By default, the parser will verify that private properties are + * only used in places where they are valid and have been declared. + * Set this to false to turn such checks off. + */ + checkPrivateFields?: boolean; + + /** + * When `locations` is on, `loc` properties holding objects with + * `start` and `end` properties as {@link Position} objects will be attached to the + * nodes. + */ + locations?: boolean; + + /** + * a callback that will cause Acorn to call that export function with object in the same + * format as tokens returned from `tokenizer().getToken()`. Note + * that you are not allowed to call the parser from the + * callback—that will corrupt its internal state. + */ + onToken?: ((token: Token) => void) | Token[]; + + /** + * This takes a export function or an array. + * + * When a export function is passed, Acorn will call that export function with `(block, text, start, + * end)` parameters whenever a comment is skipped. `block` is a + * boolean indicating whether this is a block (`/* *\/`) comment, + * `text` is the content of the comment, and `start` and `end` are + * character offsets that denote the start and end of the comment. + * When the {@link locations} option is on, two more parameters are + * passed, the full locations of {@link Position} export type of the start and + * end of the comments. + * + * When a array is passed, each found comment of {@link Comment} export type is pushed to the array. + * + * Note that you are not allowed to call the + * parser from the callback—that will corrupt its internal state. + */ + onComment?: + | (( + isBlock: boolean, + text: string, + start: number, + end: number, + startLoc?: Position, + endLoc?: Position, + ) => void) + | Comment[]; + + /** + * Nodes have their start and end characters offsets recorded in + * `start` and `end` properties (directly on the node, rather than + * the `loc` object, which holds line/column data. To also add a + * [semi-standardized][range] `range` property holding a `[start, + * end]` array with the same numbers, set the `ranges` option to + * `true`. + */ + ranges?: boolean; + + /** + * It is possible to parse multiple files into a single AST by + * passing the tree produced by parsing the first file as + * `program` option in subsequent parses. This will add the + * toplevel forms of the parsed file to the `Program` (top) node + * of an existing parse tree. + */ + program?: Node; + + /** + * When {@link locations} is on, you can pass this to record the source + * file in every node's `loc` object. + */ + sourceFile?: string; + + /** + * This value, if given, is stored in every node, whether {@link locations} is on or off. + */ + directSourceFile?: string; + + /** + * When enabled, parenthesized expressions are represented by + * (non-standard) ParenthesizedExpression nodes + */ + preserveParens?: boolean; } export class Parser { - options: Options - input: string + options: Options; + input: string; - constructor(options: Options, input: string, startPos?: number) - parse(): Program + constructor(options: Options, input: string, startPos?: number); + parse(): Program; - static parse(input: string, options: Options): Program - static parseExpressionAt(input: string, pos: number, options: Options): Expression - static tokenizer(input: string, options: Options): { - getToken(): Token - [Symbol.iterator](): Iterator - } - static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser + static parse(input: string, options: Options): Program; + static parseExpressionAt(input: string, pos: number, options: Options): Expression; + static tokenizer(input: string, options: Options): { + getToken(): Token; + [Symbol.iterator](): Iterator; + }; + static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser; } -export const defaultOptions: Options +export const defaultOptions: Options; -export function getLineInfo(input: string, offset: number): Position +export function getLineInfo(input: string, offset: number): Position; export class TokenType { - label: string - keyword: string | undefined + label: string; + keyword: string | undefined; } export const tokTypes: { - num: TokenType - regexp: TokenType - string: TokenType - name: TokenType - privateId: TokenType - eof: TokenType - - bracketL: TokenType - bracketR: TokenType - braceL: TokenType - braceR: TokenType - parenL: TokenType - parenR: TokenType - comma: TokenType - semi: TokenType - colon: TokenType - dot: TokenType - question: TokenType - questionDot: TokenType - arrow: TokenType - template: TokenType - invalidTemplate: TokenType - ellipsis: TokenType - backQuote: TokenType - dollarBraceL: TokenType - - eq: TokenType - assign: TokenType - incDec: TokenType - prefix: TokenType - logicalOR: TokenType - logicalAND: TokenType - bitwiseOR: TokenType - bitwiseXOR: TokenType - bitwiseAND: TokenType - equality: TokenType - relational: TokenType - bitShift: TokenType - plusMin: TokenType - modulo: TokenType - star: TokenType - slash: TokenType - starstar: TokenType - coalesce: TokenType - - _break: TokenType - _case: TokenType - _catch: TokenType - _continue: TokenType - _debugger: TokenType - _default: TokenType - _do: TokenType - _else: TokenType - _finally: TokenType - _for: TokenType - _function: TokenType - _if: TokenType - _return: TokenType - _switch: TokenType - _throw: TokenType - _try: TokenType - _var: TokenType - _const: TokenType - _while: TokenType - _with: TokenType - _new: TokenType - _this: TokenType - _super: TokenType - _class: TokenType - _extends: TokenType - _export: TokenType - _import: TokenType - _null: TokenType - _true: TokenType - _false: TokenType - _in: TokenType - _instanceof: TokenType - _typeof: TokenType - _void: TokenType - _delete: TokenType -} + num: TokenType; + regexp: TokenType; + string: TokenType; + name: TokenType; + privateId: TokenType; + eof: TokenType; + + bracketL: TokenType; + bracketR: TokenType; + braceL: TokenType; + braceR: TokenType; + parenL: TokenType; + parenR: TokenType; + comma: TokenType; + semi: TokenType; + colon: TokenType; + dot: TokenType; + question: TokenType; + questionDot: TokenType; + arrow: TokenType; + template: TokenType; + invalidTemplate: TokenType; + ellipsis: TokenType; + backQuote: TokenType; + dollarBraceL: TokenType; + + eq: TokenType; + assign: TokenType; + incDec: TokenType; + prefix: TokenType; + logicalOR: TokenType; + logicalAND: TokenType; + bitwiseOR: TokenType; + bitwiseXOR: TokenType; + bitwiseAND: TokenType; + equality: TokenType; + relational: TokenType; + bitShift: TokenType; + plusMin: TokenType; + modulo: TokenType; + star: TokenType; + slash: TokenType; + starstar: TokenType; + coalesce: TokenType; + + _break: TokenType; + _case: TokenType; + _catch: TokenType; + _continue: TokenType; + _debugger: TokenType; + _default: TokenType; + _do: TokenType; + _else: TokenType; + _finally: TokenType; + _for: TokenType; + _function: TokenType; + _if: TokenType; + _return: TokenType; + _switch: TokenType; + _throw: TokenType; + _try: TokenType; + _var: TokenType; + _const: TokenType; + _while: TokenType; + _with: TokenType; + _new: TokenType; + _this: TokenType; + _super: TokenType; + _class: TokenType; + _extends: TokenType; + _export: TokenType; + _import: TokenType; + _null: TokenType; + _true: TokenType; + _false: TokenType; + _in: TokenType; + _instanceof: TokenType; + _typeof: TokenType; + _void: TokenType; + _delete: TokenType; +}; export interface Comment { - type: "Line" | "Block" - value: string - start: number - end: number - loc?: SourceLocation - range?: [number, number] + type: 'Line' | 'Block'; + value: string; + start: number; + end: number; + loc?: SourceLocation; + range?: [number, number]; } export class Token { - type: TokenType - start: number - end: number - loc?: SourceLocation - range?: [number, number] + type: TokenType; + start: number; + end: number; + loc?: SourceLocation; + range?: [number, number]; } -export const version: string +export const version: string; diff --git a/packages/apps-engine/deno-runtime/deno.jsonc b/packages/apps-engine/deno-runtime/deno.jsonc index 6f3aece324cb4..cefd268cf8856 100644 --- a/packages/apps-engine/deno-runtime/deno.jsonc +++ b/packages/apps-engine/deno-runtime/deno.jsonc @@ -1,17 +1,23 @@ { - "imports": { - "@msgpack/msgpack": "npm:@msgpack/msgpack@3.0.0-beta2", - "@rocket.chat/apps-engine/": "./../src/", - "@rocket.chat/ui-kit": "npm:@rocket.chat/ui-kit@^0.31.22", - "@std/cli": "jsr:@std/cli@^1.0.9", - "acorn": "npm:acorn@8.10.0", - "acorn-walk": "npm:acorn-walk@8.2.0", - "astring": "npm:astring@1.8.6", - "jsonrpc-lite": "npm:jsonrpc-lite@2.2.0", - "stack-trace": "npm:stack-trace@0.0.10", - "uuid": "npm:uuid@8.3.2" - }, - "tasks": { - "test": "deno test --no-check --allow-read=../../../" - } + "imports": { + "@msgpack/msgpack": "npm:@msgpack/msgpack@3.0.0-beta2", + "@rocket.chat/apps-engine/": "./../src/", + "@rocket.chat/ui-kit": "npm:@rocket.chat/ui-kit@^0.31.22", + "@std/cli": "jsr:@std/cli@^1.0.9", + "acorn": "npm:acorn@8.10.0", + "acorn-walk": "npm:acorn-walk@8.2.0", + "astring": "npm:astring@1.8.6", + "jsonrpc-lite": "npm:jsonrpc-lite@2.2.0", + "stack-trace": "npm:stack-trace@0.0.10", + "uuid": "npm:uuid@8.3.2" + }, + "tasks": { + "test": "deno test --no-check --allow-read=../../../" + }, + "fmt": { + "lineWidth": 160, + "useTabs": true, + "indentWidth": 4, + "singleQuote": true + } } diff --git a/packages/apps-engine/deno-runtime/error-handlers.ts b/packages/apps-engine/deno-runtime/error-handlers.ts index 1e042e0f2c625..e26a5ad6b2d86 100644 --- a/packages/apps-engine/deno-runtime/error-handlers.ts +++ b/packages/apps-engine/deno-runtime/error-handlers.ts @@ -1,33 +1,33 @@ import * as Messenger from './lib/messenger.ts'; export function unhandledRejectionListener(event: PromiseRejectionEvent) { - event.preventDefault(); + event.preventDefault(); - const { type, reason } = event; + const { type, reason } = event; - Messenger.sendNotification({ - method: 'unhandledRejection', - params: [ - { - type, - reason: reason instanceof Error ? reason.message : reason, - timestamp: new Date(), - }, - ], - }); + Messenger.sendNotification({ + method: 'unhandledRejection', + params: [ + { + type, + reason: reason instanceof Error ? reason.message : reason, + timestamp: new Date(), + }, + ], + }); } export function unhandledExceptionListener(event: ErrorEvent) { - event.preventDefault(); + event.preventDefault(); - const { type, message, filename, lineno, colno } = event; - Messenger.sendNotification({ - method: 'uncaughtException', - params: [{ type, message, filename, lineno, colno }], - }); + const { type, message, filename, lineno, colno } = event; + Messenger.sendNotification({ + method: 'uncaughtException', + params: [{ type, message, filename, lineno, colno }], + }); } export default function registerErrorListeners() { - addEventListener('unhandledrejection', unhandledRejectionListener); - addEventListener('error', unhandledExceptionListener); + addEventListener('unhandledrejection', unhandledRejectionListener); + addEventListener('error', unhandledExceptionListener); } diff --git a/packages/apps-engine/deno-runtime/handlers/api-handler.ts b/packages/apps-engine/deno-runtime/handlers/api-handler.ts index 32d30e532fd39..0b3c5c375b89b 100644 --- a/packages/apps-engine/deno-runtime/handlers/api-handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/api-handler.ts @@ -6,41 +6,41 @@ import { Logger } from '../lib/logger.ts'; import { AppAccessorsInstance } from '../lib/accessors/mod.ts'; export default async function apiHandler(call: string, params: unknown): Promise { - const [, path, httpMethod] = call.split(':'); + const [, path, httpMethod] = call.split(':'); - const endpoint = AppObjectRegistry.get(`api:${path}`); - const logger = AppObjectRegistry.get('logger'); + const endpoint = AppObjectRegistry.get(`api:${path}`); + const logger = AppObjectRegistry.get('logger'); - if (!endpoint) { - return new JsonRpcError(`Endpoint ${path} not found`, -32000); - } + if (!endpoint) { + return new JsonRpcError(`Endpoint ${path} not found`, -32000); + } - const method = endpoint[httpMethod as keyof IApiEndpoint]; + const method = endpoint[httpMethod as keyof IApiEndpoint]; - if (typeof method !== 'function') { - return new JsonRpcError(`${path}'s ${httpMethod} not exists`, -32000); - } + if (typeof method !== 'function') { + return new JsonRpcError(`${path}'s ${httpMethod} not exists`, -32000); + } - const [request, endpointInfo] = params as Array; + const [request, endpointInfo] = params as Array; - logger?.debug(`${path}'s ${call} is being executed...`, request); + logger?.debug(`${path}'s ${call} is being executed...`, request); - try { - // deno-lint-ignore ban-types - const result = await (method as Function).apply(endpoint, [ - request, - endpointInfo, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getModifier(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - ]); + try { + // deno-lint-ignore ban-types + const result = await (method as Function).apply(endpoint, [ + request, + endpointInfo, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getModifier(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + ]); - logger?.debug(`${path}'s ${call} was successfully executed.`); + logger?.debug(`${path}'s ${call} was successfully executed.`); - return result; - } catch (e) { - logger?.debug(`${path}'s ${call} was unsuccessful.`); - return new JsonRpcError(e.message || "Internal server error", -32000); - } + return result; + } catch (e) { + logger?.debug(`${path}'s ${call} was unsuccessful.`); + return new JsonRpcError(e.message || 'Internal server error', -32000); + } } diff --git a/packages/apps-engine/deno-runtime/handlers/app/construct.ts b/packages/apps-engine/deno-runtime/handlers/app/construct.ts index 798a83d0923c5..3dc71eb8422ea 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/construct.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/construct.ts @@ -9,17 +9,16 @@ import { Socket } from 'node:net'; const ALLOWED_NATIVE_MODULES = ['path', 'url', 'crypto', 'buffer', 'stream', 'net', 'http', 'https', 'zlib', 'util', 'punycode', 'os', 'querystring', 'fs']; const ALLOWED_EXTERNAL_MODULES = ['uuid']; - function prepareEnvironment() { - // Deno does not behave equally to Node when it comes to piping content to a socket - // So we intervene here - const originalFinal = Socket.prototype._final; - Socket.prototype._final = function _final(cb) { - // Deno closes the readable stream in the Socket earlier than Node - // The exact reason for that is yet unknown, so we'll need to simply delay the execution - // which allows data to be read in a response - setTimeout(() => originalFinal.call(this, cb), 1); - }; + // Deno does not behave equally to Node when it comes to piping content to a socket + // So we intervene here + const originalFinal = Socket.prototype._final; + Socket.prototype._final = function _final(cb) { + // Deno closes the readable stream in the Socket earlier than Node + // The exact reason for that is yet unknown, so we'll need to simply delay the execution + // which allows data to be read in a response + setTimeout(() => originalFinal.call(this, cb), 1); + }; } // As the apps are bundled, the only times they will call require are @@ -27,28 +26,28 @@ function prepareEnvironment() { // 2. To require external npm packages we may provide // 3. To require apps-engine files function buildRequire(): (module: string) => unknown { - return (module: string): unknown => { - if (ALLOWED_NATIVE_MODULES.includes(module)) { - return require(`node:${module}`); - } - - if (ALLOWED_EXTERNAL_MODULES.includes(module)) { - return require(`npm:${module}`); - } - - if (module.startsWith('@rocket.chat/apps-engine')) { - // Our `require` function knows how to handle these - return require(module); - } - - throw new Error(`Module ${module} is not allowed`); - }; + return (module: string): unknown => { + if (ALLOWED_NATIVE_MODULES.includes(module)) { + return require(`node:${module}`); + } + + if (ALLOWED_EXTERNAL_MODULES.includes(module)) { + return require(`npm:${module}`); + } + + if (module.startsWith('@rocket.chat/apps-engine')) { + // Our `require` function knows how to handle these + return require(module); + } + + throw new Error(`Module ${module} is not allowed`); + }; } function wrapAppCode(code: string): (require: (module: string) => unknown) => Promise> { - return new Function( - 'require', - ` + return new Function( + 'require', + ` const { Buffer } = require('buffer'); const exports = {}; const module = { exports }; @@ -66,61 +65,61 @@ function wrapAppCode(code: string): (require: (module: string) => unknown) => Pr })(exports,module,require,Buffer,_console,undefined,undefined); return result.then(() => module.exports);`, - ) as (require: (module: string) => unknown) => Promise>; + ) as (require: (module: string) => unknown) => Promise>; } export default async function handleConstructApp(params: unknown): Promise { - if (!Array.isArray(params)) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - const [appPackage] = params as [IParseAppPackageResult]; + const [appPackage] = params as [IParseAppPackageResult]; - if (!appPackage?.info?.id || !appPackage?.info?.classFile || !appPackage?.files) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!appPackage?.info?.id || !appPackage?.info?.classFile || !appPackage?.files) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - prepareEnvironment(); + prepareEnvironment(); - AppObjectRegistry.set('id', appPackage.info.id); - const source = sanitizeDeprecatedUsage(appPackage.files[appPackage.info.classFile]); + AppObjectRegistry.set('id', appPackage.info.id); + const source = sanitizeDeprecatedUsage(appPackage.files[appPackage.info.classFile]); - const require = buildRequire(); - const exports = await wrapAppCode(source)(require); + const require = buildRequire(); + const exports = await wrapAppCode(source)(require); - // This is the same naive logic we've been using in the App Compiler - // Applying the correct type here is quite difficult because of the dynamic nature of the code - // deno-lint-ignore no-explicit-any - const appClass = Object.values(exports)[0] as any; - const logger = AppObjectRegistry.get('logger'); + // This is the same naive logic we've been using in the App Compiler + // Applying the correct type here is quite difficult because of the dynamic nature of the code + // deno-lint-ignore no-explicit-any + const appClass = Object.values(exports)[0] as any; + const logger = AppObjectRegistry.get('logger'); - const app = new appClass(appPackage.info, logger, AppAccessorsInstance.getDefaultAppAccessors()); + const app = new appClass(appPackage.info, logger, AppAccessorsInstance.getDefaultAppAccessors()); - if (typeof app.getName !== 'function') { - throw new Error('App must contain a getName function'); - } + if (typeof app.getName !== 'function') { + throw new Error('App must contain a getName function'); + } - if (typeof app.getNameSlug !== 'function') { - throw new Error('App must contain a getNameSlug function'); - } + if (typeof app.getNameSlug !== 'function') { + throw new Error('App must contain a getNameSlug function'); + } - if (typeof app.getVersion !== 'function') { - throw new Error('App must contain a getVersion function'); - } + if (typeof app.getVersion !== 'function') { + throw new Error('App must contain a getVersion function'); + } - if (typeof app.getID !== 'function') { - throw new Error('App must contain a getID function'); - } + if (typeof app.getID !== 'function') { + throw new Error('App must contain a getID function'); + } - if (typeof app.getDescription !== 'function') { - throw new Error('App must contain a getDescription function'); - } + if (typeof app.getDescription !== 'function') { + throw new Error('App must contain a getDescription function'); + } - if (typeof app.getRequiredApiVersion !== 'function') { - throw new Error('App must contain a getRequiredApiVersion function'); - } + if (typeof app.getRequiredApiVersion !== 'function') { + throw new Error('App must contain a getRequiredApiVersion function'); + } - AppObjectRegistry.set('app', app); + AppObjectRegistry.set('app', app); - return true; + return true; } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts b/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts index 5428d989812e3..8bd454b98ca7f 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts @@ -3,13 +3,13 @@ import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; export default function handleGetStatus(): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.getStatus !== 'function') { - throw new Error('App must contain a getStatus function', { - cause: 'invalid_app', - }); - } + if (typeof app?.getStatus !== 'function') { + throw new Error('App must contain a getStatus function', { + cause: 'invalid_app', + }); + } - return app.getStatus(); + return app.getStatus(); } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts b/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts index ad90d3b01e250..e8d12ff47452e 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts @@ -4,16 +4,15 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default async function handleInitialize(): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.initialize !== 'function') { - throw new Error('App must contain an initialize function', { - cause: 'invalid_app', - }); - } + if (typeof app?.initialize !== 'function') { + throw new Error('App must contain an initialize function', { + cause: 'invalid_app', + }); + } - await app.initialize(AppAccessorsInstance.getConfigurationExtend(), AppAccessorsInstance.getEnvironmentRead()); + await app.initialize(AppAccessorsInstance.getConfigurationExtend(), AppAccessorsInstance.getEnvironmentRead()); - return true; + return true; } - diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts index e66c2414fd0ac..3e7d14b618793 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts @@ -4,16 +4,15 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default async function handleOnDisable(): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.onDisable !== 'function') { - throw new Error('App must contain an onDisable function', { - cause: 'invalid_app', - }); - } + if (typeof app?.onDisable !== 'function') { + throw new Error('App must contain an onDisable function', { + cause: 'invalid_app', + }); + } - await app.onDisable(AppAccessorsInstance.getConfigurationModify()); + await app.onDisable(AppAccessorsInstance.getConfigurationModify()); - return true; + return true; } - diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts index 1bdf84476422a..6bbdbbe7a575b 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts @@ -4,13 +4,13 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default function handleOnEnable(): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.onEnable !== 'function') { - throw new Error('App must contain an onEnable function', { - cause: 'invalid_app', - }); - } + if (typeof app?.onEnable !== 'function') { + throw new Error('App must contain an onEnable function', { + cause: 'invalid_app', + }); + } - return app.onEnable(AppAccessorsInstance.getEnvironmentRead(), AppAccessorsInstance.getConfigurationModify()); + return app.onEnable(AppAccessorsInstance.getEnvironmentRead(), AppAccessorsInstance.getConfigurationModify()); } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts index aebf7628a9145..95cb2be3f909f 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts @@ -4,27 +4,27 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default async function handleOnInstall(params: unknown): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.onInstall !== 'function') { - throw new Error('App must contain an onInstall function', { - cause: 'invalid_app', - }); - } + if (typeof app?.onInstall !== 'function') { + throw new Error('App must contain an onInstall function', { + cause: 'invalid_app', + }); + } - if (!Array.isArray(params)) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - const [context] = params as [Record]; + const [context] = params as [Record]; - await app.onInstall( - context, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - AppAccessorsInstance.getModifier(), - ); + await app.onInstall( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); - return true; + return true; } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts index 19646fa6704f1..8209a93791016 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts @@ -4,19 +4,19 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default function handleOnPreSettingUpdate(params: unknown): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.onPreSettingUpdate !== 'function') { - throw new Error('App must contain an onPreSettingUpdate function', { - cause: 'invalid_app', - }); - } + if (typeof app?.onPreSettingUpdate !== 'function') { + throw new Error('App must contain an onPreSettingUpdate function', { + cause: 'invalid_app', + }); + } - if (!Array.isArray(params)) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - const [setting] = params as [Record]; + const [setting] = params as [Record]; - return app.onPreSettingUpdate(setting, AppAccessorsInstance.getConfigurationModify(), AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()); + return app.onPreSettingUpdate(setting, AppAccessorsInstance.getConfigurationModify(), AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()); } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts index 07084bc22425f..16150be39be24 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts @@ -4,21 +4,21 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default async function handleOnSettingUpdated(params: unknown): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.onSettingUpdated !== 'function') { - throw new Error('App must contain an onSettingUpdated function', { - cause: 'invalid_app', - }); - } + if (typeof app?.onSettingUpdated !== 'function') { + throw new Error('App must contain an onSettingUpdated function', { + cause: 'invalid_app', + }); + } - if (!Array.isArray(params)) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - const [setting] = params as [Record]; + const [setting] = params as [Record]; - await app.onSettingUpdated(setting, AppAccessorsInstance.getConfigurationModify(), AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()); + await app.onSettingUpdated(setting, AppAccessorsInstance.getConfigurationModify(), AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()); - return true; + return true; } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts index 865819728ca4c..cb7e50c4f0b67 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts @@ -4,27 +4,27 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export default async function handleOnUninstall(params: unknown): Promise { - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (typeof app?.onUninstall !== 'function') { - throw new Error('App must contain an onUninstall function', { - cause: 'invalid_app', - }); - } + if (typeof app?.onUninstall !== 'function') { + throw new Error('App must contain an onUninstall function', { + cause: 'invalid_app', + }); + } - if (!Array.isArray(params)) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - const [context] = params as [Record]; + const [context] = params as [Record]; - await app.onUninstall( - context, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - AppAccessorsInstance.getModifier(), - ); + await app.onUninstall( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); - return true; + return true; } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts index f21e4f947d5d9..2f27247d8af88 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts @@ -1,30 +1,30 @@ -import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; - -import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; -import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; - -export default async function handleOnUpdate(params: unknown): Promise { - const app = AppObjectRegistry.get('app'); - - if (typeof app?.onUpdate !== 'function') { - throw new Error('App must contain an onUpdate function', { - cause: 'invalid_app', - }); - } - - if (!Array.isArray(params)) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } - - const [context] = params as [Record]; - - await app.onUpdate( - context, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - AppAccessorsInstance.getModifier(), - ); - - return true; -} +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleOnUpdate(params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onUpdate !== 'function') { + throw new Error('App must contain an onUpdate function', { + cause: 'invalid_app', + }); + } + + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [context] = params as [Record]; + + await app.onUpdate( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); + + return true; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts b/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts index c39ab2a16d62d..d95f4f17e1c7a 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts @@ -5,25 +5,25 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { require } from '../../lib/require.ts'; const { AppStatus } = require('@rocket.chat/apps-engine/definition/AppStatus.js') as { - AppStatus: typeof _AppStatus; + AppStatus: typeof _AppStatus; }; export default async function handleSetStatus(params: unknown): Promise { - if (!Array.isArray(params) || !Object.values(AppStatus).includes(params[0])) { - throw new Error('Invalid params', { cause: 'invalid_param_type' }); - } + if (!Array.isArray(params) || !Object.values(AppStatus).includes(params[0])) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } - const [status] = params as [typeof AppStatus]; + const [status] = params as [typeof AppStatus]; - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (!app || typeof app['setStatus'] !== 'function') { - throw new Error('App must contain a setStatus function', { - cause: 'invalid_app', - }); - } + if (!app || typeof app['setStatus'] !== 'function') { + throw new Error('App must contain a setStatus function', { + cause: 'invalid_app', + }); + } - await app['setStatus'](status); + await app['setStatus'](status); - return null; + return null; } diff --git a/packages/apps-engine/deno-runtime/handlers/app/handler.ts b/packages/apps-engine/deno-runtime/handlers/app/handler.ts index 141e145df9719..4193e7e948b47 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handler.ts @@ -17,96 +17,96 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import handleOnUpdate from './handleOnUpdate.ts'; export default async function handleApp(method: string, params: unknown): Promise { - const [, appMethod] = method.split(':'); - - try { - // We don't want the getStatus method to generate logs, so we handle it separately - if (appMethod === 'getStatus') { - return await handleGetStatus(); - } - - // `app` will be undefined if the method here is "app:construct" - const app = AppObjectRegistry.get('app'); - - app?.getLogger().debug(`'${appMethod}' is being called...`); - - if (uikitInteractions.includes(appMethod)) { - return handleUIKitInteraction(appMethod, params).then((result) => { - if (result instanceof JsonRpcError) { - app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); - } else { - app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); - } - - return result; - }); - } - - if (appMethod.startsWith('check') || appMethod.startsWith('execute')) { - return handleListener(appMethod, params).then((result) => { - if (result instanceof JsonRpcError) { - app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); - } else { - app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); - } - - return result; - }); - } - - let result: Defined | JsonRpcError; - - switch (appMethod) { - case 'construct': - result = await handleConstructApp(params); - break; - case 'initialize': - result = await handleInitialize(); - break; - case 'setStatus': - result = await handleSetStatus(params); - break; - case 'onEnable': - result = await handleOnEnable(); - break; - case 'onDisable': - result = await handleOnDisable(); - break; - case 'onInstall': - result = await handleOnInstall(params); - break; - case 'onUninstall': - result = await handleOnUninstall(params); - break; - case 'onPreSettingUpdate': - result = await handleOnPreSettingUpdate(params); - break; - case 'onSettingUpdated': - result = await handleOnSettingUpdated(params); - break; - case 'onUpdate': - result = await handleOnUpdate(params); - break; - default: - throw new JsonRpcError('Method not found', -32601); - } - - app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); - - return result; - } catch (e: unknown) { - if (!(e instanceof Error)) { - return new JsonRpcError('Unknown error', -32000, e); - } - - if ((e.cause as string)?.includes('invalid_param_type')) { - return JsonRpcError.invalidParams(null); - } - - if ((e.cause as string)?.includes('invalid_app')) { - return JsonRpcError.internalError({ message: 'App unavailable' }); - } - - return new JsonRpcError(e.message, -32000, e); - } + const [, appMethod] = method.split(':'); + + try { + // We don't want the getStatus method to generate logs, so we handle it separately + if (appMethod === 'getStatus') { + return await handleGetStatus(); + } + + // `app` will be undefined if the method here is "app:construct" + const app = AppObjectRegistry.get('app'); + + app?.getLogger().debug(`'${appMethod}' is being called...`); + + if (uikitInteractions.includes(appMethod)) { + return handleUIKitInteraction(appMethod, params).then((result) => { + if (result instanceof JsonRpcError) { + app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); + } else { + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + } + + return result; + }); + } + + if (appMethod.startsWith('check') || appMethod.startsWith('execute')) { + return handleListener(appMethod, params).then((result) => { + if (result instanceof JsonRpcError) { + app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); + } else { + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + } + + return result; + }); + } + + let result: Defined | JsonRpcError; + + switch (appMethod) { + case 'construct': + result = await handleConstructApp(params); + break; + case 'initialize': + result = await handleInitialize(); + break; + case 'setStatus': + result = await handleSetStatus(params); + break; + case 'onEnable': + result = await handleOnEnable(); + break; + case 'onDisable': + result = await handleOnDisable(); + break; + case 'onInstall': + result = await handleOnInstall(params); + break; + case 'onUninstall': + result = await handleOnUninstall(params); + break; + case 'onPreSettingUpdate': + result = await handleOnPreSettingUpdate(params); + break; + case 'onSettingUpdated': + result = await handleOnSettingUpdated(params); + break; + case 'onUpdate': + result = await handleOnUpdate(params); + break; + default: + throw new JsonRpcError('Method not found', -32601); + } + + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + + return result; + } catch (e: unknown) { + if (!(e instanceof Error)) { + return new JsonRpcError('Unknown error', -32000, e); + } + + if ((e.cause as string)?.includes('invalid_param_type')) { + return JsonRpcError.invalidParams(null); + } + + if ((e.cause as string)?.includes('invalid_app')) { + return JsonRpcError.internalError({ message: 'App unavailable' }); + } + + return new JsonRpcError(e.message, -32000, e); + } } diff --git a/packages/apps-engine/deno-runtime/handlers/listener/handler.ts b/packages/apps-engine/deno-runtime/handlers/listener/handler.ts index 1e6de20538fc0..df6fc81a188db 100644 --- a/packages/apps-engine/deno-runtime/handlers/listener/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/listener/handler.ts @@ -12,116 +12,115 @@ import { RoomBuilder } from '../../lib/accessors/builders/RoomBuilder.ts'; import { AppAccessors, AppAccessorsInstance } from '../../lib/accessors/mod.ts'; import { require } from '../../lib/require.ts'; import createRoom from '../../lib/roomFactory.ts'; -import { Room } from "../../lib/room.ts"; +import { Room } from '../../lib/room.ts'; const { AppsEngineException } = require('@rocket.chat/apps-engine/definition/exceptions/AppsEngineException.js') as { - AppsEngineException: typeof _AppsEngineException; + AppsEngineException: typeof _AppsEngineException; }; export default async function handleListener(evtInterface: string, params: unknown): Promise { - const app = AppObjectRegistry.get('app'); - - const eventExecutor = app?.[evtInterface as keyof App]; - - if (typeof eventExecutor !== 'function') { - return JsonRpcError.methodNotFound({ - message: 'Invalid event interface called on app', - }); - } - - if (!Array.isArray(params) || params.length < 1 || params.length > 2) { - return JsonRpcError.invalidParams(null); - } - - try { - const args = parseArgs({ AppAccessorsInstance }, evtInterface, params); - return await (eventExecutor as (...args: unknown[]) => Promise).apply(app, args); - } catch (e) { - if (e instanceof JsonRpcError) { - return e; - } - - if (e instanceof AppsEngineException) { - return new JsonRpcError(e.message, AppsEngineException.JSONRPC_ERROR_CODE, { name: e.name }); - } - - return JsonRpcError.internalError({ message: e.message }); - } - + const app = AppObjectRegistry.get('app'); + + const eventExecutor = app?.[evtInterface as keyof App]; + + if (typeof eventExecutor !== 'function') { + return JsonRpcError.methodNotFound({ + message: 'Invalid event interface called on app', + }); + } + + if (!Array.isArray(params) || params.length < 1 || params.length > 2) { + return JsonRpcError.invalidParams(null); + } + + try { + const args = parseArgs({ AppAccessorsInstance }, evtInterface, params); + return await (eventExecutor as (...args: unknown[]) => Promise).apply(app, args); + } catch (e) { + if (e instanceof JsonRpcError) { + return e; + } + + if (e instanceof AppsEngineException) { + return new JsonRpcError(e.message, AppsEngineException.JSONRPC_ERROR_CODE, { name: e.name }); + } + + return JsonRpcError.internalError({ message: e.message }); + } } export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMethod: string, params: unknown[]): unknown[] { - const { AppAccessorsInstance } = deps; - /** - * param1 is the context for the event handler execution - * param2 is an optional extra content that some hanlers require - */ - const [param1, param2] = params as [unknown, unknown]; - - if (!param1) { - throw JsonRpcError.invalidParams(null); - } - - let context = param1; - - if (evtMethod.includes('Message')) { - context = hydrateMessageObjects(context) as Record; - } else if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) { - (context as Record).room = createRoom((context as Record).room as IRoom, AppAccessorsInstance.getSenderFn()); - } else if (evtMethod.includes('PreRoom')) { - context = createRoom(context as IRoom, AppAccessorsInstance.getSenderFn()); - } - - const args: unknown[] = [context, AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()]; - - // "check" events will only go this far - (context, reader, http) - if (evtMethod.startsWith('check')) { - // "checkPostMessageDeleted" has an extra param - (context, reader, http, extraContext) - if (param2) { - args.push(hydrateMessageObjects(param2)); - } - - return args; - } - - // From this point on, all events will require (reader, http, persistence) injected - args.push(AppAccessorsInstance.getPersistence()); - - // "extend" events have an additional "Extender" param - (context, extender, reader, http, persistence) - if (evtMethod.endsWith('Extend')) { - if (evtMethod.includes('Message')) { - args.splice(1, 0, new MessageExtender(param1 as IMessage)); - } else if (evtMethod.includes('Room')) { - args.splice(1, 0, new RoomExtender(param1 as IRoom)); - } - - return args; - } - - // "Modify" events have an additional "Builder" param - (context, builder, reader, http, persistence) - if (evtMethod.endsWith('Modify')) { - if (evtMethod.includes('Message')) { - args.splice(1, 0, new MessageBuilder(param1 as IMessage)); - } else if (evtMethod.includes('Room')) { - args.splice(1, 0, new RoomBuilder(param1 as IRoom)); - } - - return args; - } - - // From this point on, all events will require (reader, http, persistence, modifier) injected - args.push(AppAccessorsInstance.getModifier()); - - // This guy gets an extra one - if (evtMethod === 'executePostMessageDeleted') { - if (!param2) { - throw JsonRpcError.invalidParams(null); - } - - args.push(hydrateMessageObjects(param2)); - } - - return args; + const { AppAccessorsInstance } = deps; + /** + * param1 is the context for the event handler execution + * param2 is an optional extra content that some hanlers require + */ + const [param1, param2] = params as [unknown, unknown]; + + if (!param1) { + throw JsonRpcError.invalidParams(null); + } + + let context = param1; + + if (evtMethod.includes('Message')) { + context = hydrateMessageObjects(context) as Record; + } else if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) { + (context as Record).room = createRoom((context as Record).room as IRoom, AppAccessorsInstance.getSenderFn()); + } else if (evtMethod.includes('PreRoom')) { + context = createRoom(context as IRoom, AppAccessorsInstance.getSenderFn()); + } + + const args: unknown[] = [context, AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()]; + + // "check" events will only go this far - (context, reader, http) + if (evtMethod.startsWith('check')) { + // "checkPostMessageDeleted" has an extra param - (context, reader, http, extraContext) + if (param2) { + args.push(hydrateMessageObjects(param2)); + } + + return args; + } + + // From this point on, all events will require (reader, http, persistence) injected + args.push(AppAccessorsInstance.getPersistence()); + + // "extend" events have an additional "Extender" param - (context, extender, reader, http, persistence) + if (evtMethod.endsWith('Extend')) { + if (evtMethod.includes('Message')) { + args.splice(1, 0, new MessageExtender(param1 as IMessage)); + } else if (evtMethod.includes('Room')) { + args.splice(1, 0, new RoomExtender(param1 as IRoom)); + } + + return args; + } + + // "Modify" events have an additional "Builder" param - (context, builder, reader, http, persistence) + if (evtMethod.endsWith('Modify')) { + if (evtMethod.includes('Message')) { + args.splice(1, 0, new MessageBuilder(param1 as IMessage)); + } else if (evtMethod.includes('Room')) { + args.splice(1, 0, new RoomBuilder(param1 as IRoom)); + } + + return args; + } + + // From this point on, all events will require (reader, http, persistence, modifier) injected + args.push(AppAccessorsInstance.getModifier()); + + // This guy gets an extra one + if (evtMethod === 'executePostMessageDeleted') { + if (!param2) { + throw JsonRpcError.invalidParams(null); + } + + args.push(hydrateMessageObjects(param2)); + } + + return args; } /** @@ -131,20 +130,20 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho * so here we hydrate the complete object as necessary */ function hydrateMessageObjects(context: unknown): unknown { - if (objectIsRawMessage(context)) { - context.room = createRoom(context.room as IRoom, AppAccessorsInstance.getSenderFn()); - } else if ((context as Record)?.message) { - (context as Record).message = hydrateMessageObjects((context as Record).message); - } + if (objectIsRawMessage(context)) { + context.room = createRoom(context.room as IRoom, AppAccessorsInstance.getSenderFn()); + } else if ((context as Record)?.message) { + (context as Record).message = hydrateMessageObjects((context as Record).message); + } - return context; + return context; } function objectIsRawMessage(value: unknown): value is IMessage { - if (!value) return false; + if (!value) return false; - const { id, room, sender, createdAt } = value as Record; + const { id, room, sender, createdAt } = value as Record; - // Check if we have the fields of a message and the room hasn't already been hydrated - return !!(id && room && sender && createdAt) && !(room instanceof Room); + // Check if we have the fields of a message and the room hasn't already been hydrated + return !!(id && room && sender && createdAt) && !(room instanceof Room); } diff --git a/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts b/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts index 0145034957f2d..2df1eb564017b 100644 --- a/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts @@ -6,46 +6,46 @@ import { AppObjectRegistry } from '../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../lib/accessors/mod.ts'; export default async function handleScheduler(method: string, params: unknown): Promise { - const [, processorId] = method.split(':'); - if (!Array.isArray(params)) { - return JsonRpcError.invalidParams({ message: 'Invalid params' }); - } + const [, processorId] = method.split(':'); + if (!Array.isArray(params)) { + return JsonRpcError.invalidParams({ message: 'Invalid params' }); + } - const [context] = params as [Record]; + const [context] = params as [Record]; - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (!app) { - return JsonRpcError.internalError({ message: 'App not found' }); - } + if (!app) { + return JsonRpcError.internalError({ message: 'App not found' }); + } - // AppSchedulerManager will append the appId to the processor name to avoid conflicts - const processor = AppObjectRegistry.get(`scheduler:${processorId}`); + // AppSchedulerManager will append the appId to the processor name to avoid conflicts + const processor = AppObjectRegistry.get(`scheduler:${processorId}`); - if (!processor) { - return JsonRpcError.methodNotFound({ - message: `Could not find processor for method ${method}`, - }); - } + if (!processor) { + return JsonRpcError.methodNotFound({ + message: `Could not find processor for method ${method}`, + }); + } - app.getLogger().debug(`Job processor ${processor.id} is being executed...`); + app.getLogger().debug(`Job processor ${processor.id} is being executed...`); - try { - await processor.processor( - context, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getModifier(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - ); + try { + await processor.processor( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getModifier(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + ); - app.getLogger().debug(`Job processor ${processor.id} was successfully executed`); + app.getLogger().debug(`Job processor ${processor.id} was successfully executed`); - return null; - } catch (e) { - app.getLogger().error(e); - app.getLogger().error(`Job processor ${processor.id} was unsuccessful`); + return null; + } catch (e) { + app.getLogger().error(e); + app.getLogger().error(`Job processor ${processor.id} was unsuccessful`); - return JsonRpcError.internalError({ message: e.message }); - } + return JsonRpcError.internalError({ message: e.message }); + } } diff --git a/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts b/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts index cfebf0d1460eb..51e00fa0142d1 100644 --- a/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts @@ -1,6 +1,6 @@ import { Defined, JsonRpcError } from 'jsonrpc-lite'; -import type { App } from "@rocket.chat/apps-engine/definition/App.ts"; +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands/ISlashCommand.ts'; import type { SlashCommandContext as _SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands/SlashCommandContext.ts'; @@ -13,42 +13,42 @@ import createRoom from '../lib/roomFactory.ts'; // For some reason Deno couldn't understand the typecast to the original interfaces and said it wasn't a constructor type const { SlashCommandContext } = require('@rocket.chat/apps-engine/definition/slashcommands/SlashCommandContext.js') as { - SlashCommandContext: typeof _SlashCommandContext; + SlashCommandContext: typeof _SlashCommandContext; }; export default async function slashCommandHandler(call: string, params: unknown): Promise { - const [, commandName, method] = call.split(':'); + const [, commandName, method] = call.split(':'); - const command = AppObjectRegistry.get(`slashcommand:${commandName}`); + const command = AppObjectRegistry.get(`slashcommand:${commandName}`); - if (!command) { - return new JsonRpcError(`Slashcommand ${commandName} not found`, -32000); - } + if (!command) { + return new JsonRpcError(`Slashcommand ${commandName} not found`, -32000); + } - let result: Awaited> | Awaited>; + let result: Awaited> | Awaited>; - // If the command is registered, we're pretty safe to assume the app is not undefined - const app = AppObjectRegistry.get('app')!; + // If the command is registered, we're pretty safe to assume the app is not undefined + const app = AppObjectRegistry.get('app')!; - app.getLogger().debug(`${commandName}'s ${method} is being executed...`, params); + app.getLogger().debug(`${commandName}'s ${method} is being executed...`, params); - try { - if (method === 'executor' || method === 'previewer') { - result = await handleExecutor({ AppAccessorsInstance }, command, method, params); - } else if (method === 'executePreviewItem') { - result = await handlePreviewItem({ AppAccessorsInstance }, command, params); - } else { - return new JsonRpcError(`Method ${method} not found on slashcommand ${commandName}`, -32000); - } + try { + if (method === 'executor' || method === 'previewer') { + result = await handleExecutor({ AppAccessorsInstance }, command, method, params); + } else if (method === 'executePreviewItem') { + result = await handlePreviewItem({ AppAccessorsInstance }, command, params); + } else { + return new JsonRpcError(`Method ${method} not found on slashcommand ${commandName}`, -32000); + } - app.getLogger().debug(`${commandName}'s ${method} was successfully executed.`); - } catch (error) { - app.getLogger().debug(`${commandName}'s ${method} was unsuccessful.`); + app.getLogger().debug(`${commandName}'s ${method} was successfully executed.`); + } catch (error) { + app.getLogger().debug(`${commandName}'s ${method} was unsuccessful.`); - return new JsonRpcError(error.message, -32000); - } + return new JsonRpcError(error.message, -32000); + } - return result; + return result; } /** @@ -58,33 +58,33 @@ export default async function slashCommandHandler(call: string, params: unknown) * @param params The parameters that are being passed to the method */ export function handleExecutor(deps: { AppAccessorsInstance: AppAccessors }, command: ISlashCommand, method: 'executor' | 'previewer', params: unknown) { - const executor = command[method]; - - if (typeof executor !== 'function') { - throw new Error(`Method ${method} not found on slashcommand ${command.command}`); - } - - if (!Array.isArray(params) || typeof params[0] !== 'object' || !params[0]) { - throw new Error(`First parameter must be an object`); - } - - const { sender, room, params: args, threadId, triggerId } = params[0] as Record; - - const context = new SlashCommandContext( - sender as _SlashCommandContext['sender'], - createRoom(room as IRoom, deps.AppAccessorsInstance.getSenderFn()), - args as _SlashCommandContext['params'], - threadId as _SlashCommandContext['threadId'], - triggerId as _SlashCommandContext['triggerId'], - ); - - return executor.apply(command, [ - context, - deps.AppAccessorsInstance.getReader(), - deps.AppAccessorsInstance.getModifier(), - deps.AppAccessorsInstance.getHttp(), - deps.AppAccessorsInstance.getPersistence(), - ]); + const executor = command[method]; + + if (typeof executor !== 'function') { + throw new Error(`Method ${method} not found on slashcommand ${command.command}`); + } + + if (!Array.isArray(params) || typeof params[0] !== 'object' || !params[0]) { + throw new Error(`First parameter must be an object`); + } + + const { sender, room, params: args, threadId, triggerId } = params[0] as Record; + + const context = new SlashCommandContext( + sender as _SlashCommandContext['sender'], + createRoom(room as IRoom, deps.AppAccessorsInstance.getSenderFn()), + args as _SlashCommandContext['params'], + threadId as _SlashCommandContext['threadId'], + triggerId as _SlashCommandContext['triggerId'], + ); + + return executor.apply(command, [ + context, + deps.AppAccessorsInstance.getReader(), + deps.AppAccessorsInstance.getModifier(), + deps.AppAccessorsInstance.getHttp(), + deps.AppAccessorsInstance.getPersistence(), + ]); } /** @@ -93,30 +93,30 @@ export function handleExecutor(deps: { AppAccessorsInstance: AppAccessors }, com * @param params The parameters that are being passed to the method */ export function handlePreviewItem(deps: { AppAccessorsInstance: AppAccessors }, command: ISlashCommand, params: unknown) { - if (typeof command.executePreviewItem !== 'function') { - throw new Error(`Method not found on slashcommand ${command.command}`); - } - - if (!Array.isArray(params) || typeof params[0] !== 'object' || !params[0]) { - throw new Error(`First parameter must be an object`); - } - - const [previewItem, { sender, room, params: args, threadId, triggerId }] = params as [Record, Record]; - - const context = new SlashCommandContext( - sender as _SlashCommandContext['sender'], - createRoom(room as IRoom, deps.AppAccessorsInstance.getSenderFn()), - args as _SlashCommandContext['params'], - threadId as _SlashCommandContext['threadId'], - triggerId as _SlashCommandContext['triggerId'], - ); - - return command.executePreviewItem( - previewItem, - context, - deps.AppAccessorsInstance.getReader(), - deps.AppAccessorsInstance.getModifier(), - deps.AppAccessorsInstance.getHttp(), - deps.AppAccessorsInstance.getPersistence(), - ); + if (typeof command.executePreviewItem !== 'function') { + throw new Error(`Method not found on slashcommand ${command.command}`); + } + + if (!Array.isArray(params) || typeof params[0] !== 'object' || !params[0]) { + throw new Error(`First parameter must be an object`); + } + + const [previewItem, { sender, room, params: args, threadId, triggerId }] = params as [Record, Record]; + + const context = new SlashCommandContext( + sender as _SlashCommandContext['sender'], + createRoom(room as IRoom, deps.AppAccessorsInstance.getSenderFn()), + args as _SlashCommandContext['params'], + threadId as _SlashCommandContext['threadId'], + triggerId as _SlashCommandContext['triggerId'], + ); + + return command.executePreviewItem( + previewItem, + context, + deps.AppAccessorsInstance.getReader(), + deps.AppAccessorsInstance.getModifier(), + deps.AppAccessorsInstance.getHttp(), + deps.AppAccessorsInstance.getPersistence(), + ); } diff --git a/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts index a3789f755542e..0212fcea3a541 100644 --- a/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts +++ b/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts @@ -1,79 +1,81 @@ // deno-lint-ignore-file no-explicit-any import { assertEquals, assertObjectMatch } from 'https://deno.land/std@0.203.0/assert/mod.ts'; import { beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; -import { spy } from "https://deno.land/std@0.203.0/testing/mock.ts"; +import { spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; -import { assertInstanceOf } from "https://deno.land/std@0.203.0/assert/assert_instance_of.ts"; -import { JsonRpcError } from "jsonrpc-lite"; -import type { IApiEndpoint } from "@rocket.chat/apps-engine/definition/api/IApiEndpoint.ts"; -import apiHandler from "../api-handler.ts"; +import { assertInstanceOf } from 'https://deno.land/std@0.203.0/assert/assert_instance_of.ts'; +import { JsonRpcError } from 'jsonrpc-lite'; +import type { IApiEndpoint } from '@rocket.chat/apps-engine/definition/api/IApiEndpoint.ts'; +import apiHandler from '../api-handler.ts'; describe('handlers > api', () => { - const mockEndpoint: IApiEndpoint = { - path: '/test', - // deno-lint-ignore no-unused-vars - get: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => Promise.resolve('ok'), - // deno-lint-ignore no-unused-vars - post: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => Promise.resolve('ok'), - // deno-lint-ignore no-unused-vars - put: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => { throw new Error('Method execution error example') }, - } + const mockEndpoint: IApiEndpoint = { + path: '/test', + // deno-lint-ignore no-unused-vars + get: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => Promise.resolve('ok'), + // deno-lint-ignore no-unused-vars + post: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => Promise.resolve('ok'), + // deno-lint-ignore no-unused-vars + put: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => { + throw new Error('Method execution error example'); + }, + }; - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('api:/test', mockEndpoint); - }); + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('api:/test', mockEndpoint); + }); - it('correctly handles execution of an api endpoint method GET', async () => { - const _spy = spy(mockEndpoint, 'get'); - - const result = await apiHandler('api:/test:get', ['request', 'endpointInfo']); + it('correctly handles execution of an api endpoint method GET', async () => { + const _spy = spy(mockEndpoint, 'get'); - assertEquals(result, 'ok'); - assertEquals(_spy.calls[0].args.length, 6); - assertEquals(_spy.calls[0].args[0], 'request'); - assertEquals(_spy.calls[0].args[1], 'endpointInfo'); - }); + const result = await apiHandler('api:/test:get', ['request', 'endpointInfo']); - it('correctly handles execution of an api endpoint method POST', async () => { - const _spy = spy(mockEndpoint, 'post'); - - const result = await apiHandler('api:/test:post', ['request', 'endpointInfo']); + assertEquals(result, 'ok'); + assertEquals(_spy.calls[0].args.length, 6); + assertEquals(_spy.calls[0].args[0], 'request'); + assertEquals(_spy.calls[0].args[1], 'endpointInfo'); + }); - assertEquals(result, 'ok'); - assertEquals(_spy.calls[0].args.length, 6); - assertEquals(_spy.calls[0].args[0], 'request'); - assertEquals(_spy.calls[0].args[1], 'endpointInfo'); - }); + it('correctly handles execution of an api endpoint method POST', async () => { + const _spy = spy(mockEndpoint, 'post'); - it('correctly handles an error if the method not exists for the selected endpoint', async () => { - const result = await apiHandler(`api:/test:delete`, ['request', 'endpointInfo']); + const result = await apiHandler('api:/test:post', ['request', 'endpointInfo']); - assertInstanceOf(result, JsonRpcError) - assertObjectMatch(result, { - message: `/test's delete not exists`, - code: -32000 - }) - }); + assertEquals(result, 'ok'); + assertEquals(_spy.calls[0].args.length, 6); + assertEquals(_spy.calls[0].args[0], 'request'); + assertEquals(_spy.calls[0].args[1], 'endpointInfo'); + }); - it('correctly handles an error if endpoint not exists', async () => { - const result = await apiHandler(`api:/error:get`, ['request', 'endpointInfo']); + it('correctly handles an error if the method not exists for the selected endpoint', async () => { + const result = await apiHandler(`api:/test:delete`, ['request', 'endpointInfo']); - assertInstanceOf(result, JsonRpcError) - assertObjectMatch(result, { - message: `Endpoint /error not found`, - code: -32000 - }) - }); + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: `/test's delete not exists`, + code: -32000, + }); + }); - it('correctly handles an error if the method execution fails', async () => { - const result = await apiHandler(`api:/test:put`, ['request', 'endpointInfo']); + it('correctly handles an error if endpoint not exists', async () => { + const result = await apiHandler(`api:/error:get`, ['request', 'endpointInfo']); - assertInstanceOf(result, JsonRpcError) - assertObjectMatch(result, { - message: `Method execution error example`, - code: -32000 - }) - }); + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: `Endpoint /error not found`, + code: -32000, + }); + }); + + it('correctly handles an error if the method execution fails', async () => { + const result = await apiHandler(`api:/test:put`, ['request', 'endpointInfo']); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: `Method execution error example`, + code: -32000, + }); + }); }); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts index 3e3663b06d225..8e355f6ac4d3d 100644 --- a/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts +++ b/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts @@ -11,224 +11,224 @@ import { MessageBuilder } from '../../lib/accessors/builders/MessageBuilder.ts'; import { RoomBuilder } from '../../lib/accessors/builders/RoomBuilder.ts'; describe('handlers > listeners', () => { - const mockAppAccessors = { - getReader: () => ({ __type: 'reader' }), - getHttp: () => ({ __type: 'http' }), - getModifier: () => ({ __type: 'modifier' }), - getPersistence: () => ({ __type: 'persistence' }), - getSenderFn: () => (id: string) => Promise.resolve([{ __type: 'bridgeCall' }, { id }]), - } as unknown as AppAccessors; - - it('correctly parses the arguments for a request to trigger the "checkPreMessageSentPrevent" method', () => { - const evtMethod = 'checkPreMessageSentPrevent'; - // For the 'checkPreMessageSentPrevent' method, the context will be a message in a real scenario - const evtArgs = [{ __type: 'context' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 3); - assertEquals(params[0], { __type: 'context' }); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - }); - - it('correctly parses the arguments for a request to trigger the "checkPostMessageDeleted" method', () => { - const evtMethod = 'checkPostMessageDeleted'; - // For the 'checkPostMessageDeleted' method, the context will be a message in a real scenario, - // and the extraContext will provide further information such the user who deleted the message - const evtArgs = [{ __type: 'context' }, { __type: 'extraContext' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 4); - assertEquals(params[0], { __type: 'context' }); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - assertEquals(params[3], { __type: 'extraContext' }); - }); - - it('correctly parses the arguments for a request to trigger the "checkPreRoomCreateExtend" method', () => { - const evtMethod = 'checkPreRoomCreateExtend'; - // For the 'checkPreRoomCreateExtend' method, the context will be a room in a real scenario - const evtArgs = [ - { - id: 'fake', - type: 'fake', - slugifiedName: 'fake', - creator: 'fake', - createdAt: Date.now(), - }, - ]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 3); - - assertInstanceOf(params[0], Room); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePreMessageSentExtend" method', () => { - const evtMethod = 'executePreMessageSentExtend'; - // For the 'executePreMessageSentExtend' method, the context will be a message in a real scenario - const evtArgs = [{ __type: 'context' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - // Instantiating the MessageExtender might modify the original object, so we need to assert it matches instead of equals - assertObjectMatch(params[0] as Record, { - __type: 'context', - }); - assertInstanceOf(params[1], MessageExtender); - assertEquals(params[2], { __type: 'reader' }); - assertEquals(params[3], { __type: 'http' }); - assertEquals(params[4], { __type: 'persistence' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePreRoomCreateExtend" method', () => { - const evtMethod = 'executePreRoomCreateExtend'; - // For the 'executePreRoomCreateExtend' method, the context will be a room in a real scenario - const evtArgs = [{ __type: 'context' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - // Instantiating the RoomExtender might modify the original object, so we need to assert it matches instead of equals - assertObjectMatch(params[0] as Record, { - __type: 'context', - }); - assertInstanceOf(params[1], RoomExtender); - assertEquals(params[2], { __type: 'reader' }); - assertEquals(params[3], { __type: 'http' }); - assertEquals(params[4], { __type: 'persistence' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePreMessageSentModify" method', () => { - const evtMethod = 'executePreMessageSentModify'; - // For the 'executePreMessageSentModify' method, the context will be a message in a real scenario - const evtArgs = [{ __type: 'context' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - // Instantiating the MessageBuilder might modify the original object, so we need to assert it matches instead of equals - assertObjectMatch(params[0] as Record, { - __type: 'context', - }); - assertInstanceOf(params[1], MessageBuilder); - assertEquals(params[2], { __type: 'reader' }); - assertEquals(params[3], { __type: 'http' }); - assertEquals(params[4], { __type: 'persistence' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePreRoomCreateModify" method', () => { - const evtMethod = 'executePreRoomCreateModify'; - // For the 'executePreRoomCreateModify' method, the context will be a room in a real scenario - const evtArgs = [{ __type: 'context' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - // Instantiating the RoomBuilder might modify the original object, so we need to assert it matches instead of equals - assertObjectMatch(params[0] as Record, { - __type: 'context', - }); - assertInstanceOf(params[1], RoomBuilder); - assertEquals(params[2], { __type: 'reader' }); - assertEquals(params[3], { __type: 'http' }); - assertEquals(params[4], { __type: 'persistence' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePostRoomUserJoined" method', () => { - const evtMethod = 'executePostRoomUserJoined'; - // For the 'executePostRoomUserJoined' method, the context will be a room in a real scenario - const room = { - id: 'fake', - type: 'fake', - slugifiedName: 'fake', - creator: 'fake', - createdAt: Date.now(), - }; - - const evtArgs = [{ __type: 'context', room }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - assertInstanceOf((params[0] as any).room, Room); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - assertEquals(params[3], { __type: 'persistence' }); - assertEquals(params[4], { __type: 'modifier' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePostRoomUserLeave" method', () => { - const evtMethod = 'executePostRoomUserLeave'; - // For the 'executePostRoomUserLeave' method, the context will be a room in a real scenario - const room = { - id: 'fake', - type: 'fake', - slugifiedName: 'fake', - creator: 'fake', - createdAt: Date.now(), - }; - - const evtArgs = [{ __type: 'context', room }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - assertInstanceOf((params[0] as any).room, Room); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - assertEquals(params[3], { __type: 'persistence' }); - assertEquals(params[4], { __type: 'modifier' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePostMessageDeleted" method', () => { - const evtMethod = 'executePostMessageDeleted'; - // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario - const evtArgs = [{ __type: 'context' }, { __type: 'extraContext' }]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 6); - assertEquals(params[0], { __type: 'context' }); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - assertEquals(params[3], { __type: 'persistence' }); - assertEquals(params[4], { __type: 'modifier' }); - assertEquals(params[5], { __type: 'extraContext' }); - }); - - it('correctly parses the arguments for a request to trigger the "executePostMessageSent" method', () => { - const evtMethod = 'executePostMessageSent'; - // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario - const evtArgs = [ - { - id: 'fake', - sender: 'fake', - createdAt: Date.now(), - room: { - id: 'fake-room', - type: 'fake', - slugifiedName: 'fake', - creator: 'fake', - createdAt: Date.now(), - }, - }, - ]; - - const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); - - assertEquals(params.length, 5); - assertObjectMatch((params[0] as Record), { id: 'fake' }); - assertInstanceOf((params[0] as any).room, Room); - assertEquals(params[1], { __type: 'reader' }); - assertEquals(params[2], { __type: 'http' }); - assertEquals(params[3], { __type: 'persistence' }); - assertEquals(params[4], { __type: 'modifier' }); - }); + const mockAppAccessors = { + getReader: () => ({ __type: 'reader' }), + getHttp: () => ({ __type: 'http' }), + getModifier: () => ({ __type: 'modifier' }), + getPersistence: () => ({ __type: 'persistence' }), + getSenderFn: () => (id: string) => Promise.resolve([{ __type: 'bridgeCall' }, { id }]), + } as unknown as AppAccessors; + + it('correctly parses the arguments for a request to trigger the "checkPreMessageSentPrevent" method', () => { + const evtMethod = 'checkPreMessageSentPrevent'; + // For the 'checkPreMessageSentPrevent' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 3); + assertEquals(params[0], { __type: 'context' }); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + }); + + it('correctly parses the arguments for a request to trigger the "checkPostMessageDeleted" method', () => { + const evtMethod = 'checkPostMessageDeleted'; + // For the 'checkPostMessageDeleted' method, the context will be a message in a real scenario, + // and the extraContext will provide further information such the user who deleted the message + const evtArgs = [{ __type: 'context' }, { __type: 'extraContext' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 4); + assertEquals(params[0], { __type: 'context' }); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'extraContext' }); + }); + + it('correctly parses the arguments for a request to trigger the "checkPreRoomCreateExtend" method', () => { + const evtMethod = 'checkPreRoomCreateExtend'; + // For the 'checkPreRoomCreateExtend' method, the context will be a room in a real scenario + const evtArgs = [ + { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }, + ]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 3); + + assertInstanceOf(params[0], Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreMessageSentExtend" method', () => { + const evtMethod = 'executePreMessageSentExtend'; + // For the 'executePreMessageSentExtend' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the MessageExtender might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], MessageExtender); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreRoomCreateExtend" method', () => { + const evtMethod = 'executePreRoomCreateExtend'; + // For the 'executePreRoomCreateExtend' method, the context will be a room in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the RoomExtender might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], RoomExtender); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreMessageSentModify" method', () => { + const evtMethod = 'executePreMessageSentModify'; + // For the 'executePreMessageSentModify' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the MessageBuilder might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], MessageBuilder); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreRoomCreateModify" method', () => { + const evtMethod = 'executePreRoomCreateModify'; + // For the 'executePreRoomCreateModify' method, the context will be a room in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the RoomBuilder might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], RoomBuilder); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostRoomUserJoined" method', () => { + const evtMethod = 'executePostRoomUserJoined'; + // For the 'executePostRoomUserJoined' method, the context will be a room in a real scenario + const room = { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }; + + const evtArgs = [{ __type: 'context', room }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostRoomUserLeave" method', () => { + const evtMethod = 'executePostRoomUserLeave'; + // For the 'executePostRoomUserLeave' method, the context will be a room in a real scenario + const room = { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }; + + const evtArgs = [{ __type: 'context', room }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostMessageDeleted" method', () => { + const evtMethod = 'executePostMessageDeleted'; + // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }, { __type: 'extraContext' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 6); + assertEquals(params[0], { __type: 'context' }); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + assertEquals(params[5], { __type: 'extraContext' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostMessageSent" method', () => { + const evtMethod = 'executePostMessageSent'; + // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario + const evtArgs = [ + { + id: 'fake', + sender: 'fake', + createdAt: Date.now(), + room: { + id: 'fake-room', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }, + }, + ]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertObjectMatch(params[0] as Record, { id: 'fake' }); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); }); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts index 681f228bdb3ed..a18e7cdeb0309 100644 --- a/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts +++ b/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts @@ -6,41 +6,41 @@ import { AppAccessors } from '../../lib/accessors/mod.ts'; import handleScheduler from '../scheduler-handler.ts'; describe('handlers > scheduler', () => { - const mockAppAccessors = new AppAccessors(() => - Promise.resolve({ - id: 'mockId', - result: {}, - jsonrpc: '2.0', - serialize: () => '', - }), - ); + const mockAppAccessors = new AppAccessors(() => + Promise.resolve({ + id: 'mockId', + result: {}, + jsonrpc: '2.0', + serialize: () => '', + }) + ); - const mockApp = { - getID: () => 'mockApp', - getLogger: () => ({ - debug: () => {}, - error: () => {}, - }), - }; + const mockApp = { + getID: () => 'mockApp', + getLogger: () => ({ + debug: () => {}, + error: () => {}, + }), + }; - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('app', mockApp); - mockAppAccessors.getConfigurationExtend().scheduler.registerProcessors([ - { - id: 'mockId', - processor: () => Promise.resolve('it works!'), - }, - ]); - }); + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('app', mockApp); + mockAppAccessors.getConfigurationExtend().scheduler.registerProcessors([ + { + id: 'mockId', + processor: () => Promise.resolve('it works!'), + }, + ]); + }); - afterAll(() => { - AppObjectRegistry.clear(); - }); + afterAll(() => { + AppObjectRegistry.clear(); + }); - it('correctly executes a request to a processor', async () => { - const result = await handleScheduler('scheduler:mockId', [{}]); + it('correctly executes a request to a processor', async () => { + const result = await handleScheduler('scheduler:mockId', [{}]); - assertEquals(result, null); - }); + assertEquals(result, null); + }); }); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts index d3da4b132d660..c3cb7b105dfd8 100644 --- a/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts +++ b/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts @@ -6,147 +6,147 @@ import { spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessors } from '../../lib/accessors/mod.ts'; import { handleExecutor, handlePreviewItem } from '../slashcommand-handler.ts'; -import { Room } from "../../lib/room.ts"; +import { Room } from '../../lib/room.ts'; describe('handlers > slashcommand', () => { - const mockAppAccessors = { - getReader: () => ({ __type: 'reader' }), - getHttp: () => ({ __type: 'http' }), - getModifier: () => ({ __type: 'modifier' }), - getPersistence: () => ({ __type: 'persistence' }), - getSenderFn: () => (id: string) => Promise.resolve([{ __type: 'bridgeCall' }, { id }]), - } as unknown as AppAccessors; - - const mockCommandExecutorOnly = { - command: 'executor-only', - i18nParamsExample: 'test', - i18nDescription: 'test', - providesPreview: false, - // deno-lint-ignore no-unused-vars - async executor(context: any, read: any, modify: any, http: any, persis: any): Promise {}, - }; - - const mockCommandExecutorAndPreview = { - command: 'executor-and-preview', - i18nParamsExample: 'test', - i18nDescription: 'test', - providesPreview: true, - // deno-lint-ignore no-unused-vars - async executor(context: any, read: any, modify: any, http: any, persis: any): Promise {}, - // deno-lint-ignore no-unused-vars - async previewer(context: any, read: any, modify: any, http: any, persis: any): Promise {}, - // deno-lint-ignore no-unused-vars - async executePreviewItem(previewItem: any, context: any, read: any, modify: any, http: any, persis: any): Promise {}, - }; - - const mockCommandPreviewWithNoExecutor = { - command: 'preview-with-no-executor', - i18nParamsExample: 'test', - i18nDescription: 'test', - providesPreview: true, - // deno-lint-ignore no-unused-vars - async previewer(context: any, read: any, modify: any, http: any, persis: any): Promise {}, - // deno-lint-ignore no-unused-vars - async executePreviewItem(previewItem: any, context: any, read: any, modify: any, http: any, persis: any): Promise {}, - }; - - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('slashcommand:executor-only', mockCommandExecutorOnly); - AppObjectRegistry.set('slashcommand:executor-and-preview', mockCommandExecutorAndPreview); - AppObjectRegistry.set('slashcommand:preview-with-no-executor', mockCommandPreviewWithNoExecutor); - }); - - it('correctly handles execution of a slash command', async () => { - const mockContext = { - sender: { __type: 'sender' }, - room: { __type: 'room' }, - params: { __type: 'params' }, - threadId: 'threadId', - triggerId: 'triggerId', - }; - - const _spy = spy(mockCommandExecutorOnly, 'executor'); - - await handleExecutor({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorOnly, 'executor', [mockContext]); - - const context = _spy.calls[0].args[0]; - - assertInstanceOf(context.getRoom(), Room); - assertEquals(context.getSender(), { __type: 'sender' }); - assertEquals(context.getArguments(), { __type: 'params' }); - assertEquals(context.getThreadId(), 'threadId'); - assertEquals(context.getTriggerId(), 'triggerId'); - - assertEquals(_spy.calls[0].args[1], mockAppAccessors.getReader()); - assertEquals(_spy.calls[0].args[2], mockAppAccessors.getModifier()); - assertEquals(_spy.calls[0].args[3], mockAppAccessors.getHttp()); - assertEquals(_spy.calls[0].args[4], mockAppAccessors.getPersistence()); - - _spy.restore(); - }); - - it('correctly handles execution of a slash command previewer', async () => { - const mockContext = { - sender: { __type: 'sender' }, - room: { __type: 'room' }, - params: { __type: 'params' }, - threadId: 'threadId', - triggerId: 'triggerId', - }; - - const _spy = spy(mockCommandExecutorAndPreview, 'previewer'); - - await handleExecutor({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorAndPreview, 'previewer', [mockContext]); - - const context = _spy.calls[0].args[0]; - - assertInstanceOf(context.getRoom(), Room); - assertEquals(context.getSender(), { __type: 'sender' }); - assertEquals(context.getArguments(), { __type: 'params' }); - assertEquals(context.getThreadId(), 'threadId'); - assertEquals(context.getTriggerId(), 'triggerId'); - - assertEquals(_spy.calls[0].args[1], mockAppAccessors.getReader()); - assertEquals(_spy.calls[0].args[2], mockAppAccessors.getModifier()); - assertEquals(_spy.calls[0].args[3], mockAppAccessors.getHttp()); - assertEquals(_spy.calls[0].args[4], mockAppAccessors.getPersistence()); - - _spy.restore(); - }); - - it('correctly handles execution of a slash command preview item executor', async () => { - const mockContext = { - sender: { __type: 'sender' }, - room: { __type: 'room' }, - params: { __type: 'params' }, - threadId: 'threadId', - triggerId: 'triggerId', - }; - - const mockPreviewItem = { - id: 'previewItemId', - type: 'image', - value: 'https://example.com/image.png', - }; - - const _spy = spy(mockCommandExecutorAndPreview, 'executePreviewItem'); - - await handlePreviewItem({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorAndPreview, [mockPreviewItem, mockContext]); - - const context = _spy.calls[0].args[1]; - - assertInstanceOf(context.getRoom(), Room); - assertEquals(context.getSender(), { __type: 'sender' }); - assertEquals(context.getArguments(), { __type: 'params' }); - assertEquals(context.getThreadId(), 'threadId'); - assertEquals(context.getTriggerId(), 'triggerId'); - - assertEquals(_spy.calls[0].args[2], mockAppAccessors.getReader()); - assertEquals(_spy.calls[0].args[3], mockAppAccessors.getModifier()); - assertEquals(_spy.calls[0].args[4], mockAppAccessors.getHttp()); - assertEquals(_spy.calls[0].args[5], mockAppAccessors.getPersistence()); - - _spy.restore(); - }); + const mockAppAccessors = { + getReader: () => ({ __type: 'reader' }), + getHttp: () => ({ __type: 'http' }), + getModifier: () => ({ __type: 'modifier' }), + getPersistence: () => ({ __type: 'persistence' }), + getSenderFn: () => (id: string) => Promise.resolve([{ __type: 'bridgeCall' }, { id }]), + } as unknown as AppAccessors; + + const mockCommandExecutorOnly = { + command: 'executor-only', + i18nParamsExample: 'test', + i18nDescription: 'test', + providesPreview: false, + // deno-lint-ignore no-unused-vars + async executor(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + }; + + const mockCommandExecutorAndPreview = { + command: 'executor-and-preview', + i18nParamsExample: 'test', + i18nDescription: 'test', + providesPreview: true, + // deno-lint-ignore no-unused-vars + async executor(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + // deno-lint-ignore no-unused-vars + async previewer(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + // deno-lint-ignore no-unused-vars + async executePreviewItem(previewItem: any, context: any, read: any, modify: any, http: any, persis: any): Promise {}, + }; + + const mockCommandPreviewWithNoExecutor = { + command: 'preview-with-no-executor', + i18nParamsExample: 'test', + i18nDescription: 'test', + providesPreview: true, + // deno-lint-ignore no-unused-vars + async previewer(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + // deno-lint-ignore no-unused-vars + async executePreviewItem(previewItem: any, context: any, read: any, modify: any, http: any, persis: any): Promise {}, + }; + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('slashcommand:executor-only', mockCommandExecutorOnly); + AppObjectRegistry.set('slashcommand:executor-and-preview', mockCommandExecutorAndPreview); + AppObjectRegistry.set('slashcommand:preview-with-no-executor', mockCommandPreviewWithNoExecutor); + }); + + it('correctly handles execution of a slash command', async () => { + const mockContext = { + sender: { __type: 'sender' }, + room: { __type: 'room' }, + params: { __type: 'params' }, + threadId: 'threadId', + triggerId: 'triggerId', + }; + + const _spy = spy(mockCommandExecutorOnly, 'executor'); + + await handleExecutor({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorOnly, 'executor', [mockContext]); + + const context = _spy.calls[0].args[0]; + + assertInstanceOf(context.getRoom(), Room); + assertEquals(context.getSender(), { __type: 'sender' }); + assertEquals(context.getArguments(), { __type: 'params' }); + assertEquals(context.getThreadId(), 'threadId'); + assertEquals(context.getTriggerId(), 'triggerId'); + + assertEquals(_spy.calls[0].args[1], mockAppAccessors.getReader()); + assertEquals(_spy.calls[0].args[2], mockAppAccessors.getModifier()); + assertEquals(_spy.calls[0].args[3], mockAppAccessors.getHttp()); + assertEquals(_spy.calls[0].args[4], mockAppAccessors.getPersistence()); + + _spy.restore(); + }); + + it('correctly handles execution of a slash command previewer', async () => { + const mockContext = { + sender: { __type: 'sender' }, + room: { __type: 'room' }, + params: { __type: 'params' }, + threadId: 'threadId', + triggerId: 'triggerId', + }; + + const _spy = spy(mockCommandExecutorAndPreview, 'previewer'); + + await handleExecutor({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorAndPreview, 'previewer', [mockContext]); + + const context = _spy.calls[0].args[0]; + + assertInstanceOf(context.getRoom(), Room); + assertEquals(context.getSender(), { __type: 'sender' }); + assertEquals(context.getArguments(), { __type: 'params' }); + assertEquals(context.getThreadId(), 'threadId'); + assertEquals(context.getTriggerId(), 'triggerId'); + + assertEquals(_spy.calls[0].args[1], mockAppAccessors.getReader()); + assertEquals(_spy.calls[0].args[2], mockAppAccessors.getModifier()); + assertEquals(_spy.calls[0].args[3], mockAppAccessors.getHttp()); + assertEquals(_spy.calls[0].args[4], mockAppAccessors.getPersistence()); + + _spy.restore(); + }); + + it('correctly handles execution of a slash command preview item executor', async () => { + const mockContext = { + sender: { __type: 'sender' }, + room: { __type: 'room' }, + params: { __type: 'params' }, + threadId: 'threadId', + triggerId: 'triggerId', + }; + + const mockPreviewItem = { + id: 'previewItemId', + type: 'image', + value: 'https://example.com/image.png', + }; + + const _spy = spy(mockCommandExecutorAndPreview, 'executePreviewItem'); + + await handlePreviewItem({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorAndPreview, [mockPreviewItem, mockContext]); + + const context = _spy.calls[0].args[1]; + + assertInstanceOf(context.getRoom(), Room); + assertEquals(context.getSender(), { __type: 'sender' }); + assertEquals(context.getArguments(), { __type: 'params' }); + assertEquals(context.getThreadId(), 'threadId'); + assertEquals(context.getTriggerId(), 'triggerId'); + + assertEquals(_spy.calls[0].args[2], mockAppAccessors.getReader()); + assertEquals(_spy.calls[0].args[3], mockAppAccessors.getModifier()); + assertEquals(_spy.calls[0].args[4], mockAppAccessors.getHttp()); + assertEquals(_spy.calls[0].args[5], mockAppAccessors.getPersistence()); + + _spy.restore(); + }); }); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts index f2293d6c98e05..066cdc5ee13a1 100644 --- a/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts +++ b/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts @@ -4,96 +4,96 @@ import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203. import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import handleUIKitInteraction, { - UIKitActionButtonInteractionContext, - UIKitBlockInteractionContext, - UIKitLivechatBlockInteractionContext, - UIKitViewCloseInteractionContext, - UIKitViewSubmitInteractionContext, + UIKitActionButtonInteractionContext, + UIKitBlockInteractionContext, + UIKitLivechatBlockInteractionContext, + UIKitViewCloseInteractionContext, + UIKitViewSubmitInteractionContext, } from '../uikit/handler.ts'; describe('handlers > uikit', () => { - const mockApp = { - getID: (): string => 'appId', - executeBlockActionHandler: (context: any): Promise => Promise.resolve(context), - executeViewSubmitHandler: (context: any): Promise => Promise.resolve(context), - executeViewClosedHandler: (context: any): Promise => Promise.resolve(context), - executeActionButtonHandler: (context: any): Promise => Promise.resolve(context), - executeLivechatBlockActionHandler: (context: any): Promise => Promise.resolve(context), - }; + const mockApp = { + getID: (): string => 'appId', + executeBlockActionHandler: (context: any): Promise => Promise.resolve(context), + executeViewSubmitHandler: (context: any): Promise => Promise.resolve(context), + executeViewClosedHandler: (context: any): Promise => Promise.resolve(context), + executeActionButtonHandler: (context: any): Promise => Promise.resolve(context), + executeLivechatBlockActionHandler: (context: any): Promise => Promise.resolve(context), + }; - beforeEach(() => { - AppObjectRegistry.set('app', mockApp); - }); + beforeEach(() => { + AppObjectRegistry.set('app', mockApp); + }); - afterAll(() => { - AppObjectRegistry.clear(); - }); + afterAll(() => { + AppObjectRegistry.clear(); + }); - it('successfully handles a call for "executeBlockActionHandler"', async () => { - const result = await handleUIKitInteraction('executeBlockActionHandler', [ - { - actionId: 'actionId', - blockId: 'blockId', - value: 'value', - viewId: 'viewId', - }, - ]); + it('successfully handles a call for "executeBlockActionHandler"', async () => { + const result = await handleUIKitInteraction('executeBlockActionHandler', [ + { + actionId: 'actionId', + blockId: 'blockId', + value: 'value', + viewId: 'viewId', + }, + ]); - assertInstanceOf(result, UIKitBlockInteractionContext); - }); + assertInstanceOf(result, UIKitBlockInteractionContext); + }); - it('successfully handles a call for "executeViewSubmitHandler"', async () => { - const result = await handleUIKitInteraction('executeViewSubmitHandler', [ - { - viewId: 'viewId', - appId: 'appId', - userId: 'userId', - isAppUser: true, - values: {}, - }, - ]); + it('successfully handles a call for "executeViewSubmitHandler"', async () => { + const result = await handleUIKitInteraction('executeViewSubmitHandler', [ + { + viewId: 'viewId', + appId: 'appId', + userId: 'userId', + isAppUser: true, + values: {}, + }, + ]); - assertInstanceOf(result, UIKitViewSubmitInteractionContext); - }); + assertInstanceOf(result, UIKitViewSubmitInteractionContext); + }); - it('successfully handles a call for "executeViewClosedHandler"', async () => { - const result = await handleUIKitInteraction('executeViewClosedHandler', [ - { - viewId: 'viewId', - appId: 'appId', - userId: 'userId', - isAppUser: true, - }, - ]); + it('successfully handles a call for "executeViewClosedHandler"', async () => { + const result = await handleUIKitInteraction('executeViewClosedHandler', [ + { + viewId: 'viewId', + appId: 'appId', + userId: 'userId', + isAppUser: true, + }, + ]); - assertInstanceOf(result, UIKitViewCloseInteractionContext); - }); + assertInstanceOf(result, UIKitViewCloseInteractionContext); + }); - it('successfully handles a call for "executeActionButtonHandler"', async () => { - const result = await handleUIKitInteraction('executeActionButtonHandler', [ - { - actionId: 'actionId', - appId: 'appId', - userId: 'userId', - isAppUser: true, - }, - ]); + it('successfully handles a call for "executeActionButtonHandler"', async () => { + const result = await handleUIKitInteraction('executeActionButtonHandler', [ + { + actionId: 'actionId', + appId: 'appId', + userId: 'userId', + isAppUser: true, + }, + ]); - assertInstanceOf(result, UIKitActionButtonInteractionContext); - }); + assertInstanceOf(result, UIKitActionButtonInteractionContext); + }); - it('successfully handles a call for "executeLivechatBlockActionHandler"', async () => { - const result = await handleUIKitInteraction('executeLivechatBlockActionHandler', [ - { - actionId: 'actionId', - appId: 'appId', - userId: 'userId', - visitor: {}, - isAppUser: true, - room: {}, - }, - ]); + it('successfully handles a call for "executeLivechatBlockActionHandler"', async () => { + const result = await handleUIKitInteraction('executeLivechatBlockActionHandler', [ + { + actionId: 'actionId', + appId: 'appId', + userId: 'userId', + visitor: {}, + isAppUser: true, + room: {}, + }, + ]); - assertInstanceOf(result, UIKitLivechatBlockInteractionContext); - }); + assertInstanceOf(result, UIKitLivechatBlockInteractionContext); + }); }); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts index a32d3175e24d4..01f545ce6853e 100644 --- a/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts +++ b/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts @@ -9,114 +9,114 @@ import { assertInstanceOf } from 'https://deno.land/std@0.203.0/assert/assert_in import { JsonRpcError } from 'jsonrpc-lite'; describe('handlers > videoconference', () => { - // deno-lint-ignore no-unused-vars - const mockMethodWithoutParam = (read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok none'); - // deno-lint-ignore no-unused-vars - const mockMethodWithOneParam = (call: any, read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok one'); - // deno-lint-ignore no-unused-vars - const mockMethodWithTwoParam = (call: any, user: any, read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok two'); - // deno-lint-ignore no-unused-vars - const mockMethodWithThreeParam = (call: any, user: any, options: any, read: any, modify: any, http: any, persis: any): Promise => - Promise.resolve('ok three'); - const mockProvider = { - empty: mockMethodWithoutParam, - one: mockMethodWithOneParam, - two: mockMethodWithTwoParam, - three: mockMethodWithThreeParam, - notAFunction: true, - error: () => { - throw new Error('Method execution error example'); - }, - }; - - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('videoConfProvider:test-provider', mockProvider); - }); - - it('correctly handles execution of a videoconf method without additional params', async () => { - const _spy = spy(mockProvider, 'empty'); - - const result = await videoconfHandler('videoconference:test-provider:empty', []); - - assertEquals(result, 'ok none'); - assertEquals(_spy.calls[0].args.length, 4); - - _spy.restore(); - }); - - it('correctly handles execution of a videoconf method with one param', async () => { - const _spy = spy(mockProvider, 'one'); - - const result = await videoconfHandler('videoconference:test-provider:one', ['call']); - - assertEquals(result, 'ok one'); - assertEquals(_spy.calls[0].args.length, 5); - assertEquals(_spy.calls[0].args[0], 'call'); - - _spy.restore(); - }); - - it('correctly handles execution of a videoconf method with two params', async () => { - const _spy = spy(mockProvider, 'two'); - - const result = await videoconfHandler('videoconference:test-provider:two', ['call', 'user']); - - assertEquals(result, 'ok two'); - assertEquals(_spy.calls[0].args.length, 6); - assertEquals(_spy.calls[0].args[0], 'call'); - assertEquals(_spy.calls[0].args[1], 'user'); - - _spy.restore(); - }); - - it('correctly handles execution of a videoconf method with three params', async () => { - const _spy = spy(mockProvider, 'three'); - - const result = await videoconfHandler('videoconference:test-provider:three', ['call', 'user', 'options']); - - assertEquals(result, 'ok three'); - assertEquals(_spy.calls[0].args.length, 7); - assertEquals(_spy.calls[0].args[0], 'call'); - assertEquals(_spy.calls[0].args[1], 'user'); - assertEquals(_spy.calls[0].args[2], 'options'); - - _spy.restore(); - }); - - it('correctly handles an error on execution of a videoconf method', async () => { - const result = await videoconfHandler('videoconference:test-provider:error', []); - - assertInstanceOf(result, JsonRpcError); - assertObjectMatch(result, { - message: 'Method execution error example', - code: -32000, - }); - }); - - it('correctly handles an error when provider is not found', async () => { - const providerName = 'error-provider'; - const result = await videoconfHandler(`videoconference:${providerName}:method`, []); - - assertInstanceOf(result, JsonRpcError); - assertObjectMatch(result, { - message: `Provider ${providerName} not found`, - code: -32000, - }); - }); - - it('correctly handles an error if method is not a function of provider', async () => { - const methodName = 'notAFunction'; - const providerName = 'test-provider'; - const result = await videoconfHandler(`videoconference:${providerName}:${methodName}`, []); - - assertInstanceOf(result, JsonRpcError); - assertObjectMatch(result, { - message: 'Method not found', - code: -32601, - data: { - message: `Method ${methodName} not found on provider ${providerName}`, - }, - }); - }); + // deno-lint-ignore no-unused-vars + const mockMethodWithoutParam = (read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok none'); + // deno-lint-ignore no-unused-vars + const mockMethodWithOneParam = (call: any, read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok one'); + // deno-lint-ignore no-unused-vars + const mockMethodWithTwoParam = (call: any, user: any, read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok two'); + // deno-lint-ignore no-unused-vars + const mockMethodWithThreeParam = (call: any, user: any, options: any, read: any, modify: any, http: any, persis: any): Promise => + Promise.resolve('ok three'); + const mockProvider = { + empty: mockMethodWithoutParam, + one: mockMethodWithOneParam, + two: mockMethodWithTwoParam, + three: mockMethodWithThreeParam, + notAFunction: true, + error: () => { + throw new Error('Method execution error example'); + }, + }; + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('videoConfProvider:test-provider', mockProvider); + }); + + it('correctly handles execution of a videoconf method without additional params', async () => { + const _spy = spy(mockProvider, 'empty'); + + const result = await videoconfHandler('videoconference:test-provider:empty', []); + + assertEquals(result, 'ok none'); + assertEquals(_spy.calls[0].args.length, 4); + + _spy.restore(); + }); + + it('correctly handles execution of a videoconf method with one param', async () => { + const _spy = spy(mockProvider, 'one'); + + const result = await videoconfHandler('videoconference:test-provider:one', ['call']); + + assertEquals(result, 'ok one'); + assertEquals(_spy.calls[0].args.length, 5); + assertEquals(_spy.calls[0].args[0], 'call'); + + _spy.restore(); + }); + + it('correctly handles execution of a videoconf method with two params', async () => { + const _spy = spy(mockProvider, 'two'); + + const result = await videoconfHandler('videoconference:test-provider:two', ['call', 'user']); + + assertEquals(result, 'ok two'); + assertEquals(_spy.calls[0].args.length, 6); + assertEquals(_spy.calls[0].args[0], 'call'); + assertEquals(_spy.calls[0].args[1], 'user'); + + _spy.restore(); + }); + + it('correctly handles execution of a videoconf method with three params', async () => { + const _spy = spy(mockProvider, 'three'); + + const result = await videoconfHandler('videoconference:test-provider:three', ['call', 'user', 'options']); + + assertEquals(result, 'ok three'); + assertEquals(_spy.calls[0].args.length, 7); + assertEquals(_spy.calls[0].args[0], 'call'); + assertEquals(_spy.calls[0].args[1], 'user'); + assertEquals(_spy.calls[0].args[2], 'options'); + + _spy.restore(); + }); + + it('correctly handles an error on execution of a videoconf method', async () => { + const result = await videoconfHandler('videoconference:test-provider:error', []); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: 'Method execution error example', + code: -32000, + }); + }); + + it('correctly handles an error when provider is not found', async () => { + const providerName = 'error-provider'; + const result = await videoconfHandler(`videoconference:${providerName}:method`, []); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: `Provider ${providerName} not found`, + code: -32000, + }); + }); + + it('correctly handles an error if method is not a function of provider', async () => { + const methodName = 'notAFunction'; + const providerName = 'test-provider'; + const result = await videoconfHandler(`videoconference:${providerName}:${methodName}`, []); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: 'Method not found', + code: -32601, + data: { + message: `Method ${methodName} not found on provider ${providerName}`, + }, + }); + }); }); diff --git a/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts b/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts index 5a418f242ad99..25e08a85e648b 100644 --- a/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts @@ -6,77 +6,77 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; export const uikitInteractions = [ - 'executeBlockActionHandler', - 'executeViewSubmitHandler', - 'executeViewClosedHandler', - 'executeActionButtonHandler', - 'executeLivechatBlockActionHandler', + 'executeBlockActionHandler', + 'executeViewSubmitHandler', + 'executeViewClosedHandler', + 'executeActionButtonHandler', + 'executeLivechatBlockActionHandler', ]; export const { - UIKitBlockInteractionContext, - UIKitViewSubmitInteractionContext, - UIKitViewCloseInteractionContext, - UIKitActionButtonInteractionContext, + UIKitBlockInteractionContext, + UIKitViewSubmitInteractionContext, + UIKitViewCloseInteractionContext, + UIKitActionButtonInteractionContext, } = require('@rocket.chat/apps-engine/definition/uikit/UIKitInteractionContext.js'); export const { UIKitLivechatBlockInteractionContext } = require('@rocket.chat/apps-engine/definition/uikit/livechat/UIKitLivechatInteractionContext.js'); export default async function handleUIKitInteraction(method: string, params: unknown): Promise { - if (!uikitInteractions.includes(method)) { - return JsonRpcError.methodNotFound(null); - } + if (!uikitInteractions.includes(method)) { + return JsonRpcError.methodNotFound(null); + } - if (!Array.isArray(params)) { - return JsonRpcError.invalidParams(null); - } + if (!Array.isArray(params)) { + return JsonRpcError.invalidParams(null); + } - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - const interactionHandler = app?.[method as keyof App] as unknown; + const interactionHandler = app?.[method as keyof App] as unknown; - if (!app || typeof interactionHandler !== 'function') { - return JsonRpcError.methodNotFound({ - message: `App does not implement method "${method}"`, - }); - } + if (!app || typeof interactionHandler !== 'function') { + return JsonRpcError.methodNotFound({ + message: `App does not implement method "${method}"`, + }); + } - const [payload] = params as [Record]; + const [payload] = params as [Record]; - if (!payload) { - return JsonRpcError.invalidParams(null); - } + if (!payload) { + return JsonRpcError.invalidParams(null); + } - let context; + let context; - switch (method) { - case 'executeBlockActionHandler': - context = new UIKitBlockInteractionContext(payload); - break; - case 'executeViewSubmitHandler': - context = new UIKitViewSubmitInteractionContext(payload); - break; - case 'executeViewClosedHandler': - context = new UIKitViewCloseInteractionContext(payload); - break; - case 'executeActionButtonHandler': - context = new UIKitActionButtonInteractionContext(payload); - break; - case 'executeLivechatBlockActionHandler': - context = new UIKitLivechatBlockInteractionContext(payload); - break; - } + switch (method) { + case 'executeBlockActionHandler': + context = new UIKitBlockInteractionContext(payload); + break; + case 'executeViewSubmitHandler': + context = new UIKitViewSubmitInteractionContext(payload); + break; + case 'executeViewClosedHandler': + context = new UIKitViewCloseInteractionContext(payload); + break; + case 'executeActionButtonHandler': + context = new UIKitActionButtonInteractionContext(payload); + break; + case 'executeLivechatBlockActionHandler': + context = new UIKitLivechatBlockInteractionContext(payload); + break; + } - try { - return await interactionHandler.call( - app, - context, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - AppAccessorsInstance.getModifier(), - ); - } catch (e) { - return JsonRpcError.internalError({ message: e.message }); - } + try { + return await interactionHandler.call( + app, + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); + } catch (e) { + return JsonRpcError.internalError({ message: e.message }); + } } diff --git a/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts b/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts index 0347519db2e6f..dc897ee337b22 100644 --- a/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts @@ -6,44 +6,44 @@ import { AppAccessorsInstance } from '../lib/accessors/mod.ts'; import { Logger } from '../lib/logger.ts'; export default async function videoConferenceHandler(call: string, params: unknown): Promise { - const [, providerName, methodName] = call.split(':'); + const [, providerName, methodName] = call.split(':'); - const provider = AppObjectRegistry.get(`videoConfProvider:${providerName}`); - const logger = AppObjectRegistry.get('logger'); + const provider = AppObjectRegistry.get(`videoConfProvider:${providerName}`); + const logger = AppObjectRegistry.get('logger'); - if (!provider) { - return new JsonRpcError(`Provider ${providerName} not found`, -32000); - } + if (!provider) { + return new JsonRpcError(`Provider ${providerName} not found`, -32000); + } - const method = provider[methodName as keyof IVideoConfProvider]; + const method = provider[methodName as keyof IVideoConfProvider]; - if (typeof method !== 'function') { - return JsonRpcError.methodNotFound({ - message: `Method ${methodName} not found on provider ${providerName}`, - }); - } + if (typeof method !== 'function') { + return JsonRpcError.methodNotFound({ + message: `Method ${methodName} not found on provider ${providerName}`, + }); + } - const [videoconf, user, options] = params as Array; + const [videoconf, user, options] = params as Array; - logger?.debug(`Executing ${methodName} on video conference provider...`); + logger?.debug(`Executing ${methodName} on video conference provider...`); - const args = [...(videoconf ? [videoconf] : []), ...(user ? [user] : []), ...(options ? [options] : [])]; + const args = [...(videoconf ? [videoconf] : []), ...(user ? [user] : []), ...(options ? [options] : [])]; - try { - // deno-lint-ignore ban-types - const result = await (method as Function).apply(provider, [ - ...args, - AppAccessorsInstance.getReader(), - AppAccessorsInstance.getModifier(), - AppAccessorsInstance.getHttp(), - AppAccessorsInstance.getPersistence(), - ]); + try { + // deno-lint-ignore ban-types + const result = await (method as Function).apply(provider, [ + ...args, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getModifier(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + ]); - logger?.debug(`Video Conference Provider's ${methodName} was successfully executed.`); + logger?.debug(`Video Conference Provider's ${methodName} was successfully executed.`); - return result; - } catch (e) { - logger?.debug(`Video Conference Provider's ${methodName} was unsuccessful.`); - return new JsonRpcError(e.message, -32000); - } + return result; + } catch (e) { + logger?.debug(`Video Conference Provider's ${methodName} was unsuccessful.`); + return new JsonRpcError(e.message, -32000); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts index e1602860fe97a..de103fe50be02 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts @@ -1,28 +1,28 @@ import { v1 as uuid } from 'uuid'; import type { - BlockType as _BlockType, - IActionsBlock, - IBlock, - IConditionalBlock, - IConditionalBlockFilters, - IContextBlock, - IImageBlock, - IInputBlock, - ISectionBlock, + BlockType as _BlockType, + IActionsBlock, + IBlock, + IConditionalBlock, + IConditionalBlockFilters, + IContextBlock, + IImageBlock, + IInputBlock, + ISectionBlock, } from '@rocket.chat/apps-engine/definition/uikit/blocks/Blocks.ts'; import type { - BlockElementType as _BlockElementType, - IBlockElement, - IButtonElement, - IImageElement, - IInputElement, - IInteractiveElement, - IMultiStaticSelectElement, - IOverflowMenuElement, - IPlainTextInputElement, - ISelectElement, - IStaticSelectElement, + BlockElementType as _BlockElementType, + IBlockElement, + IButtonElement, + IImageElement, + IInputElement, + IInteractiveElement, + IMultiStaticSelectElement, + IOverflowMenuElement, + IPlainTextInputElement, + ISelectElement, + IStaticSelectElement, } from '@rocket.chat/apps-engine/definition/uikit/blocks/Elements.ts'; import type { ITextObject, TextObjectType as _TextObjectType } from '@rocket.chat/apps-engine/definition/uikit/blocks/Objects.ts'; @@ -34,9 +34,8 @@ const { BlockElementType } = require('@rocket.chat/apps-engine/definition/uikit/ const { TextObjectType } = require('@rocket.chat/apps-engine/definition/uikit/blocks/Objects.js') as { TextObjectType: typeof _TextObjectType }; type BlockFunctionParameter = Omit; -type ElementFunctionParameter = T extends IInteractiveElement - ? Omit | Partial> - : Omit; +type ElementFunctionParameter = T extends IInteractiveElement ? Omit | Partial> + : Omit; type SectionBlockParam = BlockFunctionParameter; type ImageBlockParam = BlockFunctionParameter; @@ -55,162 +54,162 @@ type MultiStaticSelectElementParam = ElementFunctionParameter; - private readonly appId: string; - - constructor() { - this.blocks = []; - this.appId = String(AppObjectRegistry.get('id')); - } - - public addSectionBlock(block: SectionBlockParam): BlockBuilder { - this.addBlock({ type: BlockType.SECTION, ...block } as ISectionBlock); - - return this; - } - - public addImageBlock(block: ImageBlockParam): BlockBuilder { - this.addBlock({ type: BlockType.IMAGE, ...block } as IImageBlock); - - return this; - } - - public addDividerBlock(): BlockBuilder { - this.addBlock({ type: BlockType.DIVIDER }); - - return this; - } - - public addActionsBlock(block: ActionsBlockParam): BlockBuilder { - this.addBlock({ type: BlockType.ACTIONS, ...block } as IActionsBlock); - - return this; - } - - public addContextBlock(block: ContextBlockParam): BlockBuilder { - this.addBlock({ type: BlockType.CONTEXT, ...block } as IContextBlock); - - return this; - } - - public addInputBlock(block: InputBlockParam): BlockBuilder { - this.addBlock({ type: BlockType.INPUT, ...block } as IInputBlock); - - return this; - } - - public addConditionalBlock(innerBlocks: BlockBuilder | Array, condition?: IConditionalBlockFilters): BlockBuilder { - const render = innerBlocks instanceof BlockBuilder ? innerBlocks.getBlocks() : innerBlocks; - - this.addBlock({ - type: BlockType.CONDITIONAL, - render, - when: condition, - } as IConditionalBlock); - - return this; - } - - public getBlocks() { - return this.blocks; - } - - public newPlainTextObject(text: string, emoji = false): ITextObject { - return { - type: TextObjectType.PLAINTEXT, - text, - emoji, - }; - } - - public newMarkdownTextObject(text: string): ITextObject { - return { - type: TextObjectType.MARKDOWN, - text, - }; - } - - public newButtonElement(info: ButtonElementParam): IButtonElement { - return this.newInteractiveElement({ - type: BlockElementType.BUTTON, - ...info, - } as IButtonElement); - } - - public newImageElement(info: ImageElementParam): IImageElement { - return { - type: BlockElementType.IMAGE, - ...info, - }; - } - - public newOverflowMenuElement(info: OverflowMenuElementParam): IOverflowMenuElement { - return this.newInteractiveElement({ - type: BlockElementType.OVERFLOW_MENU, - ...info, - } as IOverflowMenuElement); - } - - public newPlainTextInputElement(info: PlainTextInputElementParam): IPlainTextInputElement { - return this.newInputElement({ - type: BlockElementType.PLAIN_TEXT_INPUT, - ...info, - } as IPlainTextInputElement); - } - - public newStaticSelectElement(info: StaticSelectElementParam): IStaticSelectElement { - return this.newSelectElement({ - type: BlockElementType.STATIC_SELECT, - ...info, - } as IStaticSelectElement); - } - - public newMultiStaticElement(info: MultiStaticSelectElementParam): IMultiStaticSelectElement { - return this.newSelectElement({ - type: BlockElementType.MULTI_STATIC_SELECT, - ...info, - } as IMultiStaticSelectElement); - } - - private newInteractiveElement(element: T): T { - if (!element.actionId) { - element.actionId = this.generateActionId(); - } - - return element; - } - - private newInputElement(element: T): T { - if (!element.actionId) { - element.actionId = this.generateActionId(); - } - - return element; - } - - private newSelectElement(element: T): T { - if (!element.actionId) { - element.actionId = this.generateActionId(); - } - - return element; - } - - private addBlock(block: IBlock): void { - if (!block.blockId) { - block.blockId = this.generateBlockId(); - } - - block.appId = this.appId; - - this.blocks.push(block); - } - - private generateBlockId(): string { - return uuid(); - } - - private generateActionId(): string { - return uuid(); - } + private readonly blocks: Array; + private readonly appId: string; + + constructor() { + this.blocks = []; + this.appId = String(AppObjectRegistry.get('id')); + } + + public addSectionBlock(block: SectionBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.SECTION, ...block } as ISectionBlock); + + return this; + } + + public addImageBlock(block: ImageBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.IMAGE, ...block } as IImageBlock); + + return this; + } + + public addDividerBlock(): BlockBuilder { + this.addBlock({ type: BlockType.DIVIDER }); + + return this; + } + + public addActionsBlock(block: ActionsBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.ACTIONS, ...block } as IActionsBlock); + + return this; + } + + public addContextBlock(block: ContextBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.CONTEXT, ...block } as IContextBlock); + + return this; + } + + public addInputBlock(block: InputBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.INPUT, ...block } as IInputBlock); + + return this; + } + + public addConditionalBlock(innerBlocks: BlockBuilder | Array, condition?: IConditionalBlockFilters): BlockBuilder { + const render = innerBlocks instanceof BlockBuilder ? innerBlocks.getBlocks() : innerBlocks; + + this.addBlock({ + type: BlockType.CONDITIONAL, + render, + when: condition, + } as IConditionalBlock); + + return this; + } + + public getBlocks() { + return this.blocks; + } + + public newPlainTextObject(text: string, emoji = false): ITextObject { + return { + type: TextObjectType.PLAINTEXT, + text, + emoji, + }; + } + + public newMarkdownTextObject(text: string): ITextObject { + return { + type: TextObjectType.MARKDOWN, + text, + }; + } + + public newButtonElement(info: ButtonElementParam): IButtonElement { + return this.newInteractiveElement({ + type: BlockElementType.BUTTON, + ...info, + } as IButtonElement); + } + + public newImageElement(info: ImageElementParam): IImageElement { + return { + type: BlockElementType.IMAGE, + ...info, + }; + } + + public newOverflowMenuElement(info: OverflowMenuElementParam): IOverflowMenuElement { + return this.newInteractiveElement({ + type: BlockElementType.OVERFLOW_MENU, + ...info, + } as IOverflowMenuElement); + } + + public newPlainTextInputElement(info: PlainTextInputElementParam): IPlainTextInputElement { + return this.newInputElement({ + type: BlockElementType.PLAIN_TEXT_INPUT, + ...info, + } as IPlainTextInputElement); + } + + public newStaticSelectElement(info: StaticSelectElementParam): IStaticSelectElement { + return this.newSelectElement({ + type: BlockElementType.STATIC_SELECT, + ...info, + } as IStaticSelectElement); + } + + public newMultiStaticElement(info: MultiStaticSelectElementParam): IMultiStaticSelectElement { + return this.newSelectElement({ + type: BlockElementType.MULTI_STATIC_SELECT, + ...info, + } as IMultiStaticSelectElement); + } + + private newInteractiveElement(element: T): T { + if (!element.actionId) { + element.actionId = this.generateActionId(); + } + + return element; + } + + private newInputElement(element: T): T { + if (!element.actionId) { + element.actionId = this.generateActionId(); + } + + return element; + } + + private newSelectElement(element: T): T { + if (!element.actionId) { + element.actionId = this.generateActionId(); + } + + return element; + } + + private addBlock(block: IBlock): void { + if (!block.blockId) { + block.blockId = this.generateBlockId(); + } + + block.appId = this.appId; + + this.blocks.push(block); + } + + private generateBlockId(): string { + return uuid(); + } + + private generateActionId(): string { + return uuid(); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts index e2c2dc0214386..adbf060182e1d 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts @@ -10,7 +10,7 @@ import { RoomBuilder } from './RoomBuilder.ts'; import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; @@ -18,42 +18,42 @@ const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType export interface IDiscussionBuilder extends _IDiscussionBuilder, IRoomBuilder {} export class DiscussionBuilder extends RoomBuilder implements IDiscussionBuilder { - public kind: _RocketChatAssociationModel.DISCUSSION; + public kind: _RocketChatAssociationModel.DISCUSSION; - private reply?: string; + private reply?: string; - private parentMessage?: IMessage; + private parentMessage?: IMessage; - constructor(data?: Partial) { - super(data); - this.kind = RocketChatAssociationModel.DISCUSSION; - this.room.type = RoomType.PRIVATE_GROUP; - } + constructor(data?: Partial) { + super(data); + this.kind = RocketChatAssociationModel.DISCUSSION; + this.room.type = RoomType.PRIVATE_GROUP; + } - public setParentRoom(parentRoom: IRoom): IDiscussionBuilder { - this.room.parentRoom = parentRoom; - return this; - } + public setParentRoom(parentRoom: IRoom): IDiscussionBuilder { + this.room.parentRoom = parentRoom; + return this; + } - public getParentRoom(): IRoom { - return this.room.parentRoom!; - } + public getParentRoom(): IRoom { + return this.room.parentRoom!; + } - public setReply(reply: string): IDiscussionBuilder { - this.reply = reply; - return this; - } + public setReply(reply: string): IDiscussionBuilder { + this.reply = reply; + return this; + } - public getReply(): string { - return this.reply!; - } + public getReply(): string { + return this.reply!; + } - public setParentMessage(parentMessage: IMessage): IDiscussionBuilder { - this.parentMessage = parentMessage; - return this; - } + public setParentMessage(parentMessage: IMessage): IDiscussionBuilder { + this.parentMessage = parentMessage; + return this; + } - public getParentMessage(): IMessage { - return this.parentMessage!; - } + public getParentMessage(): IMessage { + return this.parentMessage!; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts index a12024ab7b5d4..b39a418c5aec0 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts @@ -14,7 +14,7 @@ import { MessageBuilder } from './MessageBuilder.ts'; import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; @@ -22,183 +22,183 @@ const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType export interface ILivechatMessage extends EngineLivechatMessage, IMessage {} export class LivechatMessageBuilder implements ILivechatMessageBuilder { - public kind: _RocketChatAssociationModel.LIVECHAT_MESSAGE; - - private msg: ILivechatMessage; - - constructor(message?: ILivechatMessage) { - this.kind = RocketChatAssociationModel.LIVECHAT_MESSAGE; - this.msg = message || ({} as ILivechatMessage); - } - - public setData(data: ILivechatMessage): ILivechatMessageBuilder { - delete data.id; - this.msg = data; - - return this; - } - - public setRoom(room: IRoom): ILivechatMessageBuilder { - this.msg.room = room; - return this; - } - - public getRoom(): IRoom { - return this.msg.room; - } - - public setSender(sender: IUser): ILivechatMessageBuilder { - this.msg.sender = sender; - delete this.msg.visitor; - - return this; - } - - public getSender(): IUser { - return this.msg.sender; - } - - public setText(text: string): ILivechatMessageBuilder { - this.msg.text = text; - return this; - } - - public getText(): string { - return this.msg.text!; - } - - public setEmojiAvatar(emoji: string): ILivechatMessageBuilder { - this.msg.emoji = emoji; - return this; - } - - public getEmojiAvatar(): string { - return this.msg.emoji!; - } - - public setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder { - this.msg.avatarUrl = avatarUrl; - return this; - } - - public getAvatarUrl(): string { - return this.msg.avatarUrl!; - } - - public setUsernameAlias(alias: string): ILivechatMessageBuilder { - this.msg.alias = alias; - return this; - } - - public getUsernameAlias(): string { - return this.msg.alias!; - } - - public addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder { - if (!this.msg.attachments) { - this.msg.attachments = []; - } - - this.msg.attachments.push(attachment); - return this; - } - - public setAttachments(attachments: Array): ILivechatMessageBuilder { - this.msg.attachments = attachments; - return this; - } - - public getAttachments(): Array { - return this.msg.attachments!; - } - - public replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder { - if (!this.msg.attachments) { - this.msg.attachments = []; - } - - if (!this.msg.attachments[position]) { - throw new Error(`No attachment found at the index of "${position}" to replace.`); - } - - this.msg.attachments[position] = attachment; - return this; - } - - public removeAttachment(position: number): ILivechatMessageBuilder { - if (!this.msg.attachments) { - this.msg.attachments = []; - } - - if (!this.msg.attachments[position]) { - throw new Error(`No attachment found at the index of "${position}" to remove.`); - } - - this.msg.attachments.splice(position, 1); - - return this; - } - - public setEditor(user: IUser): ILivechatMessageBuilder { - this.msg.editor = user; - return this; - } - - public getEditor(): IUser { - return this.msg.editor; - } - - public setGroupable(groupable: boolean): ILivechatMessageBuilder { - this.msg.groupable = groupable; - return this; - } - - public getGroupable(): boolean { - return this.msg.groupable!; - } - - public setParseUrls(parseUrls: boolean): ILivechatMessageBuilder { - this.msg.parseUrls = parseUrls; - return this; - } - - public getParseUrls(): boolean { - return this.msg.parseUrls!; - } - - public setToken(token: string): ILivechatMessageBuilder { - this.msg.token = token; - return this; - } - - public getToken(): string { - return this.msg.token!; - } - - public setVisitor(visitor: IVisitor): ILivechatMessageBuilder { - this.msg.visitor = visitor; - delete this.msg.sender; - - return this; - } - - public getVisitor(): IVisitor { - return this.msg.visitor; - } - - public getMessage(): ILivechatMessage { - if (!this.msg.room) { - throw new Error('The "room" property is required.'); - } - - if (this.msg.room.type !== RoomType.LIVE_CHAT) { - throw new Error('The room is not a Livechat room'); - } - - return this.msg; - } - - public getMessageBuilder(): IMessageBuilder { - return new MessageBuilder(this.msg as IMessage); - } + public kind: _RocketChatAssociationModel.LIVECHAT_MESSAGE; + + private msg: ILivechatMessage; + + constructor(message?: ILivechatMessage) { + this.kind = RocketChatAssociationModel.LIVECHAT_MESSAGE; + this.msg = message || ({} as ILivechatMessage); + } + + public setData(data: ILivechatMessage): ILivechatMessageBuilder { + delete data.id; + this.msg = data; + + return this; + } + + public setRoom(room: IRoom): ILivechatMessageBuilder { + this.msg.room = room; + return this; + } + + public getRoom(): IRoom { + return this.msg.room; + } + + public setSender(sender: IUser): ILivechatMessageBuilder { + this.msg.sender = sender; + delete this.msg.visitor; + + return this; + } + + public getSender(): IUser { + return this.msg.sender; + } + + public setText(text: string): ILivechatMessageBuilder { + this.msg.text = text; + return this; + } + + public getText(): string { + return this.msg.text!; + } + + public setEmojiAvatar(emoji: string): ILivechatMessageBuilder { + this.msg.emoji = emoji; + return this; + } + + public getEmojiAvatar(): string { + return this.msg.emoji!; + } + + public setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder { + this.msg.avatarUrl = avatarUrl; + return this; + } + + public getAvatarUrl(): string { + return this.msg.avatarUrl!; + } + + public setUsernameAlias(alias: string): ILivechatMessageBuilder { + this.msg.alias = alias; + return this; + } + + public getUsernameAlias(): string { + return this.msg.alias!; + } + + public addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + this.msg.attachments.push(attachment); + return this; + } + + public setAttachments(attachments: Array): ILivechatMessageBuilder { + this.msg.attachments = attachments; + return this; + } + + public getAttachments(): Array { + return this.msg.attachments!; + } + + public replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + if (!this.msg.attachments[position]) { + throw new Error(`No attachment found at the index of "${position}" to replace.`); + } + + this.msg.attachments[position] = attachment; + return this; + } + + public removeAttachment(position: number): ILivechatMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + if (!this.msg.attachments[position]) { + throw new Error(`No attachment found at the index of "${position}" to remove.`); + } + + this.msg.attachments.splice(position, 1); + + return this; + } + + public setEditor(user: IUser): ILivechatMessageBuilder { + this.msg.editor = user; + return this; + } + + public getEditor(): IUser { + return this.msg.editor; + } + + public setGroupable(groupable: boolean): ILivechatMessageBuilder { + this.msg.groupable = groupable; + return this; + } + + public getGroupable(): boolean { + return this.msg.groupable!; + } + + public setParseUrls(parseUrls: boolean): ILivechatMessageBuilder { + this.msg.parseUrls = parseUrls; + return this; + } + + public getParseUrls(): boolean { + return this.msg.parseUrls!; + } + + public setToken(token: string): ILivechatMessageBuilder { + this.msg.token = token; + return this; + } + + public getToken(): string { + return this.msg.token!; + } + + public setVisitor(visitor: IVisitor): ILivechatMessageBuilder { + this.msg.visitor = visitor; + delete this.msg.sender; + + return this; + } + + public getVisitor(): IVisitor { + return this.msg.visitor; + } + + public getMessage(): ILivechatMessage { + if (!this.msg.room) { + throw new Error('The "room" property is required.'); + } + + if (this.msg.room.type !== RoomType.LIVE_CHAT) { + throw new Error('The room is not a Livechat room'); + } + + return this.msg; + } + + public getMessageBuilder(): IMessageBuilder { + return new MessageBuilder(this.msg as IMessage); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts index b549b5174032d..032b4ba2552e9 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts @@ -12,260 +12,260 @@ import { BlockBuilder } from './BlockBuilder.ts'; import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class MessageBuilder implements IMessageBuilder { - public kind: _RocketChatAssociationModel.MESSAGE; + public kind: _RocketChatAssociationModel.MESSAGE; - private msg: IMessage; + private msg: IMessage; - private changes: Partial = {}; - private attachmentsChanged = false; - private customFieldsChanged = false; + private changes: Partial = {}; + private attachmentsChanged = false; + private customFieldsChanged = false; - constructor(message?: IMessage) { - this.kind = RocketChatAssociationModel.MESSAGE; - this.msg = message || ({} as IMessage); - } + constructor(message?: IMessage) { + this.kind = RocketChatAssociationModel.MESSAGE; + this.msg = message || ({} as IMessage); + } - public setData(data: IMessage): IMessageBuilder { - delete data.id; - this.msg = data; + public setData(data: IMessage): IMessageBuilder { + delete data.id; + this.msg = data; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public setUpdateData(data: IMessage, editor: IUser): IMessageBuilder { - this.msg = data; - this.msg.editor = editor; - this.msg.editedAt = new Date(); + public setUpdateData(data: IMessage, editor: IUser): IMessageBuilder { + this.msg = data; + this.msg.editor = editor; + this.msg.editedAt = new Date(); - this.changes = structuredClone(this.msg); + this.changes = structuredClone(this.msg); - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public setThreadId(threadId: string): IMessageBuilder { - this.msg.threadId = threadId; - this.changes.threadId = threadId; + public setThreadId(threadId: string): IMessageBuilder { + this.msg.threadId = threadId; + this.changes.threadId = threadId; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getThreadId(): string { - return this.msg.threadId!; - } + public getThreadId(): string { + return this.msg.threadId!; + } - public setRoom(room: IRoom): IMessageBuilder { - this.msg.room = room; - this.changes.room = room; + public setRoom(room: IRoom): IMessageBuilder { + this.msg.room = room; + this.changes.room = room; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getRoom(): IRoom { - return this.msg.room; - } + public getRoom(): IRoom { + return this.msg.room; + } - public setSender(sender: IUser): IMessageBuilder { - this.msg.sender = sender; - this.changes.sender = sender; + public setSender(sender: IUser): IMessageBuilder { + this.msg.sender = sender; + this.changes.sender = sender; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getSender(): IUser { - return this.msg.sender; - } + public getSender(): IUser { + return this.msg.sender; + } - public setText(text: string): IMessageBuilder { - this.msg.text = text; - this.changes.text = text; + public setText(text: string): IMessageBuilder { + this.msg.text = text; + this.changes.text = text; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getText(): string { - return this.msg.text!; - } + public getText(): string { + return this.msg.text!; + } - public setEmojiAvatar(emoji: string): IMessageBuilder { - this.msg.emoji = emoji; - this.changes.emoji = emoji; + public setEmojiAvatar(emoji: string): IMessageBuilder { + this.msg.emoji = emoji; + this.changes.emoji = emoji; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getEmojiAvatar(): string { - return this.msg.emoji!; - } + public getEmojiAvatar(): string { + return this.msg.emoji!; + } - public setAvatarUrl(avatarUrl: string): IMessageBuilder { - this.msg.avatarUrl = avatarUrl; - this.changes.avatarUrl = avatarUrl; + public setAvatarUrl(avatarUrl: string): IMessageBuilder { + this.msg.avatarUrl = avatarUrl; + this.changes.avatarUrl = avatarUrl; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getAvatarUrl(): string { - return this.msg.avatarUrl!; - } + public getAvatarUrl(): string { + return this.msg.avatarUrl!; + } - public setUsernameAlias(alias: string): IMessageBuilder { - this.msg.alias = alias; - this.changes.alias = alias; + public setUsernameAlias(alias: string): IMessageBuilder { + this.msg.alias = alias; + this.changes.alias = alias; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getUsernameAlias(): string { - return this.msg.alias!; - } + public getUsernameAlias(): string { + return this.msg.alias!; + } - public addAttachment(attachment: IMessageAttachment): IMessageBuilder { - if (!this.msg.attachments) { - this.msg.attachments = []; - } + public addAttachment(attachment: IMessageAttachment): IMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } - this.msg.attachments.push(attachment); - this.attachmentsChanged = true; + this.msg.attachments.push(attachment); + this.attachmentsChanged = true; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public setAttachments(attachments: Array): IMessageBuilder { - this.msg.attachments = attachments; - this.attachmentsChanged = true; + public setAttachments(attachments: Array): IMessageBuilder { + this.msg.attachments = attachments; + this.attachmentsChanged = true; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getAttachments(): Array { - return this.msg.attachments!; - } + public getAttachments(): Array { + return this.msg.attachments!; + } - public replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder { - if (!this.msg.attachments?.[position]) { - throw new Error(`No attachment found at the index of "${position}" to replace.`); - } + public replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder { + if (!this.msg.attachments?.[position]) { + throw new Error(`No attachment found at the index of "${position}" to replace.`); + } - this.msg.attachments[position] = attachment; - this.attachmentsChanged = true; + this.msg.attachments[position] = attachment; + this.attachmentsChanged = true; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public removeAttachment(position: number): IMessageBuilder { - if (!this.msg.attachments?.[position]) { - throw new Error(`No attachment found at the index of "${position}" to remove.`); - } + public removeAttachment(position: number): IMessageBuilder { + if (!this.msg.attachments?.[position]) { + throw new Error(`No attachment found at the index of "${position}" to remove.`); + } - this.msg.attachments.splice(position, 1); - this.attachmentsChanged = true; + this.msg.attachments.splice(position, 1); + this.attachmentsChanged = true; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public setEditor(user: IUser): IMessageBuilder { - this.msg.editor = user; - this.changes.editor = user; + public setEditor(user: IUser): IMessageBuilder { + this.msg.editor = user; + this.changes.editor = user; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getEditor(): IUser { - return this.msg.editor; - } + public getEditor(): IUser { + return this.msg.editor; + } - public setGroupable(groupable: boolean): IMessageBuilder { - this.msg.groupable = groupable; - this.changes.groupable = groupable; + public setGroupable(groupable: boolean): IMessageBuilder { + this.msg.groupable = groupable; + this.changes.groupable = groupable; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getGroupable(): boolean { - return this.msg.groupable!; - } + public getGroupable(): boolean { + return this.msg.groupable!; + } - public setParseUrls(parseUrls: boolean): IMessageBuilder { - this.msg.parseUrls = parseUrls; - this.changes.parseUrls = parseUrls; + public setParseUrls(parseUrls: boolean): IMessageBuilder { + this.msg.parseUrls = parseUrls; + this.changes.parseUrls = parseUrls; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getParseUrls(): boolean { - return this.msg.parseUrls!; - } + public getParseUrls(): boolean { + return this.msg.parseUrls!; + } - public getMessage(): IMessage { - if (!this.msg.room) { - throw new Error('The "room" property is required.'); - } + public getMessage(): IMessage { + if (!this.msg.room) { + throw new Error('The "room" property is required.'); + } - return this.msg; - } + return this.msg; + } - public addBlocks(blocks: BlockBuilder | Array) { - if (!Array.isArray(this.msg.blocks)) { - this.msg.blocks = []; - } + public addBlocks(blocks: BlockBuilder | Array) { + if (!Array.isArray(this.msg.blocks)) { + this.msg.blocks = []; + } - if (blocks instanceof BlockBuilder) { - this.msg.blocks.push(...blocks.getBlocks()); - } else { - this.msg.blocks.push(...blocks); - } + if (blocks instanceof BlockBuilder) { + this.msg.blocks.push(...blocks.getBlocks()); + } else { + this.msg.blocks.push(...blocks); + } - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public setBlocks(blocks: BlockBuilder | Array) { - const blockArray: Array = blocks instanceof BlockBuilder ? blocks.getBlocks() : blocks; + public setBlocks(blocks: BlockBuilder | Array) { + const blockArray: Array = blocks instanceof BlockBuilder ? blocks.getBlocks() : blocks; - this.msg.blocks = blockArray; - this.changes.blocks = blockArray; + this.msg.blocks = blockArray; + this.changes.blocks = blockArray; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getBlocks() { - return this.msg.blocks!; - } + public getBlocks() { + return this.msg.blocks!; + } - public addCustomField(key: string, value: unknown): IMessageBuilder { - if (!this.msg.customFields) { - this.msg.customFields = {}; - } + public addCustomField(key: string, value: unknown): IMessageBuilder { + if (!this.msg.customFields) { + this.msg.customFields = {}; + } - if (this.msg.customFields[key]) { - throw new Error(`The message already contains a custom field by the key: ${key}`); - } + if (this.msg.customFields[key]) { + throw new Error(`The message already contains a custom field by the key: ${key}`); + } - if (key.includes('.')) { - throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); - } + if (key.includes('.')) { + throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); + } - this.msg.customFields[key] = value; + this.msg.customFields[key] = value; - this.customFieldsChanged = true; + this.customFieldsChanged = true; - return this as IMessageBuilder; - } + return this as IMessageBuilder; + } - public getChanges(): Partial { - const changes: typeof this.changes = structuredClone(this.changes); + public getChanges(): Partial { + const changes: typeof this.changes = structuredClone(this.changes); - if (this.attachmentsChanged) { - changes.attachments = structuredClone(this.msg.attachments); - } + if (this.attachmentsChanged) { + changes.attachments = structuredClone(this.msg.attachments); + } - if (this.customFieldsChanged) { - changes.customFields = structuredClone(this.msg.customFields); - } + if (this.customFieldsChanged) { + changes.customFields = structuredClone(this.msg.customFields); + } - return changes; - } + return changes; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts index 44119ab67ab41..208d476d32162 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts @@ -8,190 +8,190 @@ import type { RocketChatAssociationModel as _RocketChatAssociationModel } from ' import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class RoomBuilder implements IRoomBuilder { - public kind: _RocketChatAssociationModel.ROOM | _RocketChatAssociationModel.DISCUSSION; - - protected room: IRoom; - - private members: Array; - - private changes: Partial = {}; - private customFieldsChanged = false; - - constructor(data?: Partial) { - this.kind = RocketChatAssociationModel.ROOM; - this.room = (data || { customFields: {} }) as IRoom; - this.members = []; - } - - public setData(data: Partial): IRoomBuilder { - delete data.id; - this.room = data as IRoom; - - this.changes = structuredClone(this.room); - - return this; - } - - public setDisplayName(name: string): IRoomBuilder { - this.room.displayName = name; - this.changes.displayName = name; - - return this; - } + public kind: _RocketChatAssociationModel.ROOM | _RocketChatAssociationModel.DISCUSSION; + + protected room: IRoom; + + private members: Array; + + private changes: Partial = {}; + private customFieldsChanged = false; + + constructor(data?: Partial) { + this.kind = RocketChatAssociationModel.ROOM; + this.room = (data || { customFields: {} }) as IRoom; + this.members = []; + } + + public setData(data: Partial): IRoomBuilder { + delete data.id; + this.room = data as IRoom; + + this.changes = structuredClone(this.room); + + return this; + } + + public setDisplayName(name: string): IRoomBuilder { + this.room.displayName = name; + this.changes.displayName = name; + + return this; + } - public getDisplayName(): string { - return this.room.displayName!; - } + public getDisplayName(): string { + return this.room.displayName!; + } - public setSlugifiedName(name: string): IRoomBuilder { - this.room.slugifiedName = name; - this.changes.slugifiedName = name; + public setSlugifiedName(name: string): IRoomBuilder { + this.room.slugifiedName = name; + this.changes.slugifiedName = name; - return this; - } + return this; + } - public getSlugifiedName(): string { - return this.room.slugifiedName; - } - - public setType(type: RoomType): IRoomBuilder { - this.room.type = type; - this.changes.type = type; + public getSlugifiedName(): string { + return this.room.slugifiedName; + } + + public setType(type: RoomType): IRoomBuilder { + this.room.type = type; + this.changes.type = type; - return this; - } + return this; + } - public getType(): RoomType { - return this.room.type; - } + public getType(): RoomType { + return this.room.type; + } - public setCreator(creator: IUser): IRoomBuilder { - this.room.creator = creator; - this.changes.creator = creator; + public setCreator(creator: IUser): IRoomBuilder { + this.room.creator = creator; + this.changes.creator = creator; - return this; - } + return this; + } - public getCreator(): IUser { - return this.room.creator; - } + public getCreator(): IUser { + return this.room.creator; + } - /** - * @deprecated - */ - public addUsername(username: string): IRoomBuilder { - this.addMemberToBeAddedByUsername(username); - return this; - } + /** + * @deprecated + */ + public addUsername(username: string): IRoomBuilder { + this.addMemberToBeAddedByUsername(username); + return this; + } - /** - * @deprecated - */ - public setUsernames(usernames: Array): IRoomBuilder { - this.setMembersToBeAddedByUsernames(usernames); - return this; - } + /** + * @deprecated + */ + public setUsernames(usernames: Array): IRoomBuilder { + this.setMembersToBeAddedByUsernames(usernames); + return this; + } - /** - * @deprecated - */ - public getUsernames(): Array { - const usernames = this.getMembersToBeAddedUsernames(); - if (usernames && usernames.length > 0) { - return usernames; - } - return this.room.usernames || []; - } + /** + * @deprecated + */ + public getUsernames(): Array { + const usernames = this.getMembersToBeAddedUsernames(); + if (usernames && usernames.length > 0) { + return usernames; + } + return this.room.usernames || []; + } - public addMemberToBeAddedByUsername(username: string): IRoomBuilder { - this.members.push(username); - return this; - } + public addMemberToBeAddedByUsername(username: string): IRoomBuilder { + this.members.push(username); + return this; + } - public setMembersToBeAddedByUsernames(usernames: Array): IRoomBuilder { - this.members = usernames; - return this; - } + public setMembersToBeAddedByUsernames(usernames: Array): IRoomBuilder { + this.members = usernames; + return this; + } - public getMembersToBeAddedUsernames(): Array { - return this.members; - } + public getMembersToBeAddedUsernames(): Array { + return this.members; + } - public setDefault(isDefault: boolean): IRoomBuilder { - this.room.isDefault = isDefault; - this.changes.isDefault = isDefault; + public setDefault(isDefault: boolean): IRoomBuilder { + this.room.isDefault = isDefault; + this.changes.isDefault = isDefault; - return this; - } + return this; + } - public getIsDefault(): boolean { - return this.room.isDefault!; - } + public getIsDefault(): boolean { + return this.room.isDefault!; + } - public setReadOnly(isReadOnly: boolean): IRoomBuilder { - this.room.isReadOnly = isReadOnly; - this.changes.isReadOnly = isReadOnly; + public setReadOnly(isReadOnly: boolean): IRoomBuilder { + this.room.isReadOnly = isReadOnly; + this.changes.isReadOnly = isReadOnly; - return this; - } - - public getIsReadOnly(): boolean { - return this.room.isReadOnly!; - } - - public setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder { - this.room.displaySystemMessages = displaySystemMessages; - this.changes.displaySystemMessages = displaySystemMessages; - - return this; - } - - public getDisplayingOfSystemMessages(): boolean { - return this.room.displaySystemMessages!; - } - - public addCustomField(key: string, value: object): IRoomBuilder { - if (typeof this.room.customFields !== 'object') { - this.room.customFields = {}; - } - - this.room.customFields[key] = value; - - this.customFieldsChanged = true; - - return this; - } - - public setCustomFields(fields: { [key: string]: object }): IRoomBuilder { - this.room.customFields = fields; - this.customFieldsChanged = true; - - return this; - } - - public getCustomFields(): { [key: string]: object } { - return this.room.customFields!; - } - - public getUserIds(): Array { - return this.room.userIds!; - } - - public getRoom(): IRoom { - return this.room; - } - - public getChanges() { - const changes: Partial = structuredClone(this.changes); + return this; + } + + public getIsReadOnly(): boolean { + return this.room.isReadOnly!; + } + + public setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder { + this.room.displaySystemMessages = displaySystemMessages; + this.changes.displaySystemMessages = displaySystemMessages; + + return this; + } + + public getDisplayingOfSystemMessages(): boolean { + return this.room.displaySystemMessages!; + } + + public addCustomField(key: string, value: object): IRoomBuilder { + if (typeof this.room.customFields !== 'object') { + this.room.customFields = {}; + } + + this.room.customFields[key] = value; + + this.customFieldsChanged = true; + + return this; + } + + public setCustomFields(fields: { [key: string]: object }): IRoomBuilder { + this.room.customFields = fields; + this.customFieldsChanged = true; + + return this; + } + + public getCustomFields(): { [key: string]: object } { + return this.room.customFields!; + } + + public getUserIds(): Array { + return this.room.userIds!; + } + + public getRoom(): IRoom { + return this.room; + } + + public getChanges() { + const changes: Partial = structuredClone(this.changes); - if (this.customFieldsChanged) { - changes.customFields = structuredClone(this.room.customFields); - } + if (this.customFieldsChanged) { + changes.customFields = structuredClone(this.room.customFields); + } - return changes; - } + return changes; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts index 01c11a13f7a33..caaf9a69d5941 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts @@ -7,75 +7,75 @@ import type { RocketChatAssociationModel as _RocketChatAssociationModel } from ' import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class UserBuilder implements IUserBuilder { - public kind: _RocketChatAssociationModel.USER; + public kind: _RocketChatAssociationModel.USER; - private user: Partial; + private user: Partial; - constructor(user?: Partial) { - this.kind = RocketChatAssociationModel.USER; - this.user = user || ({} as Partial); - } + constructor(user?: Partial) { + this.kind = RocketChatAssociationModel.USER; + this.user = user || ({} as Partial); + } - public setData(data: Partial): IUserBuilder { - delete data.id; - this.user = data; + public setData(data: Partial): IUserBuilder { + delete data.id; + this.user = data; - return this; - } + return this; + } - public setEmails(emails: Array): IUserBuilder { - this.user.emails = emails; - return this; - } + public setEmails(emails: Array): IUserBuilder { + this.user.emails = emails; + return this; + } - public getEmails(): Array { - return this.user.emails!; - } + public getEmails(): Array { + return this.user.emails!; + } - public setDisplayName(name: string): IUserBuilder { - this.user.name = name; - return this; - } + public setDisplayName(name: string): IUserBuilder { + this.user.name = name; + return this; + } - public getDisplayName(): string { - return this.user.name!; - } + public getDisplayName(): string { + return this.user.name!; + } - public setUsername(username: string): IUserBuilder { - this.user.username = username; - return this; - } + public setUsername(username: string): IUserBuilder { + this.user.username = username; + return this; + } - public getUsername(): string { - return this.user.username!; - } + public getUsername(): string { + return this.user.username!; + } - public setRoles(roles: Array): IUserBuilder { - this.user.roles = roles; - return this; - } + public setRoles(roles: Array): IUserBuilder { + this.user.roles = roles; + return this; + } - public getRoles(): Array { - return this.user.roles!; - } + public getRoles(): Array { + return this.user.roles!; + } - public getSettings(): Partial { - return this.user.settings; - } + public getSettings(): Partial { + return this.user.settings; + } - public getUser(): Partial { - if (!this.user.username) { - throw new Error('The "username" property is required.'); - } + public getUser(): Partial { + if (!this.user.username) { + throw new Error('The "username" property is required.'); + } - if (!this.user.name) { - throw new Error('The "name" property is required.'); - } + if (!this.user.name) { + throw new Error('The "name" property is required.'); + } - return this.user; - } + return this.user; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts index e617cdddf154a..e1bc3f3cf5b24 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts @@ -6,89 +6,89 @@ import type { RocketChatAssociationModel as _RocketChatAssociationModel } from ' import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export type AppVideoConference = Pick & { - createdBy: IGroupVideoConference['createdBy']['_id']; + createdBy: IGroupVideoConference['createdBy']['_id']; }; export class VideoConferenceBuilder implements IVideoConferenceBuilder { - public kind: _RocketChatAssociationModel.VIDEO_CONFERENCE = RocketChatAssociationModel.VIDEO_CONFERENCE; - - protected call: AppVideoConference; - - constructor(data?: Partial) { - this.call = (data || {}) as AppVideoConference; - } - - public setData(data: Partial): IVideoConferenceBuilder { - this.call = { - rid: data.rid!, - createdBy: data.createdBy, - providerName: data.providerName!, - title: data.title!, - discussionRid: data.discussionRid, - }; - - return this; - } - - public setRoomId(rid: string): IVideoConferenceBuilder { - this.call.rid = rid; - return this; - } - - public getRoomId(): string { - return this.call.rid; - } - - public setCreatedBy(userId: string): IVideoConferenceBuilder { - this.call.createdBy = userId; - return this; - } - - public getCreatedBy(): string { - return this.call.createdBy; - } - - public setProviderName(userId: string): IVideoConferenceBuilder { - this.call.providerName = userId; - return this; - } - - public getProviderName(): string { - return this.call.providerName; - } - - public setProviderData(data: Record | undefined): IVideoConferenceBuilder { - this.call.providerData = data; - return this; - } - - public getProviderData(): Record { - return this.call.providerData!; - } - - public setTitle(userId: string): IVideoConferenceBuilder { - this.call.title = userId; - return this; - } - - public getTitle(): string { - return this.call.title; - } - - public setDiscussionRid(rid: AppVideoConference['discussionRid']): IVideoConferenceBuilder { - this.call.discussionRid = rid; - return this; - } - - public getDiscussionRid(): AppVideoConference['discussionRid'] { - return this.call.discussionRid; - } - - public getVideoConference(): AppVideoConference { - return this.call; - } + public kind: _RocketChatAssociationModel.VIDEO_CONFERENCE = RocketChatAssociationModel.VIDEO_CONFERENCE; + + protected call: AppVideoConference; + + constructor(data?: Partial) { + this.call = (data || {}) as AppVideoConference; + } + + public setData(data: Partial): IVideoConferenceBuilder { + this.call = { + rid: data.rid!, + createdBy: data.createdBy, + providerName: data.providerName!, + title: data.title!, + discussionRid: data.discussionRid, + }; + + return this; + } + + public setRoomId(rid: string): IVideoConferenceBuilder { + this.call.rid = rid; + return this; + } + + public getRoomId(): string { + return this.call.rid; + } + + public setCreatedBy(userId: string): IVideoConferenceBuilder { + this.call.createdBy = userId; + return this; + } + + public getCreatedBy(): string { + return this.call.createdBy; + } + + public setProviderName(userId: string): IVideoConferenceBuilder { + this.call.providerName = userId; + return this; + } + + public getProviderName(): string { + return this.call.providerName; + } + + public setProviderData(data: Record | undefined): IVideoConferenceBuilder { + this.call.providerData = data; + return this; + } + + public getProviderData(): Record { + return this.call.providerData!; + } + + public setTitle(userId: string): IVideoConferenceBuilder { + this.call.title = userId; + return this; + } + + public getTitle(): string { + return this.call.title; + } + + public setDiscussionRid(rid: AppVideoConference['discussionRid']): IVideoConferenceBuilder { + this.call.discussionRid = rid; + return this; + } + + public getDiscussionRid(): AppVideoConference['discussionRid'] { + return this.call.discussionRid; + } + + public getVideoConference(): AppVideoConference { + return this.call; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts index c323d385de9d6..8342850975017 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts @@ -1,62 +1,58 @@ -import type { - IHttpExtend, - IHttpPreRequestHandler, - IHttpPreResponseHandler -} from "@rocket.chat/apps-engine/definition/accessors/IHttp.ts"; +import type { IHttpExtend, IHttpPreRequestHandler, IHttpPreResponseHandler } from '@rocket.chat/apps-engine/definition/accessors/IHttp.ts'; export class HttpExtend implements IHttpExtend { - private headers: Map; + private headers: Map; - private params: Map; + private params: Map; - private requests: Array; + private requests: Array; - private responses: Array; + private responses: Array; - constructor() { - this.headers = new Map(); - this.params = new Map(); - this.requests = []; - this.responses = []; - } + constructor() { + this.headers = new Map(); + this.params = new Map(); + this.requests = []; + this.responses = []; + } - public provideDefaultHeader(key: string, value: string): void { - this.headers.set(key, value); - } + public provideDefaultHeader(key: string, value: string): void { + this.headers.set(key, value); + } - public provideDefaultHeaders(headers: { [key: string]: string }): void { - Object.keys(headers).forEach((key) => this.headers.set(key, headers[key])); - } + public provideDefaultHeaders(headers: { [key: string]: string }): void { + Object.keys(headers).forEach((key) => this.headers.set(key, headers[key])); + } - public provideDefaultParam(key: string, value: string): void { - this.params.set(key, value); - } + public provideDefaultParam(key: string, value: string): void { + this.params.set(key, value); + } - public provideDefaultParams(params: { [key: string]: string }): void { - Object.keys(params).forEach((key) => this.params.set(key, params[key])); - } + public provideDefaultParams(params: { [key: string]: string }): void { + Object.keys(params).forEach((key) => this.params.set(key, params[key])); + } - public providePreRequestHandler(handler: IHttpPreRequestHandler): void { - this.requests.push(handler); - } + public providePreRequestHandler(handler: IHttpPreRequestHandler): void { + this.requests.push(handler); + } - public providePreResponseHandler(handler: IHttpPreResponseHandler): void { - this.responses.push(handler); - } + public providePreResponseHandler(handler: IHttpPreResponseHandler): void { + this.responses.push(handler); + } - public getDefaultHeaders(): Map { - return new Map(this.headers); - } + public getDefaultHeaders(): Map { + return new Map(this.headers); + } - public getDefaultParams(): Map { - return new Map(this.params); - } + public getDefaultParams(): Map { + return new Map(this.params); + } - public getPreRequestHandlers(): Array { - return Array.from(this.requests); - } + public getPreRequestHandlers(): Array { + return Array.from(this.requests); + } - public getPreResponseHandlers(): Array { - return Array.from(this.responses); - } + public getPreResponseHandlers(): Array { + return Array.from(this.responses); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts index abf1629c760ac..1f45137e15d4b 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts @@ -6,61 +6,61 @@ import type { IMessageAttachment } from '@rocket.chat/apps-engine/definition/mes import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class MessageExtender implements IMessageExtender { - public readonly kind: _RocketChatAssociationModel.MESSAGE; + public readonly kind: _RocketChatAssociationModel.MESSAGE; - constructor(private msg: IMessage) { - this.kind = RocketChatAssociationModel.MESSAGE; + constructor(private msg: IMessage) { + this.kind = RocketChatAssociationModel.MESSAGE; - if (!Array.isArray(msg.attachments)) { - this.msg.attachments = []; - } - } + if (!Array.isArray(msg.attachments)) { + this.msg.attachments = []; + } + } - public addCustomField(key: string, value: unknown): IMessageExtender { - if (!this.msg.customFields) { - this.msg.customFields = {}; - } + public addCustomField(key: string, value: unknown): IMessageExtender { + if (!this.msg.customFields) { + this.msg.customFields = {}; + } - if (this.msg.customFields[key]) { - throw new Error(`The message already contains a custom field by the key: ${key}`); - } + if (this.msg.customFields[key]) { + throw new Error(`The message already contains a custom field by the key: ${key}`); + } - if (key.includes('.')) { - throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); - } + if (key.includes('.')) { + throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); + } - this.msg.customFields[key] = value; + this.msg.customFields[key] = value; - return this; - } + return this; + } - public addAttachment(attachment: IMessageAttachment): IMessageExtender { - this.ensureAttachment(); + public addAttachment(attachment: IMessageAttachment): IMessageExtender { + this.ensureAttachment(); - this.msg.attachments!.push(attachment); + this.msg.attachments!.push(attachment); - return this; - } + return this; + } - public addAttachments(attachments: Array): IMessageExtender { - this.ensureAttachment(); + public addAttachments(attachments: Array): IMessageExtender { + this.ensureAttachment(); - this.msg.attachments = this.msg.attachments!.concat(attachments); + this.msg.attachments = this.msg.attachments!.concat(attachments); - return this; - } + return this; + } - public getMessage(): IMessage { - return structuredClone(this.msg); - } + public getMessage(): IMessage { + return structuredClone(this.msg); + } - private ensureAttachment(): void { - if (!Array.isArray(this.msg.attachments)) { - this.msg.attachments = []; - } - } + private ensureAttachment(): void { + if (!Array.isArray(this.msg.attachments)) { + this.msg.attachments = []; + } + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts index 6509d5dae90e9..a138e08d2d28e 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts @@ -6,56 +6,56 @@ import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class RoomExtender implements IRoomExtender { - public kind: _RocketChatAssociationModel.ROOM; + public kind: _RocketChatAssociationModel.ROOM; - private members: Array; + private members: Array; - constructor(private room: IRoom) { - this.kind = RocketChatAssociationModel.ROOM; - this.members = []; - } + constructor(private room: IRoom) { + this.kind = RocketChatAssociationModel.ROOM; + this.members = []; + } - public addCustomField(key: string, value: unknown): IRoomExtender { - if (!this.room.customFields) { - this.room.customFields = {}; - } + public addCustomField(key: string, value: unknown): IRoomExtender { + if (!this.room.customFields) { + this.room.customFields = {}; + } - if (this.room.customFields[key]) { - throw new Error(`The room already contains a custom field by the key: ${key}`); - } + if (this.room.customFields[key]) { + throw new Error(`The room already contains a custom field by the key: ${key}`); + } - if (key.includes('.')) { - throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); - } + if (key.includes('.')) { + throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); + } - this.room.customFields[key] = value; + this.room.customFields[key] = value; - return this; - } + return this; + } - public addMember(user: IUser): IRoomExtender { - if (this.members.find((u) => u.username === user.username)) { - throw new Error('The user is already in the room.'); - } + public addMember(user: IUser): IRoomExtender { + if (this.members.find((u) => u.username === user.username)) { + throw new Error('The user is already in the room.'); + } - this.members.push(user); + this.members.push(user); - return this; - } + return this; + } - public getMembersBeingAdded(): Array { - return this.members; - } + public getMembersBeingAdded(): Array { + return this.members; + } - public getUsernamesOfMembersBeingAdded(): Array { - return this.members.map((u) => u.username); - } + public getUsernamesOfMembersBeingAdded(): Array { + return this.members.map((u) => u.username); + } - public getRoom(): IRoom { - return structuredClone(this.room); - } + public getRoom(): IRoom { + return structuredClone(this.room); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts index 9616bf619067d..c4b154f46cb32 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts @@ -6,64 +6,64 @@ import type { RocketChatAssociationModel as _RocketChatAssociationModel } from ' import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class VideoConferenceExtender implements IVideoConferenceExtender { - public kind: _RocketChatAssociationModel.VIDEO_CONFERENCE; + public kind: _RocketChatAssociationModel.VIDEO_CONFERENCE; - constructor(private videoConference: VideoConference) { - this.kind = RocketChatAssociationModel.VIDEO_CONFERENCE; - } + constructor(private videoConference: VideoConference) { + this.kind = RocketChatAssociationModel.VIDEO_CONFERENCE; + } - public setProviderData(value: Record): IVideoConferenceExtender { - this.videoConference.providerData = value; + public setProviderData(value: Record): IVideoConferenceExtender { + this.videoConference.providerData = value; - return this; - } + return this; + } - public setStatus(value: VideoConference['status']): IVideoConferenceExtender { - this.videoConference.status = value; + public setStatus(value: VideoConference['status']): IVideoConferenceExtender { + this.videoConference.status = value; - return this; - } + return this; + } - public setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender { - this.videoConference.endedBy = { - _id: value, - // Name and username will be loaded automatically by the bridge - username: '', - name: '', - }; + public setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender { + this.videoConference.endedBy = { + _id: value, + // Name and username will be loaded automatically by the bridge + username: '', + name: '', + }; - return this; - } + return this; + } - public setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender { - this.videoConference.endedAt = value; + public setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender { + this.videoConference.endedAt = value; - return this; - } + return this; + } - public addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender { - this.videoConference.users.push({ - _id: userId, - ts, - // Name and username will be loaded automatically by the bridge - username: '', - name: '', - }); + public addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender { + this.videoConference.users.push({ + _id: userId, + ts, + // Name and username will be loaded automatically by the bridge + username: '', + name: '', + }); - return this; - } + return this; + } - public setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender { - this.videoConference.discussionRid = rid; + public setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender { + this.videoConference.discussionRid = rid; - return this; - } + return this; + } - public getVideoConference(): VideoConference { - return structuredClone(this.videoConference); - } + public getVideoConference(): VideoConference { + return structuredClone(this.videoConference); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/http.ts b/packages/apps-engine/deno-runtime/lib/accessors/http.ts index f55838e601867..1a5e7098ef376 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/http.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/http.ts @@ -1,92 +1,87 @@ -import type { - IHttp, - IHttpExtend, - IHttpRequest, - IHttpResponse, -} from "@rocket.chat/apps-engine/definition/accessors/IHttp.ts"; -import type { IPersistence } from "@rocket.chat/apps-engine/definition/accessors/IPersistence.ts"; -import type { IRead } from "@rocket.chat/apps-engine/definition/accessors/IRead.ts"; +import type { IHttp, IHttpExtend, IHttpRequest, IHttpResponse } from '@rocket.chat/apps-engine/definition/accessors/IHttp.ts'; +import type { IPersistence } from '@rocket.chat/apps-engine/definition/accessors/IPersistence.ts'; +import type { IRead } from '@rocket.chat/apps-engine/definition/accessors/IRead.ts'; import * as Messenger from '../messenger.ts'; -import { AppObjectRegistry } from "../../AppObjectRegistry.ts"; +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; type RequestMethod = 'get' | 'post' | 'put' | 'head' | 'delete' | 'patch'; export class Http implements IHttp { - private httpExtender: IHttpExtend; - private read: IRead; - private persistence: IPersistence; - private senderFn: typeof Messenger.sendRequest; - - constructor(read: IRead, persistence: IPersistence, httpExtender: IHttpExtend, senderFn: typeof Messenger.sendRequest) { - this.read = read; - this.persistence = persistence; - this.httpExtender = httpExtender; - this.senderFn = senderFn; - // this.httpExtender = new HttpExtend(); - } - - public get(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, 'get', options); - } - - public put(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, 'put', options); - } - - public post(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, 'post', options); - } - - public del(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, 'delete', options); - } - - public patch(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, 'patch', options); - } - - private async _processHandler(url: string, method: RequestMethod, options?: IHttpRequest): Promise { - let request = options || {}; - - if (typeof request.headers === 'undefined') { - request.headers = {}; - } - - this.httpExtender.getDefaultHeaders().forEach((value: string, key: string) => { - if (typeof request.headers?.[key] !== 'string') { - request.headers![key] = value; - } - }); - - if (typeof request.params === 'undefined') { - request.params = {}; - } - - this.httpExtender.getDefaultParams().forEach((value: string, key: string) => { - if (typeof request.params?.[key] !== 'string') { - request.params![key] = value; - } - }); - - for (const handler of this.httpExtender.getPreRequestHandlers()) { - request = await handler.executePreHttpRequest(url, request, this.read, this.persistence); - } - - let { result: response } = await this.senderFn({ - method: `bridges:getHttpBridge:doCall`, - params: [{ - appId: AppObjectRegistry.get('id'), - method, - url, - request, - }], - }) - - for (const handler of this.httpExtender.getPreResponseHandlers()) { - response = await handler.executePreHttpResponse(response as IHttpResponse, this.read, this.persistence); - } - - return response as IHttpResponse; - } + private httpExtender: IHttpExtend; + private read: IRead; + private persistence: IPersistence; + private senderFn: typeof Messenger.sendRequest; + + constructor(read: IRead, persistence: IPersistence, httpExtender: IHttpExtend, senderFn: typeof Messenger.sendRequest) { + this.read = read; + this.persistence = persistence; + this.httpExtender = httpExtender; + this.senderFn = senderFn; + // this.httpExtender = new HttpExtend(); + } + + public get(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'get', options); + } + + public put(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'put', options); + } + + public post(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'post', options); + } + + public del(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'delete', options); + } + + public patch(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'patch', options); + } + + private async _processHandler(url: string, method: RequestMethod, options?: IHttpRequest): Promise { + let request = options || {}; + + if (typeof request.headers === 'undefined') { + request.headers = {}; + } + + this.httpExtender.getDefaultHeaders().forEach((value: string, key: string) => { + if (typeof request.headers?.[key] !== 'string') { + request.headers![key] = value; + } + }); + + if (typeof request.params === 'undefined') { + request.params = {}; + } + + this.httpExtender.getDefaultParams().forEach((value: string, key: string) => { + if (typeof request.params?.[key] !== 'string') { + request.params![key] = value; + } + }); + + for (const handler of this.httpExtender.getPreRequestHandlers()) { + request = await handler.executePreHttpRequest(url, request, this.read, this.persistence); + } + + let { result: response } = await this.senderFn({ + method: `bridges:getHttpBridge:doCall`, + params: [{ + appId: AppObjectRegistry.get('id'), + method, + url, + request, + }], + }); + + for (const handler of this.httpExtender.getPreResponseHandlers()) { + response = await handler.executePreHttpResponse(response as IHttpResponse, this.read, this.persistence); + } + + return response as IHttpResponse; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/mod.ts b/packages/apps-engine/deno-runtime/lib/accessors/mod.ts index 6cf4e38dbc6d7..4479a2fb6a14e 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/mod.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/mod.ts @@ -27,277 +27,277 @@ const httpMethods = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'] // We need to create this object first thing, as we'll handle references to it later on if (!AppObjectRegistry.has('apiEndpoints')) { - AppObjectRegistry.set('apiEndpoints', []); + AppObjectRegistry.set('apiEndpoints', []); } export class AppAccessors { - private defaultAppAccessors?: IAppAccessors; - private environmentRead?: IEnvironmentRead; - private environmentWriter?: IEnvironmentWrite; - private configModifier?: IConfigurationModify; - private configExtender?: IConfigurationExtend; - private reader?: IRead; - private modifier?: IModify; - private persistence?: IPersistence; - private creator?: ModifyCreator; - private updater?: ModifyUpdater; - private extender?: ModifyExtender; - private httpExtend: IHttpExtend = new HttpExtend(); - private http?: IHttp; - private notifier?: INotifier; - - private proxify: (namespace: string, overrides?: Record unknown>) => T; - - constructor(private readonly senderFn: typeof Messenger.sendRequest) { - this.proxify = (namespace: string, overrides: Record unknown> = {}): T => - new Proxy( - { __kind: `accessor:${namespace}` }, - { - get: - (_target: unknown, prop: string) => - (...params: unknown[]) => { - // We don't want to send a request for this prop - if (prop === 'toJSON') { - return {}; - } - - // If the prop is inteded to be overriden by the caller - if (prop in overrides) { - return overrides[prop].apply(undefined, params); - } - - return senderFn({ - method: `accessor:${namespace}:${prop}`, - params, - }) - .then((response) => response.result) - .catch((err) => { throw new Error(err.error) }); - }, - }, - ) as T; - - this.http = new Http(this.getReader(), this.getPersistence(), this.httpExtend, this.getSenderFn()); - this.notifier = new Notifier(this.getSenderFn()); - } - - public getSenderFn() { - return this.senderFn; - } - - public getEnvironmentRead(): IEnvironmentRead { - if (!this.environmentRead) { - this.environmentRead = { - getSettings: () => this.proxify('getEnvironmentRead:getSettings'), - getServerSettings: () => this.proxify('getEnvironmentRead:getServerSettings'), - getEnvironmentVariables: () => this.proxify('getEnvironmentRead:getEnvironmentVariables'), - }; - } - - return this.environmentRead; - } - - public getEnvironmentWrite() { - if (!this.environmentWriter) { - this.environmentWriter = { - getSettings: () => this.proxify('getEnvironmentWrite:getSettings'), - getServerSettings: () => this.proxify('getEnvironmentWrite:getServerSettings'), - }; - } - - return this.environmentWriter; - } - - public getConfigurationModify() { - if (!this.configModifier) { - this.configModifier = { - scheduler: this.proxify('getConfigurationModify:scheduler'), - slashCommands: { - _proxy: this.proxify('getConfigurationModify:slashCommands'), - modifySlashCommand(slashcommand: ISlashCommand) { - // Store the slashcommand instance to use when the Apps-Engine calls the slashcommand - AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand); - - return this._proxy.modifySlashCommand(slashcommand); - }, - disableSlashCommand(command: string) { - return this._proxy.disableSlashCommand(command); - }, - enableSlashCommand(command: string) { - return this._proxy.enableSlashCommand(command); - }, - }, - serverSettings: this.proxify('getConfigurationModify:serverSettings'), - }; - } - - return this.configModifier; - } - - public getConfigurationExtend() { - if (!this.configExtender) { - const senderFn = this.senderFn; - - this.configExtender = { - ui: this.proxify('getConfigurationExtend:ui'), - http: this.httpExtend, - settings: this.proxify('getConfigurationExtend:settings'), - externalComponents: this.proxify('getConfigurationExtend:externalComponents'), - api: { - _proxy: this.proxify('getConfigurationExtend:api'), - async provideApi(api: IApi) { - const apiEndpoints = AppObjectRegistry.get('apiEndpoints')!; - - api.endpoints.forEach((endpoint) => { - endpoint._availableMethods = httpMethods.filter((method) => typeof endpoint[method] === 'function'); - - // We need to keep a reference to the endpoint around for us to call the executor later - AppObjectRegistry.set(`api:${endpoint.path}`, endpoint); - }); - - const result = await this._proxy.provideApi(api); - - // Let's call the listApis method to cache the info from the endpoints - // Also, since this is a side-effect, we do it async so we can return to the caller - senderFn({ method: 'accessor:api:listApis' }) - .then((response) => apiEndpoints.push(...(response.result as IApiEndpointMetadata[]))) - .catch((err) => err.error); - - return result; - }, - }, - scheduler: { - _proxy: this.proxify('getConfigurationExtend:scheduler'), - registerProcessors(processors: IProcessor[]) { - // Store the processor instance to use when the Apps-Engine calls the processor - processors.forEach((processor) => { - AppObjectRegistry.set(`scheduler:${processor.id}`, processor); - }); - - return this._proxy.registerProcessors(processors); - }, - }, - videoConfProviders: { - _proxy: this.proxify('getConfigurationExtend:videoConfProviders'), - provideVideoConfProvider(provider: IVideoConfProvider) { - // Store the videoConfProvider instance to use when the Apps-Engine calls the videoConfProvider - AppObjectRegistry.set(`videoConfProvider:${provider.name}`, provider); - - return this._proxy.provideVideoConfProvider(provider); - }, - }, - slashCommands: { - _proxy: this.proxify('getConfigurationExtend:slashCommands'), - provideSlashCommand(slashcommand: ISlashCommand) { - // Store the slashcommand instance to use when the Apps-Engine calls the slashcommand - AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand); - - return this._proxy.provideSlashCommand(slashcommand); - }, - }, - }; - } - - return this.configExtender; - } - - public getDefaultAppAccessors() { - if (!this.defaultAppAccessors) { - this.defaultAppAccessors = { - environmentReader: this.getEnvironmentRead(), - environmentWriter: this.getEnvironmentWrite(), - reader: this.getReader(), - http: this.getHttp(), - providedApiEndpoints: AppObjectRegistry.get('apiEndpoints') as IApiEndpointMetadata[], - }; - } - - return this.defaultAppAccessors; - } - - public getReader() { - if (!this.reader) { - this.reader = { - getEnvironmentReader: () => ({ - getSettings: () => this.proxify('getReader:getEnvironmentReader:getSettings'), - getServerSettings: () => this.proxify('getReader:getEnvironmentReader:getServerSettings'), - getEnvironmentVariables: () => this.proxify('getReader:getEnvironmentReader:getEnvironmentVariables'), - }), - getMessageReader: () => this.proxify('getReader:getMessageReader'), - getPersistenceReader: () => this.proxify('getReader:getPersistenceReader'), - getRoomReader: () => this.proxify('getReader:getRoomReader'), - getUserReader: () => this.proxify('getReader:getUserReader'), - getNotifier: () => this.getNotifier(), - getLivechatReader: () => this.proxify('getReader:getLivechatReader'), - getUploadReader: () => this.proxify('getReader:getUploadReader'), - getCloudWorkspaceReader: () => this.proxify('getReader:getCloudWorkspaceReader'), - getVideoConferenceReader: () => this.proxify('getReader:getVideoConferenceReader'), - getOAuthAppsReader: () => this.proxify('getReader:getOAuthAppsReader'), - getThreadReader: () => this.proxify('getReader:getThreadReader'), - getRoleReader: () => this.proxify('getReader:getRoleReader'), - getContactReader: () => this.proxify('getReader:getContactReader'), - }; - } - - return this.reader; - } - - public getModifier() { - if (!this.modifier) { - this.modifier = { - getCreator: this.getCreator.bind(this), - getUpdater: this.getUpdater.bind(this), - getExtender: this.getExtender.bind(this), - getDeleter: () => this.proxify('getModifier:getDeleter'), - getNotifier: () => this.getNotifier(), - getUiController: () => this.proxify('getModifier:getUiController'), - getScheduler: () => this.proxify('getModifier:getScheduler'), - getOAuthAppsModifier: () => this.proxify('getModifier:getOAuthAppsModifier'), - getModerationModifier: () => this.proxify('getModifier:getModerationModifier'), - }; - } - - return this.modifier; - } - - public getPersistence() { - if (!this.persistence) { - this.persistence = this.proxify('getPersistence'); - } - - return this.persistence; - } - - public getHttp() { - return this.http; - } - - private getCreator() { - if (!this.creator) { - this.creator = new ModifyCreator(this.senderFn); - } - - return this.creator; - } - - private getUpdater() { - if (!this.updater) { - this.updater = new ModifyUpdater(this.senderFn); - } - - return this.updater; - } - - private getExtender() { - if (!this.extender) { - this.extender = new ModifyExtender(this.senderFn); - } - - return this.extender; - } - - private getNotifier() { - return this.notifier; - } + private defaultAppAccessors?: IAppAccessors; + private environmentRead?: IEnvironmentRead; + private environmentWriter?: IEnvironmentWrite; + private configModifier?: IConfigurationModify; + private configExtender?: IConfigurationExtend; + private reader?: IRead; + private modifier?: IModify; + private persistence?: IPersistence; + private creator?: ModifyCreator; + private updater?: ModifyUpdater; + private extender?: ModifyExtender; + private httpExtend: IHttpExtend = new HttpExtend(); + private http?: IHttp; + private notifier?: INotifier; + + private proxify: (namespace: string, overrides?: Record unknown>) => T; + + constructor(private readonly senderFn: typeof Messenger.sendRequest) { + this.proxify = (namespace: string, overrides: Record unknown> = {}): T => + new Proxy( + { __kind: `accessor:${namespace}` }, + { + get: (_target: unknown, prop: string) => (...params: unknown[]) => { + // We don't want to send a request for this prop + if (prop === 'toJSON') { + return {}; + } + + // If the prop is inteded to be overriden by the caller + if (prop in overrides) { + return overrides[prop].apply(undefined, params); + } + + return senderFn({ + method: `accessor:${namespace}:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }); + }, + }, + ) as T; + + this.http = new Http(this.getReader(), this.getPersistence(), this.httpExtend, this.getSenderFn()); + this.notifier = new Notifier(this.getSenderFn()); + } + + public getSenderFn() { + return this.senderFn; + } + + public getEnvironmentRead(): IEnvironmentRead { + if (!this.environmentRead) { + this.environmentRead = { + getSettings: () => this.proxify('getEnvironmentRead:getSettings'), + getServerSettings: () => this.proxify('getEnvironmentRead:getServerSettings'), + getEnvironmentVariables: () => this.proxify('getEnvironmentRead:getEnvironmentVariables'), + }; + } + + return this.environmentRead; + } + + public getEnvironmentWrite() { + if (!this.environmentWriter) { + this.environmentWriter = { + getSettings: () => this.proxify('getEnvironmentWrite:getSettings'), + getServerSettings: () => this.proxify('getEnvironmentWrite:getServerSettings'), + }; + } + + return this.environmentWriter; + } + + public getConfigurationModify() { + if (!this.configModifier) { + this.configModifier = { + scheduler: this.proxify('getConfigurationModify:scheduler'), + slashCommands: { + _proxy: this.proxify('getConfigurationModify:slashCommands'), + modifySlashCommand(slashcommand: ISlashCommand) { + // Store the slashcommand instance to use when the Apps-Engine calls the slashcommand + AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand); + + return this._proxy.modifySlashCommand(slashcommand); + }, + disableSlashCommand(command: string) { + return this._proxy.disableSlashCommand(command); + }, + enableSlashCommand(command: string) { + return this._proxy.enableSlashCommand(command); + }, + }, + serverSettings: this.proxify('getConfigurationModify:serverSettings'), + }; + } + + return this.configModifier; + } + + public getConfigurationExtend() { + if (!this.configExtender) { + const senderFn = this.senderFn; + + this.configExtender = { + ui: this.proxify('getConfigurationExtend:ui'), + http: this.httpExtend, + settings: this.proxify('getConfigurationExtend:settings'), + externalComponents: this.proxify('getConfigurationExtend:externalComponents'), + api: { + _proxy: this.proxify('getConfigurationExtend:api'), + async provideApi(api: IApi) { + const apiEndpoints = AppObjectRegistry.get('apiEndpoints')!; + + api.endpoints.forEach((endpoint) => { + endpoint._availableMethods = httpMethods.filter((method) => typeof endpoint[method] === 'function'); + + // We need to keep a reference to the endpoint around for us to call the executor later + AppObjectRegistry.set(`api:${endpoint.path}`, endpoint); + }); + + const result = await this._proxy.provideApi(api); + + // Let's call the listApis method to cache the info from the endpoints + // Also, since this is a side-effect, we do it async so we can return to the caller + senderFn({ method: 'accessor:api:listApis' }) + .then((response) => apiEndpoints.push(...(response.result as IApiEndpointMetadata[]))) + .catch((err) => err.error); + + return result; + }, + }, + scheduler: { + _proxy: this.proxify('getConfigurationExtend:scheduler'), + registerProcessors(processors: IProcessor[]) { + // Store the processor instance to use when the Apps-Engine calls the processor + processors.forEach((processor) => { + AppObjectRegistry.set(`scheduler:${processor.id}`, processor); + }); + + return this._proxy.registerProcessors(processors); + }, + }, + videoConfProviders: { + _proxy: this.proxify('getConfigurationExtend:videoConfProviders'), + provideVideoConfProvider(provider: IVideoConfProvider) { + // Store the videoConfProvider instance to use when the Apps-Engine calls the videoConfProvider + AppObjectRegistry.set(`videoConfProvider:${provider.name}`, provider); + + return this._proxy.provideVideoConfProvider(provider); + }, + }, + slashCommands: { + _proxy: this.proxify('getConfigurationExtend:slashCommands'), + provideSlashCommand(slashcommand: ISlashCommand) { + // Store the slashcommand instance to use when the Apps-Engine calls the slashcommand + AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand); + + return this._proxy.provideSlashCommand(slashcommand); + }, + }, + }; + } + + return this.configExtender; + } + + public getDefaultAppAccessors() { + if (!this.defaultAppAccessors) { + this.defaultAppAccessors = { + environmentReader: this.getEnvironmentRead(), + environmentWriter: this.getEnvironmentWrite(), + reader: this.getReader(), + http: this.getHttp(), + providedApiEndpoints: AppObjectRegistry.get('apiEndpoints') as IApiEndpointMetadata[], + }; + } + + return this.defaultAppAccessors; + } + + public getReader() { + if (!this.reader) { + this.reader = { + getEnvironmentReader: () => ({ + getSettings: () => this.proxify('getReader:getEnvironmentReader:getSettings'), + getServerSettings: () => this.proxify('getReader:getEnvironmentReader:getServerSettings'), + getEnvironmentVariables: () => this.proxify('getReader:getEnvironmentReader:getEnvironmentVariables'), + }), + getMessageReader: () => this.proxify('getReader:getMessageReader'), + getPersistenceReader: () => this.proxify('getReader:getPersistenceReader'), + getRoomReader: () => this.proxify('getReader:getRoomReader'), + getUserReader: () => this.proxify('getReader:getUserReader'), + getNotifier: () => this.getNotifier(), + getLivechatReader: () => this.proxify('getReader:getLivechatReader'), + getUploadReader: () => this.proxify('getReader:getUploadReader'), + getCloudWorkspaceReader: () => this.proxify('getReader:getCloudWorkspaceReader'), + getVideoConferenceReader: () => this.proxify('getReader:getVideoConferenceReader'), + getOAuthAppsReader: () => this.proxify('getReader:getOAuthAppsReader'), + getThreadReader: () => this.proxify('getReader:getThreadReader'), + getRoleReader: () => this.proxify('getReader:getRoleReader'), + getContactReader: () => this.proxify('getReader:getContactReader'), + }; + } + + return this.reader; + } + + public getModifier() { + if (!this.modifier) { + this.modifier = { + getCreator: this.getCreator.bind(this), + getUpdater: this.getUpdater.bind(this), + getExtender: this.getExtender.bind(this), + getDeleter: () => this.proxify('getModifier:getDeleter'), + getNotifier: () => this.getNotifier(), + getUiController: () => this.proxify('getModifier:getUiController'), + getScheduler: () => this.proxify('getModifier:getScheduler'), + getOAuthAppsModifier: () => this.proxify('getModifier:getOAuthAppsModifier'), + getModerationModifier: () => this.proxify('getModifier:getModerationModifier'), + }; + } + + return this.modifier; + } + + public getPersistence() { + if (!this.persistence) { + this.persistence = this.proxify('getPersistence'); + } + + return this.persistence; + } + + public getHttp() { + return this.http; + } + + private getCreator() { + if (!this.creator) { + this.creator = new ModifyCreator(this.senderFn); + } + + return this.creator; + } + + private getUpdater() { + if (!this.updater) { + this.updater = new ModifyUpdater(this.senderFn); + } + + return this.updater; + } + + private getExtender() { + if (!this.extender) { + this.extender = new ModifyExtender(this.senderFn); + } + + return this.extender; + } + + private getNotifier() { + return this.notifier; + } } export const AppAccessorsInstance = new AppAccessors(Messenger.sendRequest); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts index e209cb44ea8ef..38740aef1799e 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts @@ -33,358 +33,348 @@ const { UIHelper } = require('@rocket.chat/apps-engine/server/misc/UIHelper.js') const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; const { UserType } = require('@rocket.chat/apps-engine/definition/users/UserType.js') as { UserType: typeof _UserType }; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class ModifyCreator implements IModifyCreator { - constructor(private readonly senderFn: typeof Messenger.sendRequest) { } - - getLivechatCreator(): ILivechatCreator { - return new Proxy( - { __kind: 'getLivechatCreator' }, - { - get: (_target: unknown, prop: string) => { - // It's not worthwhile to make an asynchronous request for such a simple method - if (prop === 'createToken') { - return () => randomBytes(16).toString('hex'); - } - - if (prop === 'toJSON') { - return () => ({}); - } - - return (...params: unknown[]) => - this.senderFn({ - method: `accessor:getModifier:getCreator:getLivechatCreator:${prop}`, - params, - }) - .then((response) => response.result) - .catch((err) => { - if (err instanceof Error) { - throw err; - } - if (err?.error?.message) { - throw new Error(err.error.message); - } - throw new Error(err.error); - }); - }, - }, - ) as ILivechatCreator; - } - - getUploadCreator(): IUploadCreator { - return new Proxy( - { __kind: 'getUploadCreator' }, - { - get: - (_target: unknown, prop: string) => - (...params: unknown[]) => - prop === 'toJSON' - ? {} - : this.senderFn({ - method: `accessor:getModifier:getCreator:getUploadCreator:${prop}`, - params, - }) - .then((response) => response.result) - .catch((err) => { - if (err instanceof Error) { - throw err; - } - if (err?.error?.message) { - throw new Error(err.error.message); - } - throw new Error(err.error); - }), - }, - ) as IUploadCreator; - } - - getEmailCreator(): IEmailCreator { - return new Proxy( - { __kind: 'getEmailCreator' }, - { - get: (_target: unknown, prop: string) => - (...params: unknown[]) => - prop === 'toJSON' - ? {} - : this.senderFn({ - method: `accessor:getModifier:getCreator:getEmailCreator:${prop}`, - params - }) - .then((response) => response.result) - .catch((err) => { - if (err instanceof Error) { - throw err; - } - if (err?.error?.message) { - throw new Error(err.error.message); - } - throw new Error(err.error); - }), - } - ) - } - - getContactCreator(): IContactCreator { - return new Proxy( - { __kind: 'getContactCreator' }, - { - get: (_target: unknown, prop: string) => - (...params: unknown[]) => - prop === 'toJSON' - ? {} - : this.senderFn({ - method: `accessor:getModifier:getCreator:getContactCreator:${prop}`, - params - }) - .then((response) => response.result) - .catch((err) => { - if (err instanceof Error) { - throw err; - } - if (err?.error?.message) { - throw new Error(err.error.message); - } - throw new Error(err.error); - }), - } - ) - } - - getBlockBuilder() { - return new BlockBuilder(); - } - - startMessage(data?: IMessage) { - if (data) { - delete data.id; - } - - return new MessageBuilder(data); - } - - startLivechatMessage(data?: ILivechatMessage) { - if (data) { - delete data.id; - } - - return new LivechatMessageBuilder(data); - } - - startRoom(data?: IRoom) { - if (data) { - // @ts-ignore - this has been imported from the Apps-Engine - delete data.id; - } - - return new RoomBuilder(data); - } - - startDiscussion(data?: Partial) { - if (data) { - delete data.id; - } - - return new DiscussionBuilder(data); - } - - startVideoConference(data?: Partial) { - return new VideoConferenceBuilder(data); - } - - startBotUser(data?: Partial) { - if (data) { - delete data.id; - - const { roles } = data; - - if (roles?.length) { - const hasRole = roles - .map((role: string) => role.toLocaleLowerCase()) - .some((role: string) => role === 'admin' || role === 'owner' || role === 'moderator'); - - if (hasRole) { - throw new Error('Invalid role assigned to the user. Should not be admin, owner or moderator.'); - } - } - - if (!data.type) { - data.type = UserType.BOT; - } - } - - return new UserBuilder(data); - } - - public finish( - builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder, - ): Promise { - switch (builder.kind) { - case RocketChatAssociationModel.MESSAGE: - return this._finishMessage(builder as IMessageBuilder); - case RocketChatAssociationModel.LIVECHAT_MESSAGE: - return this._finishLivechatMessage(builder as ILivechatMessageBuilder); - case RocketChatAssociationModel.ROOM: - return this._finishRoom(builder as IRoomBuilder); - case RocketChatAssociationModel.DISCUSSION: - return this._finishDiscussion(builder as IDiscussionBuilder); - case RocketChatAssociationModel.VIDEO_CONFERENCE: - return this._finishVideoConference(builder as IVideoConferenceBuilder); - case RocketChatAssociationModel.USER: - return this._finishUser(builder as IUserBuilder); - default: - throw new Error('Invalid builder passed to the ModifyCreator.finish function.'); - } - } - - private async _finishMessage(builder: IMessageBuilder): Promise { - const result = builder.getMessage(); - delete result.id; - - if (!result.sender || !result.sender.id) { - const response = await this.senderFn({ - method: 'bridges:getUserBridge:doGetAppUser', - params: ['APP_ID'], - }); - - const appUser = response.result; - - if (!appUser) { - throw new Error('Invalid sender assigned to the message.'); - } - - result.sender = appUser; - } - - if (result.blocks?.length) { - // Can we move this elsewhere? This AppObjectRegistry usage doesn't really belong here, but where? - result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || ''); - } - - const response = await this.senderFn({ - method: 'bridges:getMessageBridge:doCreate', - params: [result, AppObjectRegistry.get('id')], - }); - - return String(response.result); - } - - private async _finishLivechatMessage(builder: ILivechatMessageBuilder): Promise { - if (builder.getSender() && !builder.getVisitor()) { - return this._finishMessage(builder.getMessageBuilder()); - } - - const result = builder.getMessage(); - delete result.id; - - if (!result.token && (!result.visitor || !result.visitor.token)) { - throw new Error('Invalid visitor sending the message'); - } - - result.token = result.visitor ? result.visitor.token : result.token; - - const response = await this.senderFn({ - method: 'bridges:getLivechatBridge:doCreateMessage', - params: [result, AppObjectRegistry.get('id')], - }); - - return String(response.result); - } - - private async _finishRoom(builder: IRoomBuilder): Promise { - const result = builder.getRoom(); - delete result.id; - - if (!result.type) { - throw new Error('Invalid type assigned to the room.'); - } - - if (result.type !== RoomType.LIVE_CHAT) { - if (!result.creator || !result.creator.id) { - throw new Error('Invalid creator assigned to the room.'); - } - } - - if (result.type !== RoomType.DIRECT_MESSAGE) { - if (result.type !== RoomType.LIVE_CHAT) { - if (!result.slugifiedName || !result.slugifiedName.trim()) { - throw new Error('Invalid slugifiedName assigned to the room.'); - } - } - - if (!result.displayName || !result.displayName.trim()) { - throw new Error('Invalid displayName assigned to the room.'); - } - } - - const response = await this.senderFn({ - method: 'bridges:getRoomBridge:doCreate', - params: [result, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], - }); - - return String(response.result); - } - - private async _finishDiscussion(builder: IDiscussionBuilder): Promise { - const room = builder.getRoom(); - delete room.id; - - if (!room.creator || !room.creator.id) { - throw new Error('Invalid creator assigned to the discussion.'); - } - - if (!room.slugifiedName || !room.slugifiedName.trim()) { - throw new Error('Invalid slugifiedName assigned to the discussion.'); - } + constructor(private readonly senderFn: typeof Messenger.sendRequest) {} + + getLivechatCreator(): ILivechatCreator { + return new Proxy( + { __kind: 'getLivechatCreator' }, + { + get: (_target: unknown, prop: string) => { + // It's not worthwhile to make an asynchronous request for such a simple method + if (prop === 'createToken') { + return () => randomBytes(16).toString('hex'); + } + + if (prop === 'toJSON') { + return () => ({}); + } + + return (...params: unknown[]) => + this.senderFn({ + method: `accessor:getModifier:getCreator:getLivechatCreator:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + if (err instanceof Error) { + throw err; + } + if (err?.error?.message) { + throw new Error(err.error.message); + } + throw new Error(err.error); + }); + }, + }, + ) as ILivechatCreator; + } + + getUploadCreator(): IUploadCreator { + return new Proxy( + { __kind: 'getUploadCreator' }, + { + get: (_target: unknown, prop: string) => (...params: unknown[]) => + prop === 'toJSON' ? {} : this.senderFn({ + method: `accessor:getModifier:getCreator:getUploadCreator:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + if (err instanceof Error) { + throw err; + } + if (err?.error?.message) { + throw new Error(err.error.message); + } + throw new Error(err.error); + }), + }, + ) as IUploadCreator; + } + + getEmailCreator(): IEmailCreator { + return new Proxy( + { __kind: 'getEmailCreator' }, + { + get: (_target: unknown, prop: string) => (...params: unknown[]) => + prop === 'toJSON' ? {} : this.senderFn({ + method: `accessor:getModifier:getCreator:getEmailCreator:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + if (err instanceof Error) { + throw err; + } + if (err?.error?.message) { + throw new Error(err.error.message); + } + throw new Error(err.error); + }), + }, + ); + } + + getContactCreator(): IContactCreator { + return new Proxy( + { __kind: 'getContactCreator' }, + { + get: (_target: unknown, prop: string) => (...params: unknown[]) => + prop === 'toJSON' ? {} : this.senderFn({ + method: `accessor:getModifier:getCreator:getContactCreator:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + if (err instanceof Error) { + throw err; + } + if (err?.error?.message) { + throw new Error(err.error.message); + } + throw new Error(err.error); + }), + }, + ); + } + + getBlockBuilder() { + return new BlockBuilder(); + } + + startMessage(data?: IMessage) { + if (data) { + delete data.id; + } + + return new MessageBuilder(data); + } + + startLivechatMessage(data?: ILivechatMessage) { + if (data) { + delete data.id; + } + + return new LivechatMessageBuilder(data); + } + + startRoom(data?: IRoom) { + if (data) { + // @ts-ignore - this has been imported from the Apps-Engine + delete data.id; + } + + return new RoomBuilder(data); + } + + startDiscussion(data?: Partial) { + if (data) { + delete data.id; + } + + return new DiscussionBuilder(data); + } + + startVideoConference(data?: Partial) { + return new VideoConferenceBuilder(data); + } + + startBotUser(data?: Partial) { + if (data) { + delete data.id; + + const { roles } = data; + + if (roles?.length) { + const hasRole = roles + .map((role: string) => role.toLocaleLowerCase()) + .some((role: string) => role === 'admin' || role === 'owner' || role === 'moderator'); + + if (hasRole) { + throw new Error('Invalid role assigned to the user. Should not be admin, owner or moderator.'); + } + } + + if (!data.type) { + data.type = UserType.BOT; + } + } + + return new UserBuilder(data); + } + + public finish( + builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder, + ): Promise { + switch (builder.kind) { + case RocketChatAssociationModel.MESSAGE: + return this._finishMessage(builder as IMessageBuilder); + case RocketChatAssociationModel.LIVECHAT_MESSAGE: + return this._finishLivechatMessage(builder as ILivechatMessageBuilder); + case RocketChatAssociationModel.ROOM: + return this._finishRoom(builder as IRoomBuilder); + case RocketChatAssociationModel.DISCUSSION: + return this._finishDiscussion(builder as IDiscussionBuilder); + case RocketChatAssociationModel.VIDEO_CONFERENCE: + return this._finishVideoConference(builder as IVideoConferenceBuilder); + case RocketChatAssociationModel.USER: + return this._finishUser(builder as IUserBuilder); + default: + throw new Error('Invalid builder passed to the ModifyCreator.finish function.'); + } + } + + private async _finishMessage(builder: IMessageBuilder): Promise { + const result = builder.getMessage(); + delete result.id; + + if (!result.sender || !result.sender.id) { + const response = await this.senderFn({ + method: 'bridges:getUserBridge:doGetAppUser', + params: ['APP_ID'], + }); + + const appUser = response.result; + + if (!appUser) { + throw new Error('Invalid sender assigned to the message.'); + } + + result.sender = appUser; + } + + if (result.blocks?.length) { + // Can we move this elsewhere? This AppObjectRegistry usage doesn't really belong here, but where? + result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || ''); + } + + const response = await this.senderFn({ + method: 'bridges:getMessageBridge:doCreate', + params: [result, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishLivechatMessage(builder: ILivechatMessageBuilder): Promise { + if (builder.getSender() && !builder.getVisitor()) { + return this._finishMessage(builder.getMessageBuilder()); + } + + const result = builder.getMessage(); + delete result.id; + + if (!result.token && (!result.visitor || !result.visitor.token)) { + throw new Error('Invalid visitor sending the message'); + } + + result.token = result.visitor ? result.visitor.token : result.token; + + const response = await this.senderFn({ + method: 'bridges:getLivechatBridge:doCreateMessage', + params: [result, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishRoom(builder: IRoomBuilder): Promise { + const result = builder.getRoom(); + delete result.id; + + if (!result.type) { + throw new Error('Invalid type assigned to the room.'); + } + + if (result.type !== RoomType.LIVE_CHAT) { + if (!result.creator || !result.creator.id) { + throw new Error('Invalid creator assigned to the room.'); + } + } + + if (result.type !== RoomType.DIRECT_MESSAGE) { + if (result.type !== RoomType.LIVE_CHAT) { + if (!result.slugifiedName || !result.slugifiedName.trim()) { + throw new Error('Invalid slugifiedName assigned to the room.'); + } + } + + if (!result.displayName || !result.displayName.trim()) { + throw new Error('Invalid displayName assigned to the room.'); + } + } + + const response = await this.senderFn({ + method: 'bridges:getRoomBridge:doCreate', + params: [result, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishDiscussion(builder: IDiscussionBuilder): Promise { + const room = builder.getRoom(); + delete room.id; + + if (!room.creator || !room.creator.id) { + throw new Error('Invalid creator assigned to the discussion.'); + } + + if (!room.slugifiedName || !room.slugifiedName.trim()) { + throw new Error('Invalid slugifiedName assigned to the discussion.'); + } - if (!room.displayName || !room.displayName.trim()) { - throw new Error('Invalid displayName assigned to the discussion.'); - } + if (!room.displayName || !room.displayName.trim()) { + throw new Error('Invalid displayName assigned to the discussion.'); + } - if (!room.parentRoom || !room.parentRoom.id) { - throw new Error('Invalid parentRoom assigned to the discussion.'); - } + if (!room.parentRoom || !room.parentRoom.id) { + throw new Error('Invalid parentRoom assigned to the discussion.'); + } - const response = await this.senderFn({ - method: 'bridges:getRoomBridge:doCreateDiscussion', - params: [room, builder.getParentMessage(), builder.getReply(), builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], - }); - - return String(response.result); - } + const response = await this.senderFn({ + method: 'bridges:getRoomBridge:doCreateDiscussion', + params: [room, builder.getParentMessage(), builder.getReply(), builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], + }); + + return String(response.result); + } - private async _finishVideoConference(builder: IVideoConferenceBuilder): Promise { - const videoConference = builder.getVideoConference(); + private async _finishVideoConference(builder: IVideoConferenceBuilder): Promise { + const videoConference = builder.getVideoConference(); - if (!videoConference.createdBy) { - throw new Error('Invalid creator assigned to the video conference.'); - } + if (!videoConference.createdBy) { + throw new Error('Invalid creator assigned to the video conference.'); + } - if (!videoConference.providerName?.trim()) { - throw new Error('Invalid provider name assigned to the video conference.'); - } + if (!videoConference.providerName?.trim()) { + throw new Error('Invalid provider name assigned to the video conference.'); + } - if (!videoConference.rid) { - throw new Error('Invalid roomId assigned to the video conference.'); - } + if (!videoConference.rid) { + throw new Error('Invalid roomId assigned to the video conference.'); + } - const response = await this.senderFn({ - method: 'bridges:getVideoConferenceBridge:doCreate', - params: [videoConference, AppObjectRegistry.get('id')], - }); + const response = await this.senderFn({ + method: 'bridges:getVideoConferenceBridge:doCreate', + params: [videoConference, AppObjectRegistry.get('id')], + }); - return String(response.result); - } + return String(response.result); + } - private async _finishUser(builder: IUserBuilder): Promise { - const user = builder.getUser(); - - const response = await this.senderFn({ - method: 'bridges:getUserBridge:doCreate', - params: [user, AppObjectRegistry.get('id')], - }); - - return String(response.result); - } + private async _finishUser(builder: IUserBuilder): Promise { + const user = builder.getUser(); + + const response = await this.senderFn({ + method: 'bridges:getUserBridge:doCreate', + params: [user, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts index c0793d015c640..d9e9678e376d1 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts @@ -16,78 +16,78 @@ import { VideoConferenceExtender } from '../extenders/VideoConferenceExtend.ts'; import { require } from '../../../lib/require.ts'; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class ModifyExtender implements IModifyExtender { - constructor(private readonly senderFn: typeof Messenger.sendRequest) {} - - public async extendMessage(messageId: string, updater: IUser): Promise { - const result = await this.senderFn({ - method: 'bridges:getMessageBridge:doGetById', - params: [messageId, AppObjectRegistry.get('id')], - }); - - const msg = result.result as IMessage; - - msg.editor = updater; - msg.editedAt = new Date(); - - return new MessageExtender(msg); - } - - public async extendRoom(roomId: string, _updater: IUser): Promise { - const result = await this.senderFn({ - method: 'bridges:getRoomBridge:doGetById', - params: [roomId, AppObjectRegistry.get('id')], - }); - - const room = result.result as IRoom; - - room.updatedAt = new Date(); - - return new RoomExtender(room); - } - - public async extendVideoConference(id: string): Promise { - const result = await this.senderFn({ - method: 'bridges:getVideoConferenceBridge:doGetById', - params: [id, AppObjectRegistry.get('id')], - }); - - const call = result.result as VideoConference; - - call._updatedAt = new Date(); - - return new VideoConferenceExtender(call); - } - - public async finish(extender: IMessageExtender | IRoomExtender | IVideoConferenceExtender): Promise { - switch (extender.kind) { - case RocketChatAssociationModel.MESSAGE: - await this.senderFn({ - method: 'bridges:getMessageBridge:doUpdate', - params: [(extender as IMessageExtender).getMessage(), AppObjectRegistry.get('id')], - }); - break; - case RocketChatAssociationModel.ROOM: - await this.senderFn({ - method: 'bridges:getRoomBridge:doUpdate', - params: [ - (extender as IRoomExtender).getRoom(), - (extender as IRoomExtender).getUsernamesOfMembersBeingAdded(), - AppObjectRegistry.get('id'), - ], - }); - break; - case RocketChatAssociationModel.VIDEO_CONFERENCE: - await this.senderFn({ - method: 'bridges:getVideoConferenceBridge:doUpdate', - params: [(extender as IVideoConferenceExtender).getVideoConference(), AppObjectRegistry.get('id')], - }); - break; - default: - throw new Error('Invalid extender passed to the ModifyExtender.finish function.'); - } - } + constructor(private readonly senderFn: typeof Messenger.sendRequest) {} + + public async extendMessage(messageId: string, updater: IUser): Promise { + const result = await this.senderFn({ + method: 'bridges:getMessageBridge:doGetById', + params: [messageId, AppObjectRegistry.get('id')], + }); + + const msg = result.result as IMessage; + + msg.editor = updater; + msg.editedAt = new Date(); + + return new MessageExtender(msg); + } + + public async extendRoom(roomId: string, _updater: IUser): Promise { + const result = await this.senderFn({ + method: 'bridges:getRoomBridge:doGetById', + params: [roomId, AppObjectRegistry.get('id')], + }); + + const room = result.result as IRoom; + + room.updatedAt = new Date(); + + return new RoomExtender(room); + } + + public async extendVideoConference(id: string): Promise { + const result = await this.senderFn({ + method: 'bridges:getVideoConferenceBridge:doGetById', + params: [id, AppObjectRegistry.get('id')], + }); + + const call = result.result as VideoConference; + + call._updatedAt = new Date(); + + return new VideoConferenceExtender(call); + } + + public async finish(extender: IMessageExtender | IRoomExtender | IVideoConferenceExtender): Promise { + switch (extender.kind) { + case RocketChatAssociationModel.MESSAGE: + await this.senderFn({ + method: 'bridges:getMessageBridge:doUpdate', + params: [(extender as IMessageExtender).getMessage(), AppObjectRegistry.get('id')], + }); + break; + case RocketChatAssociationModel.ROOM: + await this.senderFn({ + method: 'bridges:getRoomBridge:doUpdate', + params: [ + (extender as IRoomExtender).getRoom(), + (extender as IRoomExtender).getUsernamesOfMembersBeingAdded(), + AppObjectRegistry.get('id'), + ], + }); + break; + case RocketChatAssociationModel.VIDEO_CONFERENCE: + await this.senderFn({ + method: 'bridges:getVideoConferenceBridge:doUpdate', + params: [(extender as IVideoConferenceExtender).getVideoConference(), AppObjectRegistry.get('id')], + }); + break; + default: + throw new Error('Invalid extender passed to the ModifyExtender.finish function.'); + } + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts index fbdeee609e9d2..6664f86092fa5 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts @@ -22,140 +22,132 @@ import { require } from '../../../lib/require.ts'; const { UIHelper } = require('@rocket.chat/apps-engine/server/misc/UIHelper.js') as { UIHelper: typeof _UIHelper }; const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { - RocketChatAssociationModel: typeof _RocketChatAssociationModel; + RocketChatAssociationModel: typeof _RocketChatAssociationModel; }; export class ModifyUpdater implements IModifyUpdater { - constructor(private readonly senderFn: typeof Messenger.sendRequest) { } - - public getLivechatUpdater(): ILivechatUpdater { - return new Proxy( - { __kind: 'getLivechatUpdater' }, - { - get: - (_target: unknown, prop: string) => - (...params: unknown[]) => - prop === 'toJSON' - ? {} - : this.senderFn({ - method: `accessor:getModifier:getUpdater:getLivechatUpdater:${prop}`, - params, - }) - .then((response) => response.result) - .catch((err) => { - throw new Error(err.error); - }), - }, - ) as ILivechatUpdater; - } - - public getUserUpdater(): IUserUpdater { - return new Proxy( - { __kind: 'getUserUpdater' }, - { - get: - (_target: unknown, prop: string) => - (...params: unknown[]) => - prop === 'toJSON' - ? {} - : this.senderFn({ - method: `accessor:getModifier:getUpdater:getUserUpdater:${prop}`, - params, - }) - .then((response) => response.result) - .catch((err) => { - throw new Error(err.error); - }), - }, - ) as IUserUpdater; - } - - public async message(messageId: string, editor: IUser): Promise { - const response = await this.senderFn({ - method: 'bridges:getMessageBridge:doGetById', - params: [messageId, AppObjectRegistry.get('id')], - }); - - const builder = new MessageBuilder(response.result as IMessage); - - builder.setEditor(editor); - - return builder; - } - - public async room(roomId: string, _updater: IUser): Promise { - const response = await this.senderFn({ - method: 'bridges:getRoomBridge:doGetById', - params: [roomId, AppObjectRegistry.get('id')], - }); - - return new RoomBuilder(response.result as IRoom); - } - - public finish(builder: IMessageBuilder | IRoomBuilder): Promise { - switch (builder.kind) { - case RocketChatAssociationModel.MESSAGE: - return this._finishMessage(builder as MessageBuilder); - case RocketChatAssociationModel.ROOM: - return this._finishRoom(builder as RoomBuilder); - default: - throw new Error('Invalid builder passed to the ModifyUpdater.finish function.'); - } - } - - private async _finishMessage(builder: MessageBuilder): Promise { - const result = builder.getMessage(); - - if (!result.id) { - throw new Error("Invalid message, can't update a message without an id."); - } - - if (!result.sender?.id) { - throw new Error('Invalid sender assigned to the message.'); - } - - if (result.blocks?.length) { - result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || ''); - } - - const changes = { id: result.id, ...builder.getChanges() }; - - await this.senderFn({ - method: 'bridges:getMessageBridge:doUpdate', - params: [changes, AppObjectRegistry.get('id')], - }); - } - - private async _finishRoom(builder: RoomBuilder): Promise { - const room = builder.getRoom(); - - if (!room.id) { - throw new Error("Invalid room, can't update a room without an id."); - } - - if (!room.type) { - throw new Error('Invalid type assigned to the room.'); - } - - if (room.type !== RoomType.LIVE_CHAT) { - if (!room.creator || !room.creator.id) { - throw new Error('Invalid creator assigned to the room.'); - } - - if (!room.slugifiedName || !room.slugifiedName.trim()) { - throw new Error('Invalid slugifiedName assigned to the room.'); - } - } - - if (!room.displayName || !room.displayName.trim()) { - throw new Error('Invalid displayName assigned to the room.'); - } - - const changes = { id: room.id, ...builder.getChanges() }; - - await this.senderFn({ - method: 'bridges:getRoomBridge:doUpdate', - params: [changes, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], - }); - } + constructor(private readonly senderFn: typeof Messenger.sendRequest) {} + + public getLivechatUpdater(): ILivechatUpdater { + return new Proxy( + { __kind: 'getLivechatUpdater' }, + { + get: (_target: unknown, prop: string) => (...params: unknown[]) => + prop === 'toJSON' ? {} : this.senderFn({ + method: `accessor:getModifier:getUpdater:getLivechatUpdater:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }), + }, + ) as ILivechatUpdater; + } + + public getUserUpdater(): IUserUpdater { + return new Proxy( + { __kind: 'getUserUpdater' }, + { + get: (_target: unknown, prop: string) => (...params: unknown[]) => + prop === 'toJSON' ? {} : this.senderFn({ + method: `accessor:getModifier:getUpdater:getUserUpdater:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }), + }, + ) as IUserUpdater; + } + + public async message(messageId: string, editor: IUser): Promise { + const response = await this.senderFn({ + method: 'bridges:getMessageBridge:doGetById', + params: [messageId, AppObjectRegistry.get('id')], + }); + + const builder = new MessageBuilder(response.result as IMessage); + + builder.setEditor(editor); + + return builder; + } + + public async room(roomId: string, _updater: IUser): Promise { + const response = await this.senderFn({ + method: 'bridges:getRoomBridge:doGetById', + params: [roomId, AppObjectRegistry.get('id')], + }); + + return new RoomBuilder(response.result as IRoom); + } + + public finish(builder: IMessageBuilder | IRoomBuilder): Promise { + switch (builder.kind) { + case RocketChatAssociationModel.MESSAGE: + return this._finishMessage(builder as MessageBuilder); + case RocketChatAssociationModel.ROOM: + return this._finishRoom(builder as RoomBuilder); + default: + throw new Error('Invalid builder passed to the ModifyUpdater.finish function.'); + } + } + + private async _finishMessage(builder: MessageBuilder): Promise { + const result = builder.getMessage(); + + if (!result.id) { + throw new Error("Invalid message, can't update a message without an id."); + } + + if (!result.sender?.id) { + throw new Error('Invalid sender assigned to the message.'); + } + + if (result.blocks?.length) { + result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || ''); + } + + const changes = { id: result.id, ...builder.getChanges() }; + + await this.senderFn({ + method: 'bridges:getMessageBridge:doUpdate', + params: [changes, AppObjectRegistry.get('id')], + }); + } + + private async _finishRoom(builder: RoomBuilder): Promise { + const room = builder.getRoom(); + + if (!room.id) { + throw new Error("Invalid room, can't update a room without an id."); + } + + if (!room.type) { + throw new Error('Invalid type assigned to the room.'); + } + + if (room.type !== RoomType.LIVE_CHAT) { + if (!room.creator || !room.creator.id) { + throw new Error('Invalid creator assigned to the room.'); + } + + if (!room.slugifiedName || !room.slugifiedName.trim()) { + throw new Error('Invalid slugifiedName assigned to the room.'); + } + } + + if (!room.displayName || !room.displayName.trim()) { + throw new Error('Invalid displayName assigned to the room.'); + } + + const changes = { id: room.id, ...builder.getChanges() }; + + await this.senderFn({ + method: 'bridges:getRoomBridge:doUpdate', + params: [changes, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], + }); + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts b/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts index 625d68c1039ff..81868c2a85b06 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts @@ -7,69 +7,69 @@ import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import { MessageBuilder } from './builders/MessageBuilder.ts'; import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import * as Messenger from '../messenger.ts'; -import { require } from "../require.ts"; +import { require } from '../require.ts'; const { TypingScope } = require('@rocket.chat/apps-engine/definition/accessors/INotifier.js') as { - TypingScope: typeof _TypingScope; + TypingScope: typeof _TypingScope; }; export class Notifier implements INotifier { - private senderFn: typeof Messenger.sendRequest; + private senderFn: typeof Messenger.sendRequest; - constructor(senderFn: typeof Messenger.sendRequest) { - this.senderFn = senderFn; - } + constructor(senderFn: typeof Messenger.sendRequest) { + this.senderFn = senderFn; + } - public async notifyUser(user: IUser, message: IMessage): Promise { - if (!message.sender || !message.sender.id) { - const appUser = await this.getAppUser(); + public async notifyUser(user: IUser, message: IMessage): Promise { + if (!message.sender || !message.sender.id) { + const appUser = await this.getAppUser(); - message.sender = appUser; - } + message.sender = appUser; + } - await this.callMessageBridge('doNotifyUser', [user, message, AppObjectRegistry.get('id')]); - } + await this.callMessageBridge('doNotifyUser', [user, message, AppObjectRegistry.get('id')]); + } - public async notifyRoom(room: IRoom, message: IMessage): Promise { - if (!message.sender || !message.sender.id) { - const appUser = await this.getAppUser(); + public async notifyRoom(room: IRoom, message: IMessage): Promise { + if (!message.sender || !message.sender.id) { + const appUser = await this.getAppUser(); - message.sender = appUser; - } + message.sender = appUser; + } - await this.callMessageBridge('doNotifyRoom', [room, message, AppObjectRegistry.get('id')]); - } + await this.callMessageBridge('doNotifyRoom', [room, message, AppObjectRegistry.get('id')]); + } - public async typing(options: ITypingOptions): Promise<() => Promise> { - options.scope = options.scope || TypingScope.Room; + public async typing(options: ITypingOptions): Promise<() => Promise> { + options.scope = options.scope || TypingScope.Room; - if (!options.username) { - const appUser = await this.getAppUser(); - options.username = (appUser && appUser.name) || ''; - } + if (!options.username) { + const appUser = await this.getAppUser(); + options.username = (appUser && appUser.name) || ''; + } - const appId = AppObjectRegistry.get('id'); + const appId = AppObjectRegistry.get('id'); - await this.callMessageBridge('doTyping', [{ ...options, isTyping: true }, appId]); + await this.callMessageBridge('doTyping', [{ ...options, isTyping: true }, appId]); - return async () => { - await this.callMessageBridge('doTyping', [{ ...options, isTyping: false }, appId]); - }; - } + return async () => { + await this.callMessageBridge('doTyping', [{ ...options, isTyping: false }, appId]); + }; + } - public getMessageBuilder(): IMessageBuilder { - return new MessageBuilder(); - } + public getMessageBuilder(): IMessageBuilder { + return new MessageBuilder(); + } - private async callMessageBridge(method: string, params: Array): Promise { - await this.senderFn({ - method: `bridges:getMessageBridge:${method}`, - params, - }); - } + private async callMessageBridge(method: string, params: Array): Promise { + await this.senderFn({ + method: `bridges:getMessageBridge:${method}`, + params, + }); + } - private async getAppUser(): Promise { - const response = await this.senderFn({ method: 'bridges:getUserBridge:doGetAppUser', params: [AppObjectRegistry.get('id')] }); - return response.result; - } + private async getAppUser(): Promise { + const response = await this.senderFn({ method: 'bridges:getUserBridge:doGetAppUser', params: [AppObjectRegistry.get('id')] }); + return response.result; + } } diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts index 04592eadd3db9..ffc77b6904bb7 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts @@ -5,118 +5,118 @@ import { AppAccessors } from '../mod.ts'; import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; describe('AppAccessors', () => { - let appAccessors: AppAccessors; - const senderFn = (r: object) => - Promise.resolve({ - id: Math.random().toString(36).substring(2), - jsonrpc: '2.0', - result: r, - serialize() { - return JSON.stringify(this); - }, - }); - - beforeEach(() => { - appAccessors = new AppAccessors(senderFn); - AppObjectRegistry.clear(); - }); - - afterAll(() => { - AppObjectRegistry.clear(); - }); - - it('creates the correct format for IRead calls', async () => { - const roomRead = appAccessors.getReader().getRoomReader(); - const room = await roomRead.getById('123'); - - assertEquals(room, { - params: ['123'], - method: 'accessor:getReader:getRoomReader:getById', - }); - }); - - it('creates the correct format for IEnvironmentRead calls from IRead', async () => { - const reader = appAccessors.getReader().getEnvironmentReader().getEnvironmentVariables(); - const room = await reader.getValueByName('NODE_ENV'); - - assertEquals(room, { - params: ['NODE_ENV'], - method: 'accessor:getReader:getEnvironmentReader:getEnvironmentVariables:getValueByName', - }); - }); - - it('creates the correct format for IEvironmentRead calls', async () => { - const envRead = appAccessors.getEnvironmentRead(); - const env = await envRead.getServerSettings().getValueById('123'); - - assertEquals(env, { - params: ['123'], - method: 'accessor:getEnvironmentRead:getServerSettings:getValueById', - }); - }); - - it('creates the correct format for IEvironmentWrite calls', async () => { - const envRead = appAccessors.getEnvironmentWrite(); - const env = await envRead.getServerSettings().incrementValue('123', 6); - - assertEquals(env, { - params: ['123', 6], - method: 'accessor:getEnvironmentWrite:getServerSettings:incrementValue', - }); - }); - - it('creates the correct format for IConfigurationModify calls', async () => { - const configModify = appAccessors.getConfigurationModify(); - const command = await configModify.slashCommands.modifySlashCommand({ - command: 'test', - i18nDescription: 'test', - i18nParamsExample: 'test', - providesPreview: true, - }); - - assertEquals(command, { - params: [ - { - command: 'test', - i18nDescription: 'test', - i18nParamsExample: 'test', - providesPreview: true, - }, - ], - method: 'accessor:getConfigurationModify:slashCommands:modifySlashCommand', - }); - }); - - it('correctly stores a reference to a slashcommand object and sends a request via proxy', async () => { - const configExtend = appAccessors.getConfigurationExtend(); - - const slashcommand = { - command: 'test', - i18nDescription: 'test', - i18nParamsExample: 'test', - providesPreview: true, - executor() { - return Promise.resolve(); - }, - }; - - const result = await configExtend.slashCommands.provideSlashCommand(slashcommand); - - assertEquals(AppObjectRegistry.get('slashcommand:test'), slashcommand); - - // The function will not be serialized and sent to the main process - delete result.params[0].executor; - - assertEquals(result, { - method: 'accessor:getConfigurationExtend:slashCommands:provideSlashCommand', - params: [ - { - command: 'test', - i18nDescription: 'test', - i18nParamsExample: 'test', - providesPreview: true, - }, - ], - }); - }); + let appAccessors: AppAccessors; + const senderFn = (r: object) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: r, + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + appAccessors = new AppAccessors(senderFn); + AppObjectRegistry.clear(); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('creates the correct format for IRead calls', async () => { + const roomRead = appAccessors.getReader().getRoomReader(); + const room = await roomRead.getById('123'); + + assertEquals(room, { + params: ['123'], + method: 'accessor:getReader:getRoomReader:getById', + }); + }); + + it('creates the correct format for IEnvironmentRead calls from IRead', async () => { + const reader = appAccessors.getReader().getEnvironmentReader().getEnvironmentVariables(); + const room = await reader.getValueByName('NODE_ENV'); + + assertEquals(room, { + params: ['NODE_ENV'], + method: 'accessor:getReader:getEnvironmentReader:getEnvironmentVariables:getValueByName', + }); + }); + + it('creates the correct format for IEvironmentRead calls', async () => { + const envRead = appAccessors.getEnvironmentRead(); + const env = await envRead.getServerSettings().getValueById('123'); + + assertEquals(env, { + params: ['123'], + method: 'accessor:getEnvironmentRead:getServerSettings:getValueById', + }); + }); + + it('creates the correct format for IEvironmentWrite calls', async () => { + const envRead = appAccessors.getEnvironmentWrite(); + const env = await envRead.getServerSettings().incrementValue('123', 6); + + assertEquals(env, { + params: ['123', 6], + method: 'accessor:getEnvironmentWrite:getServerSettings:incrementValue', + }); + }); + + it('creates the correct format for IConfigurationModify calls', async () => { + const configModify = appAccessors.getConfigurationModify(); + const command = await configModify.slashCommands.modifySlashCommand({ + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + }); + + assertEquals(command, { + params: [ + { + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + }, + ], + method: 'accessor:getConfigurationModify:slashCommands:modifySlashCommand', + }); + }); + + it('correctly stores a reference to a slashcommand object and sends a request via proxy', async () => { + const configExtend = appAccessors.getConfigurationExtend(); + + const slashcommand = { + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + executor() { + return Promise.resolve(); + }, + }; + + const result = await configExtend.slashCommands.provideSlashCommand(slashcommand); + + assertEquals(AppObjectRegistry.get('slashcommand:test'), slashcommand); + + // The function will not be serialized and sent to the main process + delete result.params[0].executor; + + assertEquals(result, { + method: 'accessor:getConfigurationExtend:slashCommands:provideSlashCommand', + params: [ + { + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + }, + ], + }); + }); }); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts index f3d83b32e4e9d..43bb7d413dcfe 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts @@ -7,253 +7,253 @@ import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; import { ModifyCreator } from '../modify/ModifyCreator.ts'; describe('ModifyCreator', () => { - const senderFn = (r: any) => - Promise.resolve({ - id: Math.random().toString(36).substring(2), - jsonrpc: '2.0', - result: r, - serialize() { - return JSON.stringify(this); - }, - }); - - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('id', 'deno-test'); - }); - - afterAll(() => { - AppObjectRegistry.clear(); - }); - - it('sends the correct payload in the request to create a message', async () => { - const spying = spy(senderFn); - const modifyCreator = new ModifyCreator(spying); - const messageBuilder = modifyCreator.startMessage(); - - // Importing types from the Apps-Engine is problematic, so we'll go with `any` here - messageBuilder - .setRoom({ id: '123' } as any) - .setSender({ id: '456' } as any) - .setText('Hello World') - .setUsernameAlias('alias') - .setAvatarUrl('https://avatars.com/123'); - - // We can't get a legitimate return value here, so we ignore it - // but we need to know that the request sent was well formed - await modifyCreator.finish(messageBuilder); - - assertSpyCall(spying, 0, { - args: [ - { - method: 'bridges:getMessageBridge:doCreate', - params: [ - { - room: { id: '123' }, - sender: { id: '456' }, - text: 'Hello World', - alias: 'alias', - avatarUrl: 'https://avatars.com/123', - }, - 'deno-test', - ], - }, - ], - }); - }); - - it('sends the correct payload in the request to upload a buffer', async () => { - const modifyCreator = new ModifyCreator(senderFn); - - const result = await modifyCreator.getUploadCreator().uploadBuffer(new Uint8Array([1, 2, 3, 4]), 'text/plain'); - - assertEquals(result, { - method: 'accessor:getModifier:getCreator:getUploadCreator:uploadBuffer', - params: [new Uint8Array([1, 2, 3, 4]), 'text/plain'], - }); - }); - - it('sends the correct payload in the request to create a visitor', async () => { - const modifyCreator = new ModifyCreator(senderFn); - - const result = (await modifyCreator.getLivechatCreator().createVisitor({ - token: 'random token', - username: 'random username for visitor', - name: 'Random Visitor', - })) as any; // We modified the send function so it changed the original return type of the function - - assertEquals(result, { - method: 'accessor:getModifier:getCreator:getLivechatCreator:createVisitor', - params: [ - { - token: 'random token', - username: 'random username for visitor', - name: 'Random Visitor', - }, - ], - }); - }); - - // This test is important because if we return a promise we break API compatibility - it('does not return a promise for calls of the createToken() method of the LivechatCreator', () => { - const modifyCreator = new ModifyCreator(senderFn); - - const result = modifyCreator.getLivechatCreator().createToken(); - - assertNotInstanceOf(result, Promise); - assert(typeof result === 'string', `Expected "${result}" to be of type "string", but got "${typeof result}"`); - }); - - it('throws an error when a proxy method of getLivechatCreator fails', async () => { - const failingSenderFn = () => Promise.reject(new Error('Test error')); - const modifyCreator = new ModifyCreator(failingSenderFn); - const livechatCreator = modifyCreator.getLivechatCreator(); - - await assertRejects( - () => - livechatCreator.createAndReturnVisitor({ - token: 'visitor-token', - username: 'visitor-username', - name: 'Visitor Name', - }), - Error, - 'Test error', - ); - }); - - it('throws an instance of Error when getLivechatCreator fails with a specific error object', async () => { - const failingSenderFn = () => Promise.reject({ error: { message: 'Livechat method error' } }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const livechatCreator = modifyCreator.getLivechatCreator(); - - await assertRejects( - () => - livechatCreator.createVisitor({ - token: 'visitor-token', - username: 'visitor-username', - name: 'Visitor Name', - }), - Error, - 'Livechat method error', - ); - }); - - it('throws a default Error when getLivechatCreator fails with an unknown error object', async () => { - const failingSenderFn = () => Promise.reject({ error: {} }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const livechatCreator = modifyCreator.getLivechatCreator(); - - await assertRejects( - () => - livechatCreator.createVisitor({ - token: 'visitor-token', - username: 'visitor-username', - name: 'Visitor Name', - }), - Error, - '[object Object]', - ); - }); - - it('throws an error when a proxy method of getUploadCreator fails', async () => { - const failingSenderFn = () => Promise.reject(new Error('Upload error')); - const modifyCreator = new ModifyCreator(failingSenderFn); - const uploadCreator = modifyCreator.getUploadCreator(); - - await assertRejects(() => uploadCreator.uploadBuffer(new Uint8Array([9, 10, 11, 12]), 'image/png'), Error, 'Upload error'); - }); - - it('throws an instance of Error when getUploadCreator fails with a specific error object', async () => { - const failingSenderFn = () => Promise.reject({ error: { message: 'Upload method error' } }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const uploadCreator = modifyCreator.getUploadCreator(); - - await assertRejects(() => uploadCreator.uploadBuffer(new Uint8Array([1, 2, 3]), 'image/png'), Error, 'Upload method error'); - }); - - it('throws a default Error when getUploadCreator fails with an unknown error object', async () => { - const failingSenderFn = () => Promise.reject({ error: {} }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const uploadCreator = modifyCreator.getUploadCreator(); - - await assertRejects(() => uploadCreator.uploadBuffer(new Uint8Array([1, 2, 3]), 'image/png'), Error, '[object Object]'); - }); - - it('throws an error when a proxy method of getEmailCreator fails', async () => { - const failingSenderFn = () => Promise.reject(new Error('Email error')); - const modifyCreator = new ModifyCreator(failingSenderFn); - const emailCreator = modifyCreator.getEmailCreator(); - - await assertRejects( - () => - emailCreator.send({ - to: 'test@example.com', - from: 'sender@example.com', - subject: 'Test Email', - text: 'This is a test email.', - }), - Error, - 'Email error', - ); - }); - - it('throws an instance of Error when getEmailCreator fails with a specific error object', async () => { - const failingSenderFn = () => Promise.reject({ error: { message: 'Email method error' } }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const emailCreator = modifyCreator.getEmailCreator(); - - await assertRejects( - () => - emailCreator.send({ - to: 'test@example.com', - from: 'sender@example.com', - subject: 'Test Email', - text: 'This is a test email.', - }), - Error, - 'Email method error', - ); - }); - - it('throws a default Error when getEmailCreator fails with an unknown error object', async () => { - const failingSenderFn = () => Promise.reject({ error: {} }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const emailCreator = modifyCreator.getEmailCreator(); - - await assertRejects( - () => - emailCreator.send({ - to: 'test@example.com', - from: 'sender@example.com', - subject: 'Test Email', - text: 'This is a test email.', - }), - Error, - '[object Object]', - ); - }); - - it('throws an error when a proxy method of getContactCreator fails', async () => { - const failingSenderFn = () => Promise.reject(new Error('Contact creation error')); - const modifyCreator = new ModifyCreator(failingSenderFn); - const contactCreator = modifyCreator.getContactCreator(); - - await assertRejects(() => contactCreator.addContactEmail('test-contact-id', 'test@example.com'), Error, 'Contact creation error'); - }); - - it('throws an instance of Error when getContactCreator fails with a specific error object', async () => { - const failingSenderFn = () => Promise.reject({ error: { message: 'Contact creation error' } }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const contactCreator = modifyCreator.getContactCreator(); - - await assertRejects(() => contactCreator.addContactEmail('test-contact-id', 'test@example.com'), Error, 'Contact creation error'); - }); - - it('throws a default Error when getContactCreator fails with an unknown error object', async () => { - const failingSenderFn = () => Promise.reject({ error: {} }); - const modifyCreator = new ModifyCreator(failingSenderFn); - const contactCreator = modifyCreator.getContactCreator(); - - await assertRejects(() => contactCreator.addContactEmail('test-contact-id', 'test@example.com'), Error, '[object Object]'); - }); + const senderFn = (r: any) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: r, + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('id', 'deno-test'); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('sends the correct payload in the request to create a message', async () => { + const spying = spy(senderFn); + const modifyCreator = new ModifyCreator(spying); + const messageBuilder = modifyCreator.startMessage(); + + // Importing types from the Apps-Engine is problematic, so we'll go with `any` here + messageBuilder + .setRoom({ id: '123' } as any) + .setSender({ id: '456' } as any) + .setText('Hello World') + .setUsernameAlias('alias') + .setAvatarUrl('https://avatars.com/123'); + + // We can't get a legitimate return value here, so we ignore it + // but we need to know that the request sent was well formed + await modifyCreator.finish(messageBuilder); + + assertSpyCall(spying, 0, { + args: [ + { + method: 'bridges:getMessageBridge:doCreate', + params: [ + { + room: { id: '123' }, + sender: { id: '456' }, + text: 'Hello World', + alias: 'alias', + avatarUrl: 'https://avatars.com/123', + }, + 'deno-test', + ], + }, + ], + }); + }); + + it('sends the correct payload in the request to upload a buffer', async () => { + const modifyCreator = new ModifyCreator(senderFn); + + const result = await modifyCreator.getUploadCreator().uploadBuffer(new Uint8Array([1, 2, 3, 4]), 'text/plain'); + + assertEquals(result, { + method: 'accessor:getModifier:getCreator:getUploadCreator:uploadBuffer', + params: [new Uint8Array([1, 2, 3, 4]), 'text/plain'], + }); + }); + + it('sends the correct payload in the request to create a visitor', async () => { + const modifyCreator = new ModifyCreator(senderFn); + + const result = (await modifyCreator.getLivechatCreator().createVisitor({ + token: 'random token', + username: 'random username for visitor', + name: 'Random Visitor', + })) as any; // We modified the send function so it changed the original return type of the function + + assertEquals(result, { + method: 'accessor:getModifier:getCreator:getLivechatCreator:createVisitor', + params: [ + { + token: 'random token', + username: 'random username for visitor', + name: 'Random Visitor', + }, + ], + }); + }); + + // This test is important because if we return a promise we break API compatibility + it('does not return a promise for calls of the createToken() method of the LivechatCreator', () => { + const modifyCreator = new ModifyCreator(senderFn); + + const result = modifyCreator.getLivechatCreator().createToken(); + + assertNotInstanceOf(result, Promise); + assert(typeof result === 'string', `Expected "${result}" to be of type "string", but got "${typeof result}"`); + }); + + it('throws an error when a proxy method of getLivechatCreator fails', async () => { + const failingSenderFn = () => Promise.reject(new Error('Test error')); + const modifyCreator = new ModifyCreator(failingSenderFn); + const livechatCreator = modifyCreator.getLivechatCreator(); + + await assertRejects( + () => + livechatCreator.createAndReturnVisitor({ + token: 'visitor-token', + username: 'visitor-username', + name: 'Visitor Name', + }), + Error, + 'Test error', + ); + }); + + it('throws an instance of Error when getLivechatCreator fails with a specific error object', async () => { + const failingSenderFn = () => Promise.reject({ error: { message: 'Livechat method error' } }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const livechatCreator = modifyCreator.getLivechatCreator(); + + await assertRejects( + () => + livechatCreator.createVisitor({ + token: 'visitor-token', + username: 'visitor-username', + name: 'Visitor Name', + }), + Error, + 'Livechat method error', + ); + }); + + it('throws a default Error when getLivechatCreator fails with an unknown error object', async () => { + const failingSenderFn = () => Promise.reject({ error: {} }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const livechatCreator = modifyCreator.getLivechatCreator(); + + await assertRejects( + () => + livechatCreator.createVisitor({ + token: 'visitor-token', + username: 'visitor-username', + name: 'Visitor Name', + }), + Error, + '[object Object]', + ); + }); + + it('throws an error when a proxy method of getUploadCreator fails', async () => { + const failingSenderFn = () => Promise.reject(new Error('Upload error')); + const modifyCreator = new ModifyCreator(failingSenderFn); + const uploadCreator = modifyCreator.getUploadCreator(); + + await assertRejects(() => uploadCreator.uploadBuffer(new Uint8Array([9, 10, 11, 12]), 'image/png'), Error, 'Upload error'); + }); + + it('throws an instance of Error when getUploadCreator fails with a specific error object', async () => { + const failingSenderFn = () => Promise.reject({ error: { message: 'Upload method error' } }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const uploadCreator = modifyCreator.getUploadCreator(); + + await assertRejects(() => uploadCreator.uploadBuffer(new Uint8Array([1, 2, 3]), 'image/png'), Error, 'Upload method error'); + }); + + it('throws a default Error when getUploadCreator fails with an unknown error object', async () => { + const failingSenderFn = () => Promise.reject({ error: {} }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const uploadCreator = modifyCreator.getUploadCreator(); + + await assertRejects(() => uploadCreator.uploadBuffer(new Uint8Array([1, 2, 3]), 'image/png'), Error, '[object Object]'); + }); + + it('throws an error when a proxy method of getEmailCreator fails', async () => { + const failingSenderFn = () => Promise.reject(new Error('Email error')); + const modifyCreator = new ModifyCreator(failingSenderFn); + const emailCreator = modifyCreator.getEmailCreator(); + + await assertRejects( + () => + emailCreator.send({ + to: 'test@example.com', + from: 'sender@example.com', + subject: 'Test Email', + text: 'This is a test email.', + }), + Error, + 'Email error', + ); + }); + + it('throws an instance of Error when getEmailCreator fails with a specific error object', async () => { + const failingSenderFn = () => Promise.reject({ error: { message: 'Email method error' } }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const emailCreator = modifyCreator.getEmailCreator(); + + await assertRejects( + () => + emailCreator.send({ + to: 'test@example.com', + from: 'sender@example.com', + subject: 'Test Email', + text: 'This is a test email.', + }), + Error, + 'Email method error', + ); + }); + + it('throws a default Error when getEmailCreator fails with an unknown error object', async () => { + const failingSenderFn = () => Promise.reject({ error: {} }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const emailCreator = modifyCreator.getEmailCreator(); + + await assertRejects( + () => + emailCreator.send({ + to: 'test@example.com', + from: 'sender@example.com', + subject: 'Test Email', + text: 'This is a test email.', + }), + Error, + '[object Object]', + ); + }); + + it('throws an error when a proxy method of getContactCreator fails', async () => { + const failingSenderFn = () => Promise.reject(new Error('Contact creation error')); + const modifyCreator = new ModifyCreator(failingSenderFn); + const contactCreator = modifyCreator.getContactCreator(); + + await assertRejects(() => contactCreator.addContactEmail('test-contact-id', 'test@example.com'), Error, 'Contact creation error'); + }); + + it('throws an instance of Error when getContactCreator fails with a specific error object', async () => { + const failingSenderFn = () => Promise.reject({ error: { message: 'Contact creation error' } }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const contactCreator = modifyCreator.getContactCreator(); + + await assertRejects(() => contactCreator.addContactEmail('test-contact-id', 'test@example.com'), Error, 'Contact creation error'); + }); + + it('throws a default Error when getContactCreator fails with an unknown error object', async () => { + const failingSenderFn = () => Promise.reject({ error: {} }); + const modifyCreator = new ModifyCreator(failingSenderFn); + const contactCreator = modifyCreator.getContactCreator(); + + await assertRejects(() => contactCreator.addContactEmail('test-contact-id', 'test@example.com'), Error, '[object Object]'); + }); }); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts index 1ec056e02ce30..66e14a1680b49 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts @@ -6,115 +6,115 @@ import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; import { ModifyExtender } from '../modify/ModifyExtender.ts'; describe('ModifyExtender', () => { - let extender: ModifyExtender; - - const senderFn = (r: any) => - Promise.resolve({ - id: Math.random().toString(36).substring(2), - jsonrpc: '2.0', - result: structuredClone(r), - serialize() { - return JSON.stringify(this); - }, - }); - - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('id', 'deno-test'); - extender = new ModifyExtender(senderFn); - }); - - afterAll(() => { - AppObjectRegistry.clear(); - }); - - it('correctly formats requests for the extend message requests', async () => { - const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); - - const messageExtender = await extender.extendMessage('message-id', { _id: 'user-id' } as any); - - assertSpyCall(_spy, 0, { - args: [ - { - method: 'bridges:getMessageBridge:doGetById', - params: ['message-id', 'deno-test'], - }, - ], - }); - - messageExtender.addCustomField('key', 'value'); - - await extender.finish(messageExtender); - - assertSpyCall(_spy, 1, { - args: [ - { - method: 'bridges:getMessageBridge:doUpdate', - params: [messageExtender.getMessage(), 'deno-test'], - }, - ], - }); - - _spy.restore(); - }); - - it('correctly formats requests for the extend room requests', async () => { - const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); - - const roomExtender = await extender.extendRoom('room-id', { _id: 'user-id' } as any); - - assertSpyCall(_spy, 0, { - args: [ - { - method: 'bridges:getRoomBridge:doGetById', - params: ['room-id', 'deno-test'], - }, - ], - }); - - roomExtender.addCustomField('key', 'value'); - - await extender.finish(roomExtender); - - assertSpyCall(_spy, 1, { - args: [ - { - method: 'bridges:getRoomBridge:doUpdate', - params: [roomExtender.getRoom(), [], 'deno-test'], - }, - ], - }); - - _spy.restore(); - }); - - it('correctly formats requests for the extend video conference requests', async () => { - const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); - - const videoConferenceExtender = await extender.extendVideoConference('video-conference-id'); - - assertSpyCall(_spy, 0, { - args: [ - { - method: 'bridges:getVideoConferenceBridge:doGetById', - params: ['video-conference-id', 'deno-test'], - }, - ], - }); - - videoConferenceExtender.setStatus(4); - - await extender.finish(videoConferenceExtender); - - assertSpyCall(_spy, 1, { - args: [ - { - method: 'bridges:getVideoConferenceBridge:doUpdate', - params: [videoConferenceExtender.getVideoConference(), 'deno-test'], - }, - ], - }); - - _spy.restore(); - }); + let extender: ModifyExtender; + + const senderFn = (r: any) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: structuredClone(r), + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('id', 'deno-test'); + extender = new ModifyExtender(senderFn); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('correctly formats requests for the extend message requests', async () => { + const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); + + const messageExtender = await extender.extendMessage('message-id', { _id: 'user-id' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getMessageBridge:doGetById', + params: ['message-id', 'deno-test'], + }, + ], + }); + + messageExtender.addCustomField('key', 'value'); + + await extender.finish(messageExtender); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getMessageBridge:doUpdate', + params: [messageExtender.getMessage(), 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); + + it('correctly formats requests for the extend room requests', async () => { + const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); + + const roomExtender = await extender.extendRoom('room-id', { _id: 'user-id' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getRoomBridge:doGetById', + params: ['room-id', 'deno-test'], + }, + ], + }); + + roomExtender.addCustomField('key', 'value'); + + await extender.finish(roomExtender); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getRoomBridge:doUpdate', + params: [roomExtender.getRoom(), [], 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); + + it('correctly formats requests for the extend video conference requests', async () => { + const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); + + const videoConferenceExtender = await extender.extendVideoConference('video-conference-id'); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getVideoConferenceBridge:doGetById', + params: ['video-conference-id', 'deno-test'], + }, + ], + }); + + videoConferenceExtender.setStatus(4); + + await extender.finish(videoConferenceExtender); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getVideoConferenceBridge:doUpdate', + params: [videoConferenceExtender.getVideoConference(), 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); }); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts index 1201179952172..a93656a84c8a7 100644 --- a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts @@ -5,125 +5,125 @@ import { assertEquals } from 'https://deno.land/std@0.203.0/assert/mod.ts'; import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; import { ModifyUpdater } from '../modify/ModifyUpdater.ts'; -import { RoomBuilder } from "../builders/RoomBuilder.ts"; +import { RoomBuilder } from '../builders/RoomBuilder.ts'; describe('ModifyUpdater', () => { - let modifyUpdater: ModifyUpdater; - - const senderFn = (r: any) => - Promise.resolve({ - id: Math.random().toString(36).substring(2), - jsonrpc: '2.0', - result: structuredClone(r), - serialize() { - return JSON.stringify(this); - }, - }); - - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('id', 'deno-test'); - modifyUpdater = new ModifyUpdater(senderFn); - }); - - afterAll(() => { - AppObjectRegistry.clear(); - }); - - it('correctly formats requests for the update message flow', async () => { - const _spy = spy(modifyUpdater, 'senderFn' as keyof ModifyUpdater); - - const messageBuilder = await modifyUpdater.message('123', { id: '456' } as any); - - assertSpyCall(_spy, 0, { - args: [ - { - method: 'bridges:getMessageBridge:doGetById', - params: ['123', 'deno-test'], - }, - ], - }); - - messageBuilder.setUpdateData( - { - id: '123', - room: { id: '123' }, - sender: { id: '456' }, - text: 'Hello World', - }, - { - id: '456', - }, - ); - - await modifyUpdater.finish(messageBuilder); - - assertSpyCall(_spy, 1, { - args: [ - { - method: 'bridges:getMessageBridge:doUpdate', - params: [{ id: '123', ...messageBuilder.getChanges() }, 'deno-test'], - }, - ], - }); - - _spy.restore(); - }); - - it('correctly formats requests for the update room flow', async () => { - const _spy = spy(modifyUpdater, 'senderFn' as keyof ModifyUpdater); - - const roomBuilder = await modifyUpdater.room('123', { id: '456' } as any) as RoomBuilder; - - assertSpyCall(_spy, 0, { - args: [ - { - method: 'bridges:getRoomBridge:doGetById', - params: ['123', 'deno-test'], - }, - ], - }); - - roomBuilder.setData({ - id: '123', - type: 'c', - displayName: 'Test Room', - slugifiedName: 'test-room', - creator: { id: '456' }, - }); - - roomBuilder.setMembersToBeAddedByUsernames(['username1', 'username2']); - - // We need to sneak in the id as the `modifyUpdater.room` call won't have legitimate data - roomBuilder.getRoom().id = '123'; - - await modifyUpdater.finish(roomBuilder); - - assertSpyCall(_spy, 1, { - args: [ - { - method: 'bridges:getRoomBridge:doUpdate', - params: [{ id: '123', ...roomBuilder.getChanges() }, roomBuilder.getMembersToBeAddedUsernames(), 'deno-test'], - }, - ], - }); - }); - - it('correctly formats requests to UserUpdater methods', async () => { - const result = await modifyUpdater.getUserUpdater().updateStatusText({ id: '123' } as any, 'Hello World') as any; - - assertEquals(result, { - method: 'accessor:getModifier:getUpdater:getUserUpdater:updateStatusText', - params: [{ id: '123' }, 'Hello World'], - }); - }); - - it('correctly formats requests to LivechatUpdater methods', async () => { - const result = await modifyUpdater.getLivechatUpdater().closeRoom({ id: '123' } as any, 'close it!') as any; - - assertEquals(result, { - method: 'accessor:getModifier:getUpdater:getLivechatUpdater:closeRoom', - params: [{ id: '123' }, 'close it!'], - }); - }); + let modifyUpdater: ModifyUpdater; + + const senderFn = (r: any) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: structuredClone(r), + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('id', 'deno-test'); + modifyUpdater = new ModifyUpdater(senderFn); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('correctly formats requests for the update message flow', async () => { + const _spy = spy(modifyUpdater, 'senderFn' as keyof ModifyUpdater); + + const messageBuilder = await modifyUpdater.message('123', { id: '456' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getMessageBridge:doGetById', + params: ['123', 'deno-test'], + }, + ], + }); + + messageBuilder.setUpdateData( + { + id: '123', + room: { id: '123' }, + sender: { id: '456' }, + text: 'Hello World', + }, + { + id: '456', + }, + ); + + await modifyUpdater.finish(messageBuilder); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getMessageBridge:doUpdate', + params: [{ id: '123', ...messageBuilder.getChanges() }, 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); + + it('correctly formats requests for the update room flow', async () => { + const _spy = spy(modifyUpdater, 'senderFn' as keyof ModifyUpdater); + + const roomBuilder = await modifyUpdater.room('123', { id: '456' } as any) as RoomBuilder; + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getRoomBridge:doGetById', + params: ['123', 'deno-test'], + }, + ], + }); + + roomBuilder.setData({ + id: '123', + type: 'c', + displayName: 'Test Room', + slugifiedName: 'test-room', + creator: { id: '456' }, + }); + + roomBuilder.setMembersToBeAddedByUsernames(['username1', 'username2']); + + // We need to sneak in the id as the `modifyUpdater.room` call won't have legitimate data + roomBuilder.getRoom().id = '123'; + + await modifyUpdater.finish(roomBuilder); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getRoomBridge:doUpdate', + params: [{ id: '123', ...roomBuilder.getChanges() }, roomBuilder.getMembersToBeAddedUsernames(), 'deno-test'], + }, + ], + }); + }); + + it('correctly formats requests to UserUpdater methods', async () => { + const result = await modifyUpdater.getUserUpdater().updateStatusText({ id: '123' } as any, 'Hello World') as any; + + assertEquals(result, { + method: 'accessor:getModifier:getUpdater:getUserUpdater:updateStatusText', + params: [{ id: '123' }, 'Hello World'], + }); + }); + + it('correctly formats requests to LivechatUpdater methods', async () => { + const result = await modifyUpdater.getLivechatUpdater().closeRoom({ id: '123' } as any, 'close it!') as any; + + assertEquals(result, { + method: 'accessor:getModifier:getUpdater:getLivechatUpdater:closeRoom', + params: [{ id: '123' }, 'close it!'], + }); + }); }); diff --git a/packages/apps-engine/deno-runtime/lib/ast/mod.ts b/packages/apps-engine/deno-runtime/lib/ast/mod.ts index 09f4994f2badf..d4f0f5858a281 100644 --- a/packages/apps-engine/deno-runtime/lib/ast/mod.ts +++ b/packages/apps-engine/deno-runtime/lib/ast/mod.ts @@ -1,64 +1,69 @@ -import { generate } from "astring"; +import { generate } from 'astring'; // @deno-types="../../acorn.d.ts" -import { Program, parse } from "acorn"; +import { parse, Program } from 'acorn'; // @deno-types="../../acorn-walk.d.ts" -import { fullAncestor } from "acorn-walk"; +import { fullAncestor } from 'acorn-walk'; -import * as operations from "./operations.ts"; -import type { WalkerState } from "./operations.ts"; +import * as operations from './operations.ts'; +import type { WalkerState } from './operations.ts'; function fixAst(ast: Program): boolean { - const pendingOperations = [ - operations.fixLivechatIsOnlineCalls, - operations.checkReassignmentOfModifiedIdentifiers, - operations.fixRoomUsernamesCalls, - ]; + const pendingOperations = [ + operations.fixLivechatIsOnlineCalls, + operations.checkReassignmentOfModifiedIdentifiers, + operations.fixRoomUsernamesCalls, + ]; - // Have we touched the tree? - let isModified = false; + // Have we touched the tree? + let isModified = false; - while (pendingOperations.length) { - const ops = pendingOperations.splice(0); - const state: WalkerState = { - isModified: false, - functionIdentifiers: new Set(), - }; + while (pendingOperations.length) { + const ops = pendingOperations.splice(0); + const state: WalkerState = { + isModified: false, + functionIdentifiers: new Set(), + }; - fullAncestor(ast, (node, state, ancestors, type) => { - ops.forEach(operation => operation(node, state, ancestors, type)); - }, undefined, state); + fullAncestor( + ast, + (node, state, ancestors, type) => { + ops.forEach((operation) => operation(node, state, ancestors, type)); + }, + undefined, + state, + ); - if (state.isModified) { - isModified = true; - } + if (state.isModified) { + isModified = true; + } - if (state.functionIdentifiers.size) { - pendingOperations.push( - operations.buildFixModifiedFunctionsOperation(state.functionIdentifiers), - operations.checkReassignmentOfModifiedIdentifiers - ); - } - } + if (state.functionIdentifiers.size) { + pendingOperations.push( + operations.buildFixModifiedFunctionsOperation(state.functionIdentifiers), + operations.checkReassignmentOfModifiedIdentifiers, + ); + } + } - return isModified; + return isModified; } export function fixBrokenSynchronousAPICalls(appSource: string): string { - const astRootNode = parse(appSource, { - ecmaVersion: 2017, - // Allow everything, we don't want to complain if code is badly written - // Also, since the code itself has been transpiled, the chance of getting - // shenanigans is lower - allowReserved: true, - allowReturnOutsideFunction: true, - allowImportExportEverywhere: true, - allowAwaitOutsideFunction: true, - allowSuperOutsideMethod: true, - }); + const astRootNode = parse(appSource, { + ecmaVersion: 2017, + // Allow everything, we don't want to complain if code is badly written + // Also, since the code itself has been transpiled, the chance of getting + // shenanigans is lower + allowReserved: true, + allowReturnOutsideFunction: true, + allowImportExportEverywhere: true, + allowAwaitOutsideFunction: true, + allowSuperOutsideMethod: true, + }); - if (fixAst(astRootNode)) { - return generate(astRootNode); - } + if (fixAst(astRootNode)) { + return generate(astRootNode); + } - return appSource; + return appSource; } diff --git a/packages/apps-engine/deno-runtime/lib/ast/operations.ts b/packages/apps-engine/deno-runtime/lib/ast/operations.ts index d3886348041f1..7a5a4993ad297 100644 --- a/packages/apps-engine/deno-runtime/lib/ast/operations.ts +++ b/packages/apps-engine/deno-runtime/lib/ast/operations.ts @@ -4,236 +4,234 @@ import { AnyNode, AssignmentExpression, AwaitExpression, Expression, Function, I import { FullAncestorWalkerCallback } from 'acorn-walk'; export type WalkerState = { - isModified: boolean; - functionIdentifiers: Set; + isModified: boolean; + functionIdentifiers: Set; }; export function getFunctionIdentifier(ancestors: AnyNode[], functionNodeIndex: number) { - const parent = ancestors[functionNodeIndex - 1]; - - // If there is a parent node and it's not a computed property, we can try to - // extract an identifier for our function from it. This needs to be done first - // because when functions are assigned to named symbols, this will be the only - // way to call it, even if the function itself has an identifier - // Consider the following block: - // - // const foo = function bar() {} - // - // Even though the function itself has a name, the only way to call it in the - // program is wiht `foo()` - if (parent && !(parent as Property | MethodDefinition).computed) { - // Several node types can have an id prop of type Identifier - const { id } = parent as unknown as { id?: Identifier }; - if (id?.type === 'Identifier') { - return id.name; - } - - // Usually assignments to object properties (MethodDefinition, Property) - const { key } = parent as MethodDefinition | Property; - if (key?.type === 'Identifier') { - return key.name; - } - - // Variable assignments have left hand side that can be used as Identifier - const { left } = parent as AssignmentExpression; - - // Simple assignment: `const fn = () => {}` - if (left?.type === 'Identifier') { - return left.name; - } - - // Object property assignment: `obj.fn = () => {}` - if (left?.type === 'MemberExpression' && !left.computed) { - return (left.property as Identifier).name; - } - } - - // nodeIndex needs to be the index of a Function node (either FunctionDeclaration or FunctionExpression) - const currentNode = ancestors[functionNodeIndex] as Function; - - // Function declarations or expressions can be directly named - if (currentNode.id?.type === 'Identifier') { - return currentNode.id.name; - } + const parent = ancestors[functionNodeIndex - 1]; + + // If there is a parent node and it's not a computed property, we can try to + // extract an identifier for our function from it. This needs to be done first + // because when functions are assigned to named symbols, this will be the only + // way to call it, even if the function itself has an identifier + // Consider the following block: + // + // const foo = function bar() {} + // + // Even though the function itself has a name, the only way to call it in the + // program is wiht `foo()` + if (parent && !(parent as Property | MethodDefinition).computed) { + // Several node types can have an id prop of type Identifier + const { id } = parent as unknown as { id?: Identifier }; + if (id?.type === 'Identifier') { + return id.name; + } + + // Usually assignments to object properties (MethodDefinition, Property) + const { key } = parent as MethodDefinition | Property; + if (key?.type === 'Identifier') { + return key.name; + } + + // Variable assignments have left hand side that can be used as Identifier + const { left } = parent as AssignmentExpression; + + // Simple assignment: `const fn = () => {}` + if (left?.type === 'Identifier') { + return left.name; + } + + // Object property assignment: `obj.fn = () => {}` + if (left?.type === 'MemberExpression' && !left.computed) { + return (left.property as Identifier).name; + } + } + + // nodeIndex needs to be the index of a Function node (either FunctionDeclaration or FunctionExpression) + const currentNode = ancestors[functionNodeIndex] as Function; + + // Function declarations or expressions can be directly named + if (currentNode.id?.type === 'Identifier') { + return currentNode.id.name; + } } export function wrapWithAwait(node: Expression) { - if (!node.type.endsWith('Expression')) { - throw new Error(`Can't wrap "${node.type}" with await`); - } + if (!node.type.endsWith('Expression')) { + throw new Error(`Can't wrap "${node.type}" with await`); + } - const innerNode: Expression = { ...node }; + const innerNode: Expression = { ...node }; - node.type = 'AwaitExpression'; - // starting here node has become an AwaitExpression - (node as AwaitExpression).argument = innerNode; + node.type = 'AwaitExpression'; + // starting here node has become an AwaitExpression + (node as AwaitExpression).argument = innerNode; - Object.keys(node).forEach((key) => !['type', 'argument'].includes(key) && delete node[key as keyof AnyNode]); + Object.keys(node).forEach((key) => !['type', 'argument'].includes(key) && delete node[key as keyof AnyNode]); } export function asyncifyScope(ancestors: AnyNode[], state: WalkerState) { - const functionNodeIndex = ancestors.findLastIndex((n) => 'async' in n); - if (functionNodeIndex === -1) return; + const functionNodeIndex = ancestors.findLastIndex((n) => 'async' in n); + if (functionNodeIndex === -1) return; - // At this point this is a node with an "async" property, so it has to be - // of type Function - let TS know about that - const functionScopeNode = ancestors[functionNodeIndex] as Function; + // At this point this is a node with an "async" property, so it has to be + // of type Function - let TS know about that + const functionScopeNode = ancestors[functionNodeIndex] as Function; - if (functionScopeNode.async) { - return; - } + if (functionScopeNode.async) { + return; + } - functionScopeNode.async = true; + functionScopeNode.async = true; - // If the parent of a function node is a call expression, we're talking about an IIFE - // Should we care about this case as well? - // const parentNode = ancestors[functionScopeIndex-1]; - // if (parentNode?.type === 'CallExpression' && ancestors[functionScopeIndex-2] && ancestors[functionScopeIndex-2].type !== 'AwaitExpression') { - // pendingOperations.push(buildFunctionPredicate(getFunctionIdentifier(ancestors, functionScopeIndex-2))); - // } + // If the parent of a function node is a call expression, we're talking about an IIFE + // Should we care about this case as well? + // const parentNode = ancestors[functionScopeIndex-1]; + // if (parentNode?.type === 'CallExpression' && ancestors[functionScopeIndex-2] && ancestors[functionScopeIndex-2].type !== 'AwaitExpression') { + // pendingOperations.push(buildFunctionPredicate(getFunctionIdentifier(ancestors, functionScopeIndex-2))); + // } - const identifier = getFunctionIdentifier(ancestors, functionNodeIndex); + const identifier = getFunctionIdentifier(ancestors, functionNodeIndex); - // We can't fix calls of functions which name we can't determine at compile time - if (!identifier) return; + // We can't fix calls of functions which name we can't determine at compile time + if (!identifier) return; - state.functionIdentifiers.add(identifier); + state.functionIdentifiers.add(identifier); } export function buildFixModifiedFunctionsOperation(functionIdentifiers: Set): FullAncestorWalkerCallback { - return function _fixModifiedFunctionsOperation(node, state, ancestors) { - if (node.type !== 'CallExpression') return; - - let isWrappable = false; - - // This node is a simple call to a function, like `fn()` - isWrappable = node.callee.type === 'Identifier' && functionIdentifiers.has(node.callee.name); - - // This node is a call to an object property or instance method, like `obj.fn()`, but not computed like `obj[fn]()` - isWrappable ||= - node.callee.type === 'MemberExpression' && - !node.callee.computed && - node.callee.property?.type === 'Identifier' && - functionIdentifiers.has(node.callee.property.name); - - // This is a weird dereferencing technique used by bundlers, and since we'll be dealing with bundled sources we have to check for it - // e.g. `r=(0,fn)(e)` - if (!isWrappable && node.callee.type === 'SequenceExpression') { - const [, secondExpression] = node.callee.expressions; - isWrappable = secondExpression?.type === 'Identifier' && functionIdentifiers.has(secondExpression.name); - isWrappable ||= - secondExpression?.type === 'MemberExpression' && - !secondExpression.computed && - secondExpression.property.type === 'Identifier' && - functionIdentifiers.has(secondExpression.property.name); - } - - if (!isWrappable) return; - - // ancestors[ancestors.length-1] === node, so here we're checking for parent node - const parentNode = ancestors[ancestors.length - 2]; - if (!parentNode || parentNode.type === 'AwaitExpression') return; - - wrapWithAwait(node); - asyncifyScope(ancestors, state); - - state.isModified = true; - }; + return function _fixModifiedFunctionsOperation(node, state, ancestors) { + if (node.type !== 'CallExpression') return; + + let isWrappable = false; + + // This node is a simple call to a function, like `fn()` + isWrappable = node.callee.type === 'Identifier' && functionIdentifiers.has(node.callee.name); + + // This node is a call to an object property or instance method, like `obj.fn()`, but not computed like `obj[fn]()` + isWrappable ||= node.callee.type === 'MemberExpression' && + !node.callee.computed && + node.callee.property?.type === 'Identifier' && + functionIdentifiers.has(node.callee.property.name); + + // This is a weird dereferencing technique used by bundlers, and since we'll be dealing with bundled sources we have to check for it + // e.g. `r=(0,fn)(e)` + if (!isWrappable && node.callee.type === 'SequenceExpression') { + const [, secondExpression] = node.callee.expressions; + isWrappable = secondExpression?.type === 'Identifier' && functionIdentifiers.has(secondExpression.name); + isWrappable ||= secondExpression?.type === 'MemberExpression' && + !secondExpression.computed && + secondExpression.property.type === 'Identifier' && + functionIdentifiers.has(secondExpression.property.name); + } + + if (!isWrappable) return; + + // ancestors[ancestors.length-1] === node, so here we're checking for parent node + const parentNode = ancestors[ancestors.length - 2]; + if (!parentNode || parentNode.type === 'AwaitExpression') return; + + wrapWithAwait(node); + asyncifyScope(ancestors, state); + + state.isModified = true; + }; } export const checkReassignmentOfModifiedIdentifiers: FullAncestorWalkerCallback = (node, { functionIdentifiers }, _ancestors) => { - if (node.type === 'AssignmentExpression') { - if (node.operator !== '=') return; + if (node.type === 'AssignmentExpression') { + if (node.operator !== '=') return; - let identifier = ''; + let identifier = ''; - if (node.left.type === 'Identifier') identifier = node.left.name; + if (node.left.type === 'Identifier') identifier = node.left.name; - if (node.left.type === 'MemberExpression' && !node.left.computed) { - identifier = (node.left.property as Identifier).name; - } + if (node.left.type === 'MemberExpression' && !node.left.computed) { + identifier = (node.left.property as Identifier).name; + } - if (!identifier || node.right.type !== 'Identifier' || !functionIdentifiers.has(node.right.name)) return; + if (!identifier || node.right.type !== 'Identifier' || !functionIdentifiers.has(node.right.name)) return; - functionIdentifiers.add(identifier); + functionIdentifiers.add(identifier); - return; - } + return; + } - if (node.type === 'VariableDeclarator') { - if (node.id.type !== 'Identifier' || functionIdentifiers.has(node.id.name)) return; + if (node.type === 'VariableDeclarator') { + if (node.id.type !== 'Identifier' || functionIdentifiers.has(node.id.name)) return; - if (node.init?.type !== 'Identifier' || !functionIdentifiers.has(node.init?.name)) return; + if (node.init?.type !== 'Identifier' || !functionIdentifiers.has(node.init?.name)) return; - functionIdentifiers.add(node.id.name); + functionIdentifiers.add(node.id.name); - return; - } + return; + } - // "Property" is for plain objects, "PropertyDefinition" is for classes - // but both share the same structure - if (node.type === 'Property' || node.type === 'PropertyDefinition') { - if (node.key.type !== 'Identifier' || functionIdentifiers.has(node.key.name)) return; + // "Property" is for plain objects, "PropertyDefinition" is for classes + // but both share the same structure + if (node.type === 'Property' || node.type === 'PropertyDefinition') { + if (node.key.type !== 'Identifier' || functionIdentifiers.has(node.key.name)) return; - if (node.value?.type !== 'Identifier' || !functionIdentifiers.has(node.value.name)) return; + if (node.value?.type !== 'Identifier' || !functionIdentifiers.has(node.value.name)) return; - functionIdentifiers.add(node.key.name); + functionIdentifiers.add(node.key.name); - return; - } + return; + } }; export const fixLivechatIsOnlineCalls: FullAncestorWalkerCallback = (node, state, ancestors) => { - if (node.type !== 'MemberExpression' || node.computed) return; + if (node.type !== 'MemberExpression' || node.computed) return; - if ((node.property as Identifier).name !== 'isOnline') return; + if ((node.property as Identifier).name !== 'isOnline') return; - if (node.object.type !== 'CallExpression') return; + if (node.object.type !== 'CallExpression') return; - if (node.object.callee.type !== 'MemberExpression') return; + if (node.object.callee.type !== 'MemberExpression') return; - if ((node.object.callee.property as Identifier).name !== 'getLivechatReader') return; + if ((node.object.callee.property as Identifier).name !== 'getLivechatReader') return; - let parentIndex = ancestors.length - 2; - let targetNode = ancestors[parentIndex]; + let parentIndex = ancestors.length - 2; + let targetNode = ancestors[parentIndex]; - if (targetNode.type !== 'CallExpression') { - targetNode = node; - } else { - parentIndex--; - } + if (targetNode.type !== 'CallExpression') { + targetNode = node; + } else { + parentIndex--; + } - // If we're already wrapped with an await, nothing to do - if (ancestors[parentIndex].type === 'AwaitExpression') return; + // If we're already wrapped with an await, nothing to do + if (ancestors[parentIndex].type === 'AwaitExpression') return; - // If we're in the middle of a chained member access, we can't wrap with await - if (ancestors[parentIndex].type === 'MemberExpression') return; + // If we're in the middle of a chained member access, we can't wrap with await + if (ancestors[parentIndex].type === 'MemberExpression') return; - wrapWithAwait(targetNode); - asyncifyScope(ancestors, state); + wrapWithAwait(targetNode); + asyncifyScope(ancestors, state); - state.isModified = true; + state.isModified = true; }; export const fixRoomUsernamesCalls: FullAncestorWalkerCallback = (node, state, ancestors) => { - if (node.type !== 'MemberExpression' || node.computed) return; + if (node.type !== 'MemberExpression' || node.computed) return; - if ((node.property as Identifier).name !== 'usernames') return; + if ((node.property as Identifier).name !== 'usernames') return; - let parentIndex = ancestors.length - 2; - let targetNode = ancestors[parentIndex]; + let parentIndex = ancestors.length - 2; + let targetNode = ancestors[parentIndex]; - if (targetNode.type !== 'CallExpression') { - targetNode = node; - } else { - parentIndex--; - } + if (targetNode.type !== 'CallExpression') { + targetNode = node; + } else { + parentIndex--; + } - // If we're already wrapped with an await, nothing to do - if (ancestors[parentIndex].type === 'AwaitExpression') return; + // If we're already wrapped with an await, nothing to do + if (ancestors[parentIndex].type === 'AwaitExpression') return; - wrapWithAwait(targetNode); - asyncifyScope(ancestors, state); + wrapWithAwait(targetNode); + asyncifyScope(ancestors, state); - state.isModified = true; -} + state.isModified = true; +}; diff --git a/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts b/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts index 330d2bf526208..8e750e6eaf587 100644 --- a/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts +++ b/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts @@ -7,318 +7,318 @@ import { AnyNode, ClassDeclaration, ExpressionStatement, FunctionDeclaration, Va */ type TestNodeExcerpt = { - code: string; - node: N; + code: string; + node: N; }; export const FunctionDeclarationFoo: TestNodeExcerpt = { - code: 'function foo() {}', - node: { - type: 'FunctionDeclaration', - id: { - type: 'Identifier', - name: 'foo', - }, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [], - }, - }, + code: 'function foo() {}', + node: { + type: 'FunctionDeclaration', + id: { + type: 'Identifier', + name: 'foo', + }, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, }; export const ConstFooAssignedFunctionExpression: TestNodeExcerpt = { - code: 'const foo = function() {}', - node: { - type: 'VariableDeclaration', - kind: 'const', - declarations: [ - { - type: 'VariableDeclarator', - id: { - type: 'Identifier', - name: 'foo', - }, - init: { - type: 'FunctionExpression', - id: null, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [], - }, - }, - }, - ], - }, + code: 'const foo = function() {}', + node: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'foo', + }, + init: { + type: 'FunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + }, + ], + }, }; export const AssignmentExpressionOfArrowFunctionToFooIdentifier: TestNodeExcerpt = { - code: 'foo = () => {}', - node: { - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: { - type: 'Identifier', - name: 'foo', - }, - right: { - type: 'ArrowFunctionExpression', - id: null, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [], - }, - }, - }, - }, + code: 'foo = () => {}', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'Identifier', + name: 'foo', + }, + right: { + type: 'ArrowFunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + }, + }, }; export const AssignmentExpressionOfNamedFunctionToFooMemberExpression: TestNodeExcerpt = { - code: 'obj.foo = function bar() {}', - node: { - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: 'a', - }, - property: { - type: 'Identifier', - name: 'foo', - }, - computed: false, - optional: false, - }, - right: { - type: 'FunctionExpression', - id: null, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [], - }, - }, - }, - }, + code: 'obj.foo = function bar() {}', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'a', + }, + property: { + type: 'Identifier', + name: 'foo', + }, + computed: false, + optional: false, + }, + right: { + type: 'FunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + }, + }, }; export const MethodDefinitionOfFooInClassBar: TestNodeExcerpt = { - code: 'class Bar { foo() {} }', - node: { - type: 'ClassDeclaration', - id: { - type: 'Identifier', - name: 'Bar', - }, - superClass: null, - body: { - type: 'ClassBody', - body: [ - { - type: 'MethodDefinition', - key: { - type: 'Identifier', - name: 'foo', - }, - value: { - type: 'FunctionExpression', - id: null, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [], - }, - }, - kind: 'method', - computed: false, - static: false, - }, - ], - }, - }, + code: 'class Bar { foo() {} }', + node: { + type: 'ClassDeclaration', + id: { + type: 'Identifier', + name: 'Bar', + }, + superClass: null, + body: { + type: 'ClassBody', + body: [ + { + type: 'MethodDefinition', + key: { + type: 'Identifier', + name: 'foo', + }, + value: { + type: 'FunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + kind: 'method', + computed: false, + static: false, + }, + ], + }, + }, }; export const SimpleCallExpressionOfFoo: TestNodeExcerpt = { - code: 'foo()', - node: { - type: 'ExpressionStatement', - expression: { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'foo', - }, - arguments: [], - optional: false, - }, - }, + code: 'foo()', + node: { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + }, + arguments: [], + optional: false, + }, + }, }; export const SyncFunctionDeclarationWithAsyncCallExpression: TestNodeExcerpt = { - // NOTE: this is invalid syntax, it won't be parsed by acorn - // but it can be an intermediary state of the AST after we run - // `wrapWithAwait` on "bar" call expressions, for instance - code: 'function foo() { return () => await bar() }', - node: { - type: 'FunctionDeclaration', - id: { - type: 'Identifier', - name: 'foo', - }, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [ - { - type: 'ReturnStatement', - argument: { - type: 'ArrowFunctionExpression', - id: null, - expression: true, - generator: false, - async: false, - params: [], - body: { - type: 'AwaitExpression', - argument: { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'bar', - }, - arguments: [], - optional: false, - }, - }, - }, - }, - ], - }, - }, + // NOTE: this is invalid syntax, it won't be parsed by acorn + // but it can be an intermediary state of the AST after we run + // `wrapWithAwait` on "bar" call expressions, for instance + code: 'function foo() { return () => await bar() }', + node: { + type: 'FunctionDeclaration', + id: { + type: 'Identifier', + name: 'foo', + }, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ReturnStatement', + argument: { + type: 'ArrowFunctionExpression', + id: null, + expression: true, + generator: false, + async: false, + params: [], + body: { + type: 'AwaitExpression', + argument: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'bar', + }, + arguments: [], + optional: false, + }, + }, + }, + }, + ], + }, + }, }; export const AssignmentOfFooToBar: TestNodeExcerpt = { - code: 'bar = foo', - node: { - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: { - type: 'Identifier', - name: 'bar', - }, - right: { - type: 'Identifier', - name: 'foo', - }, - }, - }, + code: 'bar = foo', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'Identifier', + name: 'bar', + }, + right: { + type: 'Identifier', + name: 'foo', + }, + }, + }, }; export const AssignmentOfFooToBarMemberExpression: TestNodeExcerpt = { - code: 'obj.bar = foo', - node: { - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - operator: '=', - left: { - type: 'MemberExpression', - computed: false, - optional: false, - object: { - type: 'Identifier', - name: 'obj', - }, - property: { - type: 'Identifier', - name: 'bar', - }, - }, - right: { - type: 'Identifier', - name: 'foo', - }, - }, - }, + code: 'obj.bar = foo', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'MemberExpression', + computed: false, + optional: false, + object: { + type: 'Identifier', + name: 'obj', + }, + property: { + type: 'Identifier', + name: 'bar', + }, + }, + right: { + type: 'Identifier', + name: 'foo', + }, + }, + }, }; export const AssignmentOfFooToBarVariableDeclarator: TestNodeExcerpt = { - code: 'const bar = foo', - node: { - type: 'VariableDeclaration', - kind: 'const', - declarations: [ - { - type: 'VariableDeclarator', - id: { - type: 'Identifier', - name: 'bar', - }, - init: { - type: 'Identifier', - name: 'foo', - }, - }, - ], - }, + code: 'const bar = foo', + node: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'bar', + }, + init: { + type: 'Identifier', + name: 'foo', + }, + }, + ], + }, }; export const AssignmentOfFooToBarPropertyDefinition: TestNodeExcerpt = { - code: 'class baz { bar = foo }', - node: { - type: 'ClassDeclaration', - id: { - type: 'Identifier', - name: 'baz', - }, - superClass: null, - body: { - type: 'ClassBody', - body: [ - { - type: 'PropertyDefinition', - static: false, - computed: false, - key: { - type: 'Identifier', - name: 'bar', - }, - value: { - type: 'Identifier', - name: 'foo', - }, - }, - ], - }, - }, + code: 'class baz { bar = foo }', + node: { + type: 'ClassDeclaration', + id: { + type: 'Identifier', + name: 'baz', + }, + superClass: null, + body: { + type: 'ClassBody', + body: [ + { + type: 'PropertyDefinition', + static: false, + computed: false, + key: { + type: 'Identifier', + name: 'bar', + }, + value: { + type: 'Identifier', + name: 'foo', + }, + }, + ], + }, + }, }; const fixSimpleCallExpressionCode = ` @@ -329,108 +329,108 @@ function bar() { }`; export const FixSimpleCallExpression: TestNodeExcerpt = { - code: fixSimpleCallExpressionCode, - node: { - type: 'FunctionDeclaration', - id: { - type: 'Identifier', - name: 'bar', - }, - expression: false, - generator: false, - async: false, - params: [], - body: { - type: 'BlockStatement', - body: [ - { - type: 'VariableDeclaration', - kind: 'const', - declarations: [ - { - type: 'VariableDeclarator', - id: { - type: 'Identifier', - name: 'a', - }, - init: { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'foo', - }, - arguments: [], - optional: false, - }, - }, - ], - }, - { - type: 'ReturnStatement', - argument: { - type: 'Identifier', - name: 'a', - }, - }, - ], - }, - }, + code: fixSimpleCallExpressionCode, + node: { + type: 'FunctionDeclaration', + id: { + type: 'Identifier', + name: 'bar', + }, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + }, + init: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + }, + arguments: [], + optional: false, + }, + }, + ], + }, + { + type: 'ReturnStatement', + argument: { + type: 'Identifier', + name: 'a', + }, + }, + ], + }, + }, }; export const ArrowFunctionDerefCallExpression: TestNodeExcerpt = { - // NOTE: this call strategy is widely used by bundlers; it's used to sever the `this` - // reference in the method from the object that contains it. This is mostly because - // the bundler wants to ensure that it does not messes up the bindings in the code it - // generates. - // - // This would be similar to doing `foo.call(undefined)` - code: 'const bar = () => (0, e.foo)();', - node: { - type: 'VariableDeclaration', - kind: 'const', - declarations: [ - { - type: 'VariableDeclarator', - id: { - type: 'Identifier', - name: 'bar', - }, - init: { - type: 'ArrowFunctionExpression', - id: null, - expression: true, - generator: false, - async: false, - params: [], - body: { - type: 'CallExpression', - optional: false, - arguments: [], - callee: { - type: 'SequenceExpression', - expressions: [ - { - type: 'Literal', - value: 0, - }, - { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: 'e', - }, - property: { - type: 'Identifier', - name: 'foo', - }, - computed: false, - optional: false, - }, - ], - }, - }, - }, - }, - ], - }, + // NOTE: this call strategy is widely used by bundlers; it's used to sever the `this` + // reference in the method from the object that contains it. This is mostly because + // the bundler wants to ensure that it does not messes up the bindings in the code it + // generates. + // + // This would be similar to doing `foo.call(undefined)` + code: 'const bar = () => (0, e.foo)();', + node: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'bar', + }, + init: { + type: 'ArrowFunctionExpression', + id: null, + expression: true, + generator: false, + async: false, + params: [], + body: { + type: 'CallExpression', + optional: false, + arguments: [], + callee: { + type: 'SequenceExpression', + expressions: [ + { + type: 'Literal', + value: 0, + }, + { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'e', + }, + property: { + type: 'Identifier', + name: 'foo', + }, + computed: false, + optional: false, + }, + ], + }, + }, + }, + }, + ], + }, }; diff --git a/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts b/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts index 2b00c271f7300..809de475013c9 100644 --- a/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts +++ b/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts @@ -1,245 +1,261 @@ import { assertEquals, assertThrows } from 'https://deno.land/std@0.203.0/assert/mod.ts'; import { beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; -import { WalkerState, asyncifyScope, buildFixModifiedFunctionsOperation, checkReassignmentOfModifiedIdentifiers, getFunctionIdentifier, wrapWithAwait } from '../operations.ts'; import { - ArrowFunctionDerefCallExpression, - AssignmentExpressionOfArrowFunctionToFooIdentifier, - AssignmentExpressionOfNamedFunctionToFooMemberExpression, - AssignmentOfFooToBar, - AssignmentOfFooToBarMemberExpression, - AssignmentOfFooToBarPropertyDefinition, - AssignmentOfFooToBarVariableDeclarator, - ConstFooAssignedFunctionExpression, - FixSimpleCallExpression, - FunctionDeclarationFoo, - MethodDefinitionOfFooInClassBar, - SimpleCallExpressionOfFoo, - SyncFunctionDeclarationWithAsyncCallExpression, + asyncifyScope, + buildFixModifiedFunctionsOperation, + checkReassignmentOfModifiedIdentifiers, + getFunctionIdentifier, + WalkerState, + wrapWithAwait, +} from '../operations.ts'; +import { + ArrowFunctionDerefCallExpression, + AssignmentExpressionOfArrowFunctionToFooIdentifier, + AssignmentExpressionOfNamedFunctionToFooMemberExpression, + AssignmentOfFooToBar, + AssignmentOfFooToBarMemberExpression, + AssignmentOfFooToBarPropertyDefinition, + AssignmentOfFooToBarVariableDeclarator, + ConstFooAssignedFunctionExpression, + FixSimpleCallExpression, + FunctionDeclarationFoo, + MethodDefinitionOfFooInClassBar, + SimpleCallExpressionOfFoo, + SyncFunctionDeclarationWithAsyncCallExpression, } from './data/ast_blocks.ts'; -import { AnyNode, ArrowFunctionExpression, AssignmentExpression, AwaitExpression, Expression, MethodDefinition, ReturnStatement, VariableDeclaration } from '../../../acorn.d.ts'; +import { + AnyNode, + ArrowFunctionExpression, + AssignmentExpression, + AwaitExpression, + Expression, + MethodDefinition, + ReturnStatement, + VariableDeclaration, +} from '../../../acorn.d.ts'; import { assertNotEquals } from 'https://deno.land/std@0.203.0/assert/assert_not_equals.ts'; describe('getFunctionIdentifier', () => { - it(`identifies the name "foo" for the code \`${FunctionDeclarationFoo.code}\``, () => { - // ancestors array is built by the walking lib - const nodeAncestors = [FunctionDeclarationFoo.node]; - const functionNodeIndex = 0; - assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); - }); - - it(`identifies the name "foo" for the code \`${ConstFooAssignedFunctionExpression.code}\``, () => { - // ancestors array is built by the walking lib - const nodeAncestors = [ - ConstFooAssignedFunctionExpression.node, // VariableDeclaration - ConstFooAssignedFunctionExpression.node.declarations[0], // VariableDeclarator - ConstFooAssignedFunctionExpression.node.declarations[0].init! // FunctionExpression - ]; - const functionNodeIndex = 2; - assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); - }); - - it(`identifies the name "foo" for the code \`${AssignmentExpressionOfArrowFunctionToFooIdentifier.code}\``, () => { - // ancestors array is built by the walking lib - const nodeAncestors = [ - AssignmentExpressionOfArrowFunctionToFooIdentifier.node, // ExpressionStatement - AssignmentExpressionOfArrowFunctionToFooIdentifier.node.expression, // AssignmentExpression - (AssignmentExpressionOfArrowFunctionToFooIdentifier.node.expression as AssignmentExpression).right, // ArrowFunctionExpression - ]; - const functionNodeIndex = 2; - assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); - }); - - it(`identifies the name "foo" for the code \`${AssignmentExpressionOfNamedFunctionToFooMemberExpression.code}\``, () => { - // ancestors array is built by the walking lib - const nodeAncestors = [ - AssignmentExpressionOfNamedFunctionToFooMemberExpression.node, // ExpressionStatement - AssignmentExpressionOfNamedFunctionToFooMemberExpression.node.expression, // AssignmentExpression - (AssignmentExpressionOfNamedFunctionToFooMemberExpression.node.expression as AssignmentExpression).right, // FunctionExpression - ]; - const functionNodeIndex = 2; - assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); - }); - - it(`identifies the name "foo" for the code \`${MethodDefinitionOfFooInClassBar.code}\``, () => { - // ancestors array is built by the walking lib - const nodeAncestors = [ - MethodDefinitionOfFooInClassBar.node, // ClassDeclaration - MethodDefinitionOfFooInClassBar.node.body, // ClassBody - MethodDefinitionOfFooInClassBar.node.body!.body[0], // MethodDefinition - (MethodDefinitionOfFooInClassBar.node.body!.body[0] as MethodDefinition).value, // FunctionExpression - ]; - const functionNodeIndex = 3; - assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); - }); + it(`identifies the name "foo" for the code \`${FunctionDeclarationFoo.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [FunctionDeclarationFoo.node]; + const functionNodeIndex = 0; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${ConstFooAssignedFunctionExpression.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + ConstFooAssignedFunctionExpression.node, // VariableDeclaration + ConstFooAssignedFunctionExpression.node.declarations[0], // VariableDeclarator + ConstFooAssignedFunctionExpression.node.declarations[0].init!, // FunctionExpression + ]; + const functionNodeIndex = 2; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${AssignmentExpressionOfArrowFunctionToFooIdentifier.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + AssignmentExpressionOfArrowFunctionToFooIdentifier.node, // ExpressionStatement + AssignmentExpressionOfArrowFunctionToFooIdentifier.node.expression, // AssignmentExpression + (AssignmentExpressionOfArrowFunctionToFooIdentifier.node.expression as AssignmentExpression).right, // ArrowFunctionExpression + ]; + const functionNodeIndex = 2; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${AssignmentExpressionOfNamedFunctionToFooMemberExpression.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + AssignmentExpressionOfNamedFunctionToFooMemberExpression.node, // ExpressionStatement + AssignmentExpressionOfNamedFunctionToFooMemberExpression.node.expression, // AssignmentExpression + (AssignmentExpressionOfNamedFunctionToFooMemberExpression.node.expression as AssignmentExpression).right, // FunctionExpression + ]; + const functionNodeIndex = 2; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${MethodDefinitionOfFooInClassBar.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + MethodDefinitionOfFooInClassBar.node, // ClassDeclaration + MethodDefinitionOfFooInClassBar.node.body, // ClassBody + MethodDefinitionOfFooInClassBar.node.body!.body[0], // MethodDefinition + (MethodDefinitionOfFooInClassBar.node.body!.body[0] as MethodDefinition).value, // FunctionExpression + ]; + const functionNodeIndex = 3; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); }); describe('wrapWithAwait', () => { - it('wraps a call expression with await', () => { - const node = structuredClone(SimpleCallExpressionOfFoo.node.expression); - wrapWithAwait(node); - - assertEquals('AwaitExpression', node.type); - assertNotEquals(SimpleCallExpressionOfFoo.node.expression.type, node.type); - assertEquals(SimpleCallExpressionOfFoo.node.expression, (node as AwaitExpression).argument); - }); - - it('throws if node is not an expression', () => { - const node = structuredClone(SimpleCallExpressionOfFoo.node); - assertThrows(() => wrapWithAwait(node as unknown as Expression)); - }) + it('wraps a call expression with await', () => { + const node = structuredClone(SimpleCallExpressionOfFoo.node.expression); + wrapWithAwait(node); + + assertEquals('AwaitExpression', node.type); + assertNotEquals(SimpleCallExpressionOfFoo.node.expression.type, node.type); + assertEquals(SimpleCallExpressionOfFoo.node.expression, (node as AwaitExpression).argument); + }); + + it('throws if node is not an expression', () => { + const node = structuredClone(SimpleCallExpressionOfFoo.node); + assertThrows(() => wrapWithAwait(node as unknown as Expression)); + }); }); describe('asyncifyScope', () => { - it('makes only the first function scope async', () => { - const node = structuredClone(SyncFunctionDeclarationWithAsyncCallExpression.node); - const ancestors: AnyNode[] = [ - node, // FunctionDeclaration - node.body, // BlockStatement - node.body!.body[0], // ReturnStatement - (node.body!.body[0] as ReturnStatement).argument!, // ArrowFunctionExpression - ((node.body!.body[0] as ReturnStatement).argument! as ArrowFunctionExpression).body, // AwaitExpression - (((node.body!.body[0] as ReturnStatement).argument! as ArrowFunctionExpression).body as AwaitExpression).argument, // CallExpression - ]; - const state: WalkerState = { - isModified: false, - functionIdentifiers: new Set(), - } - - asyncifyScope(ancestors, state); - - // Assert the function did indeed change the expression to async - assertEquals(((node.body.body[0] as ReturnStatement).argument as ArrowFunctionExpression).async, true) - - // Assert the function did NOT change all ancestors in the chain - assertEquals(node.async, false); - - // Assert it couldn't find a function identifier - assertEquals(state.functionIdentifiers.size, 0); - }); + it('makes only the first function scope async', () => { + const node = structuredClone(SyncFunctionDeclarationWithAsyncCallExpression.node); + const ancestors: AnyNode[] = [ + node, // FunctionDeclaration + node.body, // BlockStatement + node.body!.body[0], // ReturnStatement + (node.body!.body[0] as ReturnStatement).argument!, // ArrowFunctionExpression + ((node.body!.body[0] as ReturnStatement).argument! as ArrowFunctionExpression).body, // AwaitExpression + (((node.body!.body[0] as ReturnStatement).argument! as ArrowFunctionExpression).body as AwaitExpression).argument, // CallExpression + ]; + const state: WalkerState = { + isModified: false, + functionIdentifiers: new Set(), + }; + + asyncifyScope(ancestors, state); + + // Assert the function did indeed change the expression to async + assertEquals(((node.body.body[0] as ReturnStatement).argument as ArrowFunctionExpression).async, true); + + // Assert the function did NOT change all ancestors in the chain + assertEquals(node.async, false); + + // Assert it couldn't find a function identifier + assertEquals(state.functionIdentifiers.size, 0); + }); }); describe('checkReassignmentofModifiedIdentifiers', () => { - it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBar.code}"`, () => { - const node = structuredClone(AssignmentOfFooToBar.node); - const ancestors: AnyNode[] = [ - node, // ExpressionStatement - node.expression, // AssignmentExpression - (node.expression as AssignmentExpression).right, // Identifier - ]; - const state: WalkerState = { - isModified: true, - functionIdentifiers: new Set(['foo']), - } - - checkReassignmentOfModifiedIdentifiers(node.expression, state, ancestors, ''); - - assertEquals(state.functionIdentifiers.has('bar'), true); - }); - - it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarMemberExpression.code}"`, () => { - const node = structuredClone(AssignmentOfFooToBarMemberExpression.node); - const ancestors: AnyNode[] = [ - node, // ExpressionStatement - node.expression, // AssignmentExpression - (node.expression as AssignmentExpression).right, // Identifier - ]; - const state: WalkerState = { - isModified: true, - functionIdentifiers: new Set(['foo']), - } - - checkReassignmentOfModifiedIdentifiers(node.expression, state, ancestors, ''); - - assertEquals(state.functionIdentifiers.has('bar'), true); - }); - - it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarVariableDeclarator.code}"`, () => { - const node = structuredClone(AssignmentOfFooToBarVariableDeclarator.node); - const ancestors: AnyNode[] = [ - node, // VariableDeclaration - node.declarations[0], // VariableDeclarator - ]; - const state: WalkerState = { - isModified: true, - functionIdentifiers: new Set(['foo']), - } - - checkReassignmentOfModifiedIdentifiers(node.declarations[0], state, ancestors, ''); - - assertEquals(state.functionIdentifiers.has('bar'), true); - }); - - it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarPropertyDefinition.code}"`, () => { - const node = structuredClone(AssignmentOfFooToBarPropertyDefinition.node); - const ancestors: AnyNode[] = [ - node, // ClassDeclaration - node.body, // ClassBody - node.body.body[0], // PropertyDefinition - ]; - const state: WalkerState = { - isModified: true, - functionIdentifiers: new Set(['foo']), - } - - checkReassignmentOfModifiedIdentifiers(node.body.body[0], state, ancestors, ''); - - assertEquals(state.functionIdentifiers.has('bar'), true); - }); + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBar.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBar.node); + const ancestors: AnyNode[] = [ + node, // ExpressionStatement + node.expression, // AssignmentExpression + (node.expression as AssignmentExpression).right, // Identifier + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + }; + + checkReassignmentOfModifiedIdentifiers(node.expression, state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); + + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarMemberExpression.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBarMemberExpression.node); + const ancestors: AnyNode[] = [ + node, // ExpressionStatement + node.expression, // AssignmentExpression + (node.expression as AssignmentExpression).right, // Identifier + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + }; + + checkReassignmentOfModifiedIdentifiers(node.expression, state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); + + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarVariableDeclarator.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBarVariableDeclarator.node); + const ancestors: AnyNode[] = [ + node, // VariableDeclaration + node.declarations[0], // VariableDeclarator + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + }; + + checkReassignmentOfModifiedIdentifiers(node.declarations[0], state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); + + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarPropertyDefinition.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBarPropertyDefinition.node); + const ancestors: AnyNode[] = [ + node, // ClassDeclaration + node.body, // ClassBody + node.body.body[0], // PropertyDefinition + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + }; + + checkReassignmentOfModifiedIdentifiers(node.body.body[0], state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); }); -describe('buildFixModifiedFunctionsOperation', function() { - const state: WalkerState = { - isModified: false, - functionIdentifiers: new Set(['foo']), - }; - - const fixFunction = buildFixModifiedFunctionsOperation(state.functionIdentifiers); - - beforeEach(() => { - state.isModified = false; - state.functionIdentifiers = new Set(['foo']); - }); - - it(`fixes calls of "foo" in the code "${FixSimpleCallExpression.code}"`, () => { - const node = structuredClone(FixSimpleCallExpression.node); - const ancestors: AnyNode[] = [ - node, // FunctionDeclaration - node.body, // BlockStatement - node.body.body[0], // VariableDeclaration - (node.body.body[0] as VariableDeclaration).declarations[0], // VariableDeclarator - (node.body.body[0] as VariableDeclaration).declarations[0].init!, // CallExpression - ]; - - fixFunction(ancestors[4], state, ancestors, ''); - - assertEquals(state.isModified, true); - assertEquals(state.functionIdentifiers.has('bar'), true); - assertNotEquals(FixSimpleCallExpression.node, node); - assertEquals(node.async, true); - assertEquals(ancestors[4].type, 'AwaitExpression'); - }); - - it(`fixes calls of "foo" in the code "${ArrowFunctionDerefCallExpression.code}"`, () => { - const node = structuredClone(ArrowFunctionDerefCallExpression.node); - const ancestors: AnyNode[] = [ - node, // VariableDeclaration - node.declarations[0], // VariableDeclarator - node.declarations[0].init!, // ArrowFunctionExpression - (node.declarations[0].init as ArrowFunctionExpression).body, // CallExpression - ]; - - fixFunction(ancestors[3], state, ancestors, ''); - - // Recorded that a modification has been made - assertEquals(state.isModified, true); - // Recorded that the enclosing scope of the call also requires fixing - assertEquals(state.functionIdentifiers.has('bar'), true); - // Original node and fixed node are different - assertNotEquals(ArrowFunctionDerefCallExpression.node, node); - // The function call is now await'ed - assertEquals(ancestors[3].type, 'AwaitExpression'); - // The parent function of the call is now marked as async - assertEquals((ancestors[2] as ArrowFunctionExpression).async, true); - }); -}) +describe('buildFixModifiedFunctionsOperation', function () { + const state: WalkerState = { + isModified: false, + functionIdentifiers: new Set(['foo']), + }; + + const fixFunction = buildFixModifiedFunctionsOperation(state.functionIdentifiers); + + beforeEach(() => { + state.isModified = false; + state.functionIdentifiers = new Set(['foo']); + }); + + it(`fixes calls of "foo" in the code "${FixSimpleCallExpression.code}"`, () => { + const node = structuredClone(FixSimpleCallExpression.node); + const ancestors: AnyNode[] = [ + node, // FunctionDeclaration + node.body, // BlockStatement + node.body.body[0], // VariableDeclaration + (node.body.body[0] as VariableDeclaration).declarations[0], // VariableDeclarator + (node.body.body[0] as VariableDeclaration).declarations[0].init!, // CallExpression + ]; + + fixFunction(ancestors[4], state, ancestors, ''); + + assertEquals(state.isModified, true); + assertEquals(state.functionIdentifiers.has('bar'), true); + assertNotEquals(FixSimpleCallExpression.node, node); + assertEquals(node.async, true); + assertEquals(ancestors[4].type, 'AwaitExpression'); + }); + + it(`fixes calls of "foo" in the code "${ArrowFunctionDerefCallExpression.code}"`, () => { + const node = structuredClone(ArrowFunctionDerefCallExpression.node); + const ancestors: AnyNode[] = [ + node, // VariableDeclaration + node.declarations[0], // VariableDeclarator + node.declarations[0].init!, // ArrowFunctionExpression + (node.declarations[0].init as ArrowFunctionExpression).body, // CallExpression + ]; + + fixFunction(ancestors[3], state, ancestors, ''); + + // Recorded that a modification has been made + assertEquals(state.isModified, true); + // Recorded that the enclosing scope of the call also requires fixing + assertEquals(state.functionIdentifiers.has('bar'), true); + // Original node and fixed node are different + assertNotEquals(ArrowFunctionDerefCallExpression.node, node); + // The function call is now await'ed + assertEquals(ancestors[3].type, 'AwaitExpression'); + // The parent function of the call is now marked as async + assertEquals((ancestors[2] as ArrowFunctionExpression).async, true); + }); +}); diff --git a/packages/apps-engine/deno-runtime/lib/codec.ts b/packages/apps-engine/deno-runtime/lib/codec.ts index 288db46169dcc..95bbfa1a2aa26 100644 --- a/packages/apps-engine/deno-runtime/lib/codec.ts +++ b/packages/apps-engine/deno-runtime/lib/codec.ts @@ -2,41 +2,41 @@ import { Buffer } from 'node:buffer'; import { Decoder, Encoder, ExtensionCodec } from '@msgpack/msgpack'; import type { App as _App } from '@rocket.chat/apps-engine/definition/App.ts'; -import { require } from "./require.ts"; +import { require } from './require.ts'; const { App } = require('@rocket.chat/apps-engine/definition/App.js') as { - App: typeof _App; + App: typeof _App; }; const extensionCodec = new ExtensionCodec(); extensionCodec.register({ - type: 0, - encode: (object: unknown) => { - // We don't care about functions, but also don't want to throw an error - if (typeof object === 'function' || object instanceof App) { - return new Uint8Array(0); - } - - return null; - }, - decode: (_data: Uint8Array) => undefined, + type: 0, + encode: (object: unknown) => { + // We don't care about functions, but also don't want to throw an error + if (typeof object === 'function' || object instanceof App) { + return new Uint8Array(0); + } + + return null; + }, + decode: (_data: Uint8Array) => undefined, }); // Since Deno doesn't have Buffer by default, we need to use Uint8Array extensionCodec.register({ - type: 1, - encode: (object: unknown) => { - if (object instanceof Buffer) { - return new Uint8Array(object.buffer, object.byteOffset, object.byteLength); - } - - return null; - }, - // msgpack will reuse the Uint8Array instance, so WE NEED to copy it instead of simply creating a view - decode: (data: Uint8Array) => { - return Buffer.from(data); - }, + type: 1, + encode: (object: unknown) => { + if (object instanceof Buffer) { + return new Uint8Array(object.buffer, object.byteOffset, object.byteLength); + } + + return null; + }, + // msgpack will reuse the Uint8Array instance, so WE NEED to copy it instead of simply creating a view + decode: (data: Uint8Array) => { + return Buffer.from(data); + }, }); export const encoder = new Encoder({ extensionCodec }); diff --git a/packages/apps-engine/deno-runtime/lib/logger.ts b/packages/apps-engine/deno-runtime/lib/logger.ts index ea2701c702308..336c420080d37 100644 --- a/packages/apps-engine/deno-runtime/lib/logger.ts +++ b/packages/apps-engine/deno-runtime/lib/logger.ts @@ -2,141 +2,141 @@ import stackTrace from 'stack-trace'; import { AppObjectRegistry } from '../AppObjectRegistry.ts'; export interface StackFrame { - getTypeName(): string; - getFunctionName(): string; - getMethodName(): string; - getFileName(): string; - getLineNumber(): number; - getColumnNumber(): number; - isNative(): boolean; - isConstructor(): boolean; + getTypeName(): string; + getFunctionName(): string; + getMethodName(): string; + getFileName(): string; + getLineNumber(): number; + getColumnNumber(): number; + isNative(): boolean; + isConstructor(): boolean; } enum LogMessageSeverity { - DEBUG = 'debug', - INFORMATION = 'info', - LOG = 'log', - WARNING = 'warning', - ERROR = 'error', - SUCCESS = 'success', + DEBUG = 'debug', + INFORMATION = 'info', + LOG = 'log', + WARNING = 'warning', + ERROR = 'error', + SUCCESS = 'success', } type Entry = { - caller: string; - severity: LogMessageSeverity; - method: string; - timestamp: Date; - args: Array; + caller: string; + severity: LogMessageSeverity; + method: string; + timestamp: Date; + args: Array; }; interface ILoggerStorageEntry { - appId: string; - method: string; - entries: Array; - startTime: Date; - endTime: Date; - totalTime: number; - _createdAt: Date; + appId: string; + method: string; + entries: Array; + startTime: Date; + endTime: Date; + totalTime: number; + _createdAt: Date; } export class Logger { - private entries: Array; - private start: Date; - private method: string; - - constructor(method: string) { - this.method = method; - this.entries = []; - this.start = new Date(); - } - - public debug(...args: Array): void { - this.addEntry(LogMessageSeverity.DEBUG, this.getStack(stackTrace.get()), ...args); - } - - public info(...args: Array): void { - this.addEntry(LogMessageSeverity.INFORMATION, this.getStack(stackTrace.get()), ...args); - } - - public log(...args: Array): void { - this.addEntry(LogMessageSeverity.LOG, this.getStack(stackTrace.get()), ...args); - } - - public warn(...args: Array): void { - this.addEntry(LogMessageSeverity.WARNING, this.getStack(stackTrace.get()), ...args); - } - - public error(...args: Array): void { - this.addEntry(LogMessageSeverity.ERROR, this.getStack(stackTrace.get()), ...args); - } - - public success(...args: Array): void { - this.addEntry(LogMessageSeverity.SUCCESS, this.getStack(stackTrace.get()), ...args); - } - - private addEntry(severity: LogMessageSeverity, caller: string, ...items: Array): void { - const i = items.map((args) => { - if (args instanceof Error) { - return JSON.stringify(args, Object.getOwnPropertyNames(args)); - } - if (typeof args === 'object' && args !== null && 'stack' in args) { - return JSON.stringify(args, Object.getOwnPropertyNames(args)); - } - if (typeof args === 'object' && args !== null && 'message' in args) { - return JSON.stringify(args, Object.getOwnPropertyNames(args)); - } - const str = JSON.stringify(args, null, 2); - return str ? JSON.parse(str) : str; // force call toJSON to prevent circular references - }); - - this.entries.push({ - caller, - severity, - method: this.method, - timestamp: new Date(), - args: i, - }); - } - - private getStack(stack: Array): string { - let func = 'anonymous'; - - if (stack.length === 1) { - return func; - } - - const frame = stack[1]; - - if (frame.getMethodName() === null) { - func = 'anonymous OR constructor'; - } else { - func = frame.getMethodName(); - } - - if (frame.getFunctionName() !== null) { - func = `${func} -> ${frame.getFunctionName()}`; - } - - return func; - } - - private getTotalTime(): number { - return new Date().getTime() - this.start.getTime(); - } - - public hasEntries(): boolean { - return this.entries.length > 0; - } - - public getLogs(): ILoggerStorageEntry { - return { - appId: AppObjectRegistry.get('id')!, - method: this.method, - entries: this.entries, - startTime: this.start, - endTime: new Date(), - totalTime: this.getTotalTime(), - _createdAt: new Date(), - }; - } + private entries: Array; + private start: Date; + private method: string; + + constructor(method: string) { + this.method = method; + this.entries = []; + this.start = new Date(); + } + + public debug(...args: Array): void { + this.addEntry(LogMessageSeverity.DEBUG, this.getStack(stackTrace.get()), ...args); + } + + public info(...args: Array): void { + this.addEntry(LogMessageSeverity.INFORMATION, this.getStack(stackTrace.get()), ...args); + } + + public log(...args: Array): void { + this.addEntry(LogMessageSeverity.LOG, this.getStack(stackTrace.get()), ...args); + } + + public warn(...args: Array): void { + this.addEntry(LogMessageSeverity.WARNING, this.getStack(stackTrace.get()), ...args); + } + + public error(...args: Array): void { + this.addEntry(LogMessageSeverity.ERROR, this.getStack(stackTrace.get()), ...args); + } + + public success(...args: Array): void { + this.addEntry(LogMessageSeverity.SUCCESS, this.getStack(stackTrace.get()), ...args); + } + + private addEntry(severity: LogMessageSeverity, caller: string, ...items: Array): void { + const i = items.map((args) => { + if (args instanceof Error) { + return JSON.stringify(args, Object.getOwnPropertyNames(args)); + } + if (typeof args === 'object' && args !== null && 'stack' in args) { + return JSON.stringify(args, Object.getOwnPropertyNames(args)); + } + if (typeof args === 'object' && args !== null && 'message' in args) { + return JSON.stringify(args, Object.getOwnPropertyNames(args)); + } + const str = JSON.stringify(args, null, 2); + return str ? JSON.parse(str) : str; // force call toJSON to prevent circular references + }); + + this.entries.push({ + caller, + severity, + method: this.method, + timestamp: new Date(), + args: i, + }); + } + + private getStack(stack: Array): string { + let func = 'anonymous'; + + if (stack.length === 1) { + return func; + } + + const frame = stack[1]; + + if (frame.getMethodName() === null) { + func = 'anonymous OR constructor'; + } else { + func = frame.getMethodName(); + } + + if (frame.getFunctionName() !== null) { + func = `${func} -> ${frame.getFunctionName()}`; + } + + return func; + } + + private getTotalTime(): number { + return new Date().getTime() - this.start.getTime(); + } + + public hasEntries(): boolean { + return this.entries.length > 0; + } + + public getLogs(): ILoggerStorageEntry { + return { + appId: AppObjectRegistry.get('id')!, + method: this.method, + entries: this.entries, + startTime: this.start, + endTime: new Date(), + totalTime: this.getTotalTime(), + _createdAt: new Date(), + }; + } } diff --git a/packages/apps-engine/deno-runtime/lib/messenger.ts b/packages/apps-engine/deno-runtime/lib/messenger.ts index 5881d408c01ce..c8d8182b0480b 100644 --- a/packages/apps-engine/deno-runtime/lib/messenger.ts +++ b/packages/apps-engine/deno-runtime/lib/messenger.ts @@ -1,4 +1,4 @@ -import { writeAll } from "https://deno.land/std@0.216.0/io/write_all.ts"; +import { writeAll } from 'https://deno.land/std@0.216.0/io/write_all.ts'; import * as jsonrpc from 'jsonrpc-lite'; @@ -18,15 +18,15 @@ export type JsonRpcRequest = jsonrpc.IParsedObjectRequest | jsonrpc.IParsedObjec export type JsonRpcResponse = jsonrpc.IParsedObjectSuccess | jsonrpc.IParsedObjectError; export function isRequest(message: jsonrpc.IParsedObject): message is JsonRpcRequest { - return message.type === 'request' || message.type === 'notification'; + return message.type === 'request' || message.type === 'notification'; } export function isResponse(message: jsonrpc.IParsedObject): message is JsonRpcResponse { - return message.type === 'success' || message.type === 'error'; + return message.type === 'success' || message.type === 'error'; } export function isErrorResponse(message: jsonrpc.JsonRpc): message is jsonrpc.ErrorObject { - return message instanceof jsonrpc.ErrorObject; + return message instanceof jsonrpc.ErrorObject; } const COMMAND_PONG = '_zPONG'; @@ -34,170 +34,170 @@ const COMMAND_PONG = '_zPONG'; export const RPCResponseObserver = new EventTarget(); export const Queue = new (class Queue { - private queue: Uint8Array[] = []; - private isProcessing = false; + private queue: Uint8Array[] = []; + private isProcessing = false; - private async processQueue() { - if (this.isProcessing) { - return; - } + private async processQueue() { + if (this.isProcessing) { + return; + } - this.isProcessing = true; + this.isProcessing = true; - while (this.queue.length) { - const message = this.queue.shift(); + while (this.queue.length) { + const message = this.queue.shift(); - if (message) { - await Transport.send(message); - } - } + if (message) { + await Transport.send(message); + } + } - this.isProcessing = false; - } + this.isProcessing = false; + } - public enqueue(message: jsonrpc.JsonRpc | typeof COMMAND_PONG) { - this.queue.push(encoder.encode(message)); - this.processQueue(); - } + public enqueue(message: jsonrpc.JsonRpc | typeof COMMAND_PONG) { + this.queue.push(encoder.encode(message)); + this.processQueue(); + } - public getCurrentSize() { - return this.queue.length; - } -}); + public getCurrentSize() { + return this.queue.length; + } +})(); export const Transport = new (class Transporter { - private selectedTransport: Transporter['stdoutTransport'] | Transporter['noopTransport']; - - constructor() { - this.selectedTransport = this.stdoutTransport.bind(this); - } - - private async stdoutTransport(message: Uint8Array): Promise { - await writeAll(Deno.stdout, message); - } - - private async noopTransport(_message: Uint8Array): Promise {} - - public selectTransport(transport: 'stdout' | 'noop'): void { - switch (transport) { - case 'stdout': - this.selectedTransport = this.stdoutTransport.bind(this); - break; - case 'noop': - this.selectedTransport = this.noopTransport.bind(this); - break; - } - } - - public send(message: Uint8Array): Promise { - return this.selectedTransport(message); - } + private selectedTransport: Transporter['stdoutTransport'] | Transporter['noopTransport']; + + constructor() { + this.selectedTransport = this.stdoutTransport.bind(this); + } + + private async stdoutTransport(message: Uint8Array): Promise { + await writeAll(Deno.stdout, message); + } + + private async noopTransport(_message: Uint8Array): Promise {} + + public selectTransport(transport: 'stdout' | 'noop'): void { + switch (transport) { + case 'stdout': + this.selectedTransport = this.stdoutTransport.bind(this); + break; + case 'noop': + this.selectedTransport = this.noopTransport.bind(this); + break; + } + } + + public send(message: Uint8Array): Promise { + return this.selectedTransport(message); + } })(); export function parseMessage(message: string | Record) { - let parsed: jsonrpc.IParsedObject | jsonrpc.IParsedObject[]; + let parsed: jsonrpc.IParsedObject | jsonrpc.IParsedObject[]; - if (typeof message === 'string') { - parsed = jsonrpc.parse(message); - } else { - parsed = jsonrpc.parseObject(message); - } + if (typeof message === 'string') { + parsed = jsonrpc.parse(message); + } else { + parsed = jsonrpc.parseObject(message); + } - if (Array.isArray(parsed)) { - throw jsonrpc.error(null, jsonrpc.JsonRpcError.invalidRequest(null)); - } + if (Array.isArray(parsed)) { + throw jsonrpc.error(null, jsonrpc.JsonRpcError.invalidRequest(null)); + } - if (parsed.type === 'invalid') { - throw jsonrpc.error(null, parsed.payload); - } + if (parsed.type === 'invalid') { + throw jsonrpc.error(null, parsed.payload); + } - return parsed; + return parsed; } export async function sendInvalidRequestError(): Promise { - const rpc = jsonrpc.error(null, jsonrpc.JsonRpcError.invalidRequest(null)); + const rpc = jsonrpc.error(null, jsonrpc.JsonRpcError.invalidRequest(null)); - await Queue.enqueue(rpc); + await Queue.enqueue(rpc); } export async function sendInvalidParamsError(id: jsonrpc.ID): Promise { - const rpc = jsonrpc.error(id, jsonrpc.JsonRpcError.invalidParams(null)); + const rpc = jsonrpc.error(id, jsonrpc.JsonRpcError.invalidParams(null)); - await Queue.enqueue(rpc); + await Queue.enqueue(rpc); } export async function sendParseError(): Promise { - const rpc = jsonrpc.error(null, jsonrpc.JsonRpcError.parseError(null)); + const rpc = jsonrpc.error(null, jsonrpc.JsonRpcError.parseError(null)); - await Queue.enqueue(rpc); + await Queue.enqueue(rpc); } export async function sendMethodNotFound(id: jsonrpc.ID): Promise { - const rpc = jsonrpc.error(id, jsonrpc.JsonRpcError.methodNotFound(null)); + const rpc = jsonrpc.error(id, jsonrpc.JsonRpcError.methodNotFound(null)); - await Queue.enqueue(rpc); + await Queue.enqueue(rpc); } export async function errorResponse({ error: { message, code = -32000, data = {} }, id }: ErrorResponseDescriptor): Promise { - const logger = AppObjectRegistry.get('logger'); + const logger = AppObjectRegistry.get('logger'); - if (logger?.hasEntries()) { - data.logs = logger.getLogs(); - } + if (logger?.hasEntries()) { + data.logs = logger.getLogs(); + } - const rpc = jsonrpc.error(id, new jsonrpc.JsonRpcError(message, code, data)); + const rpc = jsonrpc.error(id, new jsonrpc.JsonRpcError(message, code, data)); - await Queue.enqueue(rpc); + await Queue.enqueue(rpc); } export async function successResponse({ id, result }: SuccessResponseDescriptor): Promise { - const payload = { value: result } as Record; - const logger = AppObjectRegistry.get('logger'); + const payload = { value: result } as Record; + const logger = AppObjectRegistry.get('logger'); - if (logger?.hasEntries()) { - payload.logs = logger.getLogs(); - } + if (logger?.hasEntries()) { + payload.logs = logger.getLogs(); + } - const rpc = jsonrpc.success(id, payload); + const rpc = jsonrpc.success(id, payload); - await Queue.enqueue(rpc); + await Queue.enqueue(rpc); } export function pongResponse(): Promise { - return Promise.resolve(Queue.enqueue(COMMAND_PONG)); + return Promise.resolve(Queue.enqueue(COMMAND_PONG)); } export async function sendRequest(requestDescriptor: RequestDescriptor): Promise { - const request = jsonrpc.request(Math.random().toString(36).slice(2), requestDescriptor.method, requestDescriptor.params); + const request = jsonrpc.request(Math.random().toString(36).slice(2), requestDescriptor.method, requestDescriptor.params); - // TODO: add timeout to this - const responsePromise = new Promise((resolve, reject) => { - const handler = (event: Event) => { - if (event instanceof ErrorEvent) { - reject(event.error); - } + // TODO: add timeout to this + const responsePromise = new Promise((resolve, reject) => { + const handler = (event: Event) => { + if (event instanceof ErrorEvent) { + reject(event.error); + } - if (event instanceof CustomEvent) { - resolve(event.detail); - } + if (event instanceof CustomEvent) { + resolve(event.detail); + } - RPCResponseObserver.removeEventListener(`response:${request.id}`, handler); - }; + RPCResponseObserver.removeEventListener(`response:${request.id}`, handler); + }; - RPCResponseObserver.addEventListener(`response:${request.id}`, handler); - }); + RPCResponseObserver.addEventListener(`response:${request.id}`, handler); + }); - await Queue.enqueue(request); + await Queue.enqueue(request); - return responsePromise as Promise; + return responsePromise as Promise; } export function sendNotification({ method, params }: NotificationDescriptor) { - const request = jsonrpc.notification(method, params); + const request = jsonrpc.notification(method, params); - Queue.enqueue(request); + Queue.enqueue(request); } export function log(params: jsonrpc.RpcParams) { - sendNotification({ method: 'log', params }); + sendNotification({ method: 'log', params }); } diff --git a/packages/apps-engine/deno-runtime/lib/metricsCollector.ts b/packages/apps-engine/deno-runtime/lib/metricsCollector.ts index 0a95460e299cd..df14ed3c94347 100644 --- a/packages/apps-engine/deno-runtime/lib/metricsCollector.ts +++ b/packages/apps-engine/deno-runtime/lib/metricsCollector.ts @@ -2,11 +2,11 @@ import { writeAll } from 'https://deno.land/std@0.216.0/io/write_all.ts'; import { Queue } from './messenger.ts'; export function collectMetrics() { - return { - pid: Deno.pid, - queueSize: Queue.getCurrentSize(), - } -}; + return { + pid: Deno.pid, + queueSize: Queue.getCurrentSize(), + }; +} const encoder = new TextEncoder(); @@ -14,7 +14,7 @@ const encoder = new TextEncoder(); * Sends metrics collected from the system via stderr */ export async function sendMetrics() { - const metrics = collectMetrics(); + const metrics = collectMetrics(); - await writeAll(Deno.stderr, encoder.encode(JSON.stringify(metrics))); + await writeAll(Deno.stderr, encoder.encode(JSON.stringify(metrics))); } diff --git a/packages/apps-engine/deno-runtime/lib/parseArgs.ts b/packages/apps-engine/deno-runtime/lib/parseArgs.ts index b628aab76ec7d..a9c4844154990 100644 --- a/packages/apps-engine/deno-runtime/lib/parseArgs.ts +++ b/packages/apps-engine/deno-runtime/lib/parseArgs.ts @@ -1,11 +1,11 @@ -import { parseArgs as $parseArgs } from "@std/cli/parse-args"; +import { parseArgs as $parseArgs } from '@std/cli/parse-args'; export type ParsedArgs = { - subprocess: string; - spawnId: number; - metricsReportFrequencyInMs?: number; -} + subprocess: string; + spawnId: number; + metricsReportFrequencyInMs?: number; +}; export function parseArgs(args: string[]): ParsedArgs { - return $parseArgs(args); + return $parseArgs(args); } diff --git a/packages/apps-engine/deno-runtime/lib/require.ts b/packages/apps-engine/deno-runtime/lib/require.ts index 3288ecf67ffa2..845b38fc1ca2b 100644 --- a/packages/apps-engine/deno-runtime/lib/require.ts +++ b/packages/apps-engine/deno-runtime/lib/require.ts @@ -3,12 +3,12 @@ import { createRequire } from 'node:module'; const _require = createRequire(import.meta.url); export const require = (mod: string) => { - // When we try to import something from the apps-engine, we resolve the path using import maps from Deno - // However, the import maps are configured to look at the source folder for typescript files, but during - // runtime those files are not available - if (mod.startsWith('@rocket.chat/apps-engine')) { - mod = import.meta.resolve(mod).replace('file://', '').replace('src/', ''); - } + // When we try to import something from the apps-engine, we resolve the path using import maps from Deno + // However, the import maps are configured to look at the source folder for typescript files, but during + // runtime those files are not available + if (mod.startsWith('@rocket.chat/apps-engine')) { + mod = import.meta.resolve(mod).replace('file://', '').replace('src/', ''); + } - return _require(mod); -} + return _require(mod); +}; diff --git a/packages/apps-engine/deno-runtime/lib/room.ts b/packages/apps-engine/deno-runtime/lib/room.ts index b7423cdd31ff3..282ded4a90457 100644 --- a/packages/apps-engine/deno-runtime/lib/room.ts +++ b/packages/apps-engine/deno-runtime/lib/room.ts @@ -6,99 +6,99 @@ import type { AppManager } from '@rocket.chat/apps-engine/server/AppManager.ts'; const PrivateManager = Symbol('RoomPrivateManager'); export class Room { - public id: string | undefined; + public id: string | undefined; - public displayName?: string; + public displayName?: string; - public slugifiedName: string | undefined; + public slugifiedName: string | undefined; - public type: RoomType | undefined; + public type: RoomType | undefined; - public creator: IUser | undefined; + public creator: IUser | undefined; - public isDefault?: boolean; + public isDefault?: boolean; - public isReadOnly?: boolean; + public isReadOnly?: boolean; - public displaySystemMessages?: boolean; + public displaySystemMessages?: boolean; - public messageCount?: number; + public messageCount?: number; - public createdAt?: Date; + public createdAt?: Date; - public updatedAt?: Date; + public updatedAt?: Date; - public lastModifiedAt?: Date; + public lastModifiedAt?: Date; - public customFields?: { [key: string]: unknown }; + public customFields?: { [key: string]: unknown }; - public userIds?: Array; + public userIds?: Array; - private _USERNAMES: Promise> | undefined; + private _USERNAMES: Promise> | undefined; - private [PrivateManager]: AppManager | undefined; + private [PrivateManager]: AppManager | undefined; - /** - * @deprecated - */ - public get usernames(): Promise> { - if (!this._USERNAMES) { - this._USERNAMES = this[PrivateManager]?.getBridges().getInternalBridge().doGetUsernamesOfRoomById(this.id); - } + /** + * @deprecated + */ + public get usernames(): Promise> { + if (!this._USERNAMES) { + this._USERNAMES = this[PrivateManager]?.getBridges().getInternalBridge().doGetUsernamesOfRoomById(this.id); + } - return this._USERNAMES || Promise.resolve([]); - } + return this._USERNAMES || Promise.resolve([]); + } - public set usernames(usernames) {} + public set usernames(usernames) {} - public constructor(room: IRoom, manager: AppManager) { - Object.assign(this, room); + public constructor(room: IRoom, manager: AppManager) { + Object.assign(this, room); - Object.defineProperty(this, PrivateManager, { - configurable: false, - enumerable: false, - writable: false, - value: manager, - }); - } + Object.defineProperty(this, PrivateManager, { + configurable: false, + enumerable: false, + writable: false, + value: manager, + }); + } - get value(): object { - return { - id: this.id, - displayName: this.displayName, - slugifiedName: this.slugifiedName, - type: this.type, - creator: this.creator, - isDefault: this.isDefault, - isReadOnly: this.isReadOnly, - displaySystemMessages: this.displaySystemMessages, - messageCount: this.messageCount, - createdAt: this.createdAt, - updatedAt: this.updatedAt, - lastModifiedAt: this.lastModifiedAt, - customFields: this.customFields, - userIds: this.userIds, - }; - } + get value(): object { + return { + id: this.id, + displayName: this.displayName, + slugifiedName: this.slugifiedName, + type: this.type, + creator: this.creator, + isDefault: this.isDefault, + isReadOnly: this.isReadOnly, + displaySystemMessages: this.displaySystemMessages, + messageCount: this.messageCount, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + lastModifiedAt: this.lastModifiedAt, + customFields: this.customFields, + userIds: this.userIds, + }; + } - public async getUsernames(): Promise> { - // Get usernames - if (!this._USERNAMES) { - this._USERNAMES = await this[PrivateManager]?.getBridges().getInternalBridge().doGetUsernamesOfRoomById(this.id); - } + public async getUsernames(): Promise> { + // Get usernames + if (!this._USERNAMES) { + this._USERNAMES = await this[PrivateManager]?.getBridges().getInternalBridge().doGetUsernamesOfRoomById(this.id); + } - return this._USERNAMES || []; - } + return this._USERNAMES || []; + } - public toJSON() { - return this.value; - } + public toJSON() { + return this.value; + } - public toString() { - return this.value; - } + public toString() { + return this.value; + } - public valueOf() { - return this.value; - } + public valueOf() { + return this.value; + } } diff --git a/packages/apps-engine/deno-runtime/lib/roomFactory.ts b/packages/apps-engine/deno-runtime/lib/roomFactory.ts index 8c270eeb86b96..902eba92cfc15 100644 --- a/packages/apps-engine/deno-runtime/lib/roomFactory.ts +++ b/packages/apps-engine/deno-runtime/lib/roomFactory.ts @@ -1,27 +1,27 @@ -import type { IRoom } from "@rocket.chat/apps-engine/definition/rooms/IRoom.ts"; -import type { AppManager } from "@rocket.chat/apps-engine/server/AppManager.ts"; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { AppManager } from '@rocket.chat/apps-engine/server/AppManager.ts'; -import { AppAccessors } from "./accessors/mod.ts"; -import { Room } from "./room.ts"; -import { JsonRpcError } from "jsonrpc-lite"; +import { AppAccessors } from './accessors/mod.ts'; +import { Room } from './room.ts'; +import { JsonRpcError } from 'jsonrpc-lite'; const getMockAppManager = (senderFn: AppAccessors['senderFn']) => ({ - getBridges: () => ({ - getInternalBridge: () => ({ - doGetUsernamesOfRoomById: (roomId: string) => { - return senderFn({ - method: 'bridges:getInternalBridge:doGetUsernamesOfRoomById', - params: [roomId], - }).then((result) => result.result).catch((err) => { - throw new JsonRpcError(`Error getting usernames of room: ${err}`, -32000); - }) - }, - }), - }), + getBridges: () => ({ + getInternalBridge: () => ({ + doGetUsernamesOfRoomById: (roomId: string) => { + return senderFn({ + method: 'bridges:getInternalBridge:doGetUsernamesOfRoomById', + params: [roomId], + }).then((result) => result.result).catch((err) => { + throw new JsonRpcError(`Error getting usernames of room: ${err}`, -32000); + }); + }, + }), + }), }); export default function createRoom(room: IRoom, senderFn: AppAccessors['senderFn']) { - const mockAppManager = getMockAppManager(senderFn); + const mockAppManager = getMockAppManager(senderFn); - return new Room(room, mockAppManager as unknown as AppManager); + return new Room(room, mockAppManager as unknown as AppManager); } diff --git a/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts b/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts index 91cf6587e7413..4b5838bce12d1 100644 --- a/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts +++ b/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts @@ -1,20 +1,20 @@ -import { fixBrokenSynchronousAPICalls } from "./ast/mod.ts"; +import { fixBrokenSynchronousAPICalls } from './ast/mod.ts'; function hasPotentialDeprecatedUsage(source: string) { - return ( - // potential usage of Room.usernames getter - source.includes('.usernames') || - // potential usage of LivechatRead.isOnline method - source.includes('.isOnline(') || - // potential usage of LivechatCreator.createToken method - source.includes('.createToken(') - ) + return ( + // potential usage of Room.usernames getter + source.includes('.usernames') || + // potential usage of LivechatRead.isOnline method + source.includes('.isOnline(') || + // potential usage of LivechatCreator.createToken method + source.includes('.createToken(') + ); } export function sanitizeDeprecatedUsage(source: string) { - if (!hasPotentialDeprecatedUsage(source)) { - return source; - } + if (!hasPotentialDeprecatedUsage(source)) { + return source; + } - return fixBrokenSynchronousAPICalls(source); + return fixBrokenSynchronousAPICalls(source); } diff --git a/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts b/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts index f69a728e79afd..7ccc49b3b9ca4 100644 --- a/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts +++ b/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts @@ -1,111 +1,110 @@ import { assertEquals } from 'https://deno.land/std@0.203.0/assert/mod.ts'; import { describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; -import { Logger } from "../logger.ts"; +import { Logger } from '../logger.ts'; describe('Logger', () => { - it('getLogs should return an array of entries', () => { - const logger = new Logger('test'); - logger.info('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.method, 'test'); - }) + it('getLogs should return an array of entries', () => { + const logger = new Logger('test'); + logger.info('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.method, 'test'); + }); - it('should be able to add entries of different severity', () => { - const logger = new Logger('test'); - logger.info('test'); - logger.debug('test'); - logger.error('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 3); - assertEquals(logs.entries[0].severity, 'info'); - assertEquals(logs.entries[1].severity, 'debug'); - assertEquals(logs.entries[2].severity, 'error'); - }) + it('should be able to add entries of different severity', () => { + const logger = new Logger('test'); + logger.info('test'); + logger.debug('test'); + logger.error('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 3); + assertEquals(logs.entries[0].severity, 'info'); + assertEquals(logs.entries[1].severity, 'debug'); + assertEquals(logs.entries[2].severity, 'error'); + }); - it('should be able to add an info entry', () => { - const logger = new Logger('test'); - logger.info('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'info'); - }); + it('should be able to add an info entry', () => { + const logger = new Logger('test'); + logger.info('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'info'); + }); - it('should be able to add an debug entry', () => { - const logger = new Logger('test'); - logger.debug('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'debug'); - }); + it('should be able to add an debug entry', () => { + const logger = new Logger('test'); + logger.debug('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'debug'); + }); - it('should be able to add an error entry', () => { - const logger = new Logger('test'); - logger.error('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'error'); - }); + it('should be able to add an error entry', () => { + const logger = new Logger('test'); + logger.error('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'error'); + }); - it('should be able to add an success entry', () => { - const logger = new Logger('test'); - logger.success('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'success'); - }); + it('should be able to add an success entry', () => { + const logger = new Logger('test'); + logger.success('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'success'); + }); - it('should be able to add an warning entry', () => { - const logger = new Logger('test'); - logger.warn('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'warning'); - }); + it('should be able to add an warning entry', () => { + const logger = new Logger('test'); + logger.warn('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'warning'); + }); - it('should be able to add an log entry', () => { - const logger = new Logger('test'); - logger.log('test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'log'); - }); + it('should be able to add an log entry', () => { + const logger = new Logger('test'); + logger.log('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'log'); + }); - it('should be able to add an entry with multiple arguments', () => { - const logger = new Logger('test'); - logger.log('test', 'test', 'test'); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].args[1], 'test'); - assertEquals(logs.entries[0].args[2], 'test'); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'log'); - }); + it('should be able to add an entry with multiple arguments', () => { + const logger = new Logger('test'); + logger.log('test', 'test', 'test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].args[1], 'test'); + assertEquals(logs.entries[0].args[2], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'log'); + }); - it('should be able to add an entry with multiple arguments of different types', () => { - const logger = new Logger('test'); - logger.log('test', 1, true, { foo: 'bar' }); - const logs = logger.getLogs(); - assertEquals(logs.entries.length, 1); - assertEquals(logs.entries[0].args[0], 'test'); - assertEquals(logs.entries[0].args[1], 1); - assertEquals(logs.entries[0].args[2], true); - assertEquals(logs.entries[0].args[3], { foo: 'bar' }); - assertEquals(logs.entries[0].method, 'test'); - assertEquals(logs.entries[0].severity, 'log'); - }); - -}) + it('should be able to add an entry with multiple arguments of different types', () => { + const logger = new Logger('test'); + logger.log('test', 1, true, { foo: 'bar' }); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].args[1], 1); + assertEquals(logs.entries[0].args[2], true); + assertEquals(logs.entries[0].args[3], { foo: 'bar' }); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'log'); + }); +}); diff --git a/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts b/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts index 9b4f128380bc3..afa20d198cc93 100644 --- a/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts +++ b/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts @@ -7,90 +7,90 @@ import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; import { Logger } from '../logger.ts'; describe('Messenger', () => { - beforeEach(() => { - AppObjectRegistry.clear(); - AppObjectRegistry.set('logger', new Logger('test')); - AppObjectRegistry.set('id', 'test'); - Messenger.Transport.selectTransport('noop'); - }); - - afterAll(() => { - AppObjectRegistry.clear(); - Messenger.Transport.selectTransport('stdout'); - }); - - it('should add logs to success responses', async () => { - const theSpy = spy(Messenger.Queue, 'enqueue'); - - const logger = AppObjectRegistry.get('logger') as Logger; - - logger.info('test'); - - await Messenger.successResponse({ id: 'test', result: 'test' }); - - assertEquals(theSpy.calls.length, 1); - - const [responseArgument] = theSpy.calls[0].args; - - assertObjectMatch(responseArgument, { - jsonrpc: '2.0', - id: 'test', - result: { - value: 'test', - logs: { - appId: 'test', - method: 'test', - entries: [ - { - severity: 'info', - method: 'test', - args: ['test'], - caller: 'anonymous OR constructor', - }, - ], - }, - }, - }); - - theSpy.restore(); - }); - - it('should add logs to error responses', async () => { - const theSpy = spy(Messenger.Queue, 'enqueue'); - - const logger = AppObjectRegistry.get('logger') as Logger; - - logger.info('test'); - - await Messenger.errorResponse({ id: 'test', error: { code: -32000, message: 'test' } }); - - assertEquals(theSpy.calls.length, 1); - - const [responseArgument] = theSpy.calls[0].args; - - assertObjectMatch(responseArgument, { - jsonrpc: '2.0', - id: 'test', - error: { - code: -32000, - message: 'test', - data: { - logs: { - appId: 'test', - method: 'test', - entries: [ - { - severity: 'info', - method: 'test', - args: ['test'], - caller: 'anonymous OR constructor', - }, - ], - }, - }, - }, - }); - - theSpy.restore(); - }); + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('logger', new Logger('test')); + AppObjectRegistry.set('id', 'test'); + Messenger.Transport.selectTransport('noop'); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + Messenger.Transport.selectTransport('stdout'); + }); + + it('should add logs to success responses', async () => { + const theSpy = spy(Messenger.Queue, 'enqueue'); + + const logger = AppObjectRegistry.get('logger') as Logger; + + logger.info('test'); + + await Messenger.successResponse({ id: 'test', result: 'test' }); + + assertEquals(theSpy.calls.length, 1); + + const [responseArgument] = theSpy.calls[0].args; + + assertObjectMatch(responseArgument, { + jsonrpc: '2.0', + id: 'test', + result: { + value: 'test', + logs: { + appId: 'test', + method: 'test', + entries: [ + { + severity: 'info', + method: 'test', + args: ['test'], + caller: 'anonymous OR constructor', + }, + ], + }, + }, + }); + + theSpy.restore(); + }); + + it('should add logs to error responses', async () => { + const theSpy = spy(Messenger.Queue, 'enqueue'); + + const logger = AppObjectRegistry.get('logger') as Logger; + + logger.info('test'); + + await Messenger.errorResponse({ id: 'test', error: { code: -32000, message: 'test' } }); + + assertEquals(theSpy.calls.length, 1); + + const [responseArgument] = theSpy.calls[0].args; + + assertObjectMatch(responseArgument, { + jsonrpc: '2.0', + id: 'test', + error: { + code: -32000, + message: 'test', + data: { + logs: { + appId: 'test', + method: 'test', + entries: [ + { + severity: 'info', + method: 'test', + args: ['test'], + caller: 'anonymous OR constructor', + }, + ], + }, + }, + }, + }); + + theSpy.restore(); + }); }); diff --git a/packages/apps-engine/deno-runtime/main.ts b/packages/apps-engine/deno-runtime/main.ts index 54bb3b70eba26..2debc6f800500 100644 --- a/packages/apps-engine/deno-runtime/main.ts +++ b/packages/apps-engine/deno-runtime/main.ts @@ -1,11 +1,11 @@ if (!Deno.args.includes('--subprocess')) { - Deno.stderr.writeSync( - new TextEncoder().encode(` + Deno.stderr.writeSync( + new TextEncoder().encode(` This is a Deno wrapper for Rocket.Chat Apps. It is not meant to be executed stand-alone; It is instead meant to be executed as a subprocess by the Apps-Engine framework. `), - ); - Deno.exit(1001); + ); + Deno.exit(1001); } import { JsonRpcError } from 'jsonrpc-lite'; @@ -25,108 +25,108 @@ import registerErrorListeners from './error-handlers.ts'; import { sendMetrics } from './lib/metricsCollector.ts'; type Handlers = { - app: typeof handleApp; - api: typeof apiHandler; - slashcommand: typeof slashcommandHandler; - videoconference: typeof videoConferenceHandler; - scheduler: typeof handleScheduler; - ping: (method: string, params: unknown) => 'pong'; + app: typeof handleApp; + api: typeof apiHandler; + slashcommand: typeof slashcommandHandler; + videoconference: typeof videoConferenceHandler; + scheduler: typeof handleScheduler; + ping: (method: string, params: unknown) => 'pong'; }; const COMMAND_PING = '_zPING'; async function requestRouter({ type, payload }: Messenger.JsonRpcRequest): Promise { - const methodHandlers: Handlers = { - app: handleApp, - api: apiHandler, - slashcommand: slashcommandHandler, - videoconference: videoConferenceHandler, - scheduler: handleScheduler, - ping: (_method, _params) => 'pong', - }; + const methodHandlers: Handlers = { + app: handleApp, + api: apiHandler, + slashcommand: slashcommandHandler, + videoconference: videoConferenceHandler, + scheduler: handleScheduler, + ping: (_method, _params) => 'pong', + }; - // We're not handling notifications at the moment - if (type === 'notification') { - return Messenger.sendInvalidRequestError(); - } + // We're not handling notifications at the moment + if (type === 'notification') { + return Messenger.sendInvalidRequestError(); + } - const { id, method, params } = payload; + const { id, method, params } = payload; - const logger = new Logger(method); - AppObjectRegistry.set('logger', logger); + const logger = new Logger(method); + AppObjectRegistry.set('logger', logger); - const app = AppObjectRegistry.get('app'); + const app = AppObjectRegistry.get('app'); - if (app) { - // Same logic as applied in the ProxiedApp class previously - (app as unknown as Record).logger = logger; - } + if (app) { + // Same logic as applied in the ProxiedApp class previously + (app as unknown as Record).logger = logger; + } - const [methodPrefix] = method.split(':') as [keyof Handlers]; - const handler = methodHandlers[methodPrefix]; + const [methodPrefix] = method.split(':') as [keyof Handlers]; + const handler = methodHandlers[methodPrefix]; - if (!handler) { - return Messenger.errorResponse({ - error: { message: 'Method not found', code: -32601 }, - id, - }); - } + if (!handler) { + return Messenger.errorResponse({ + error: { message: 'Method not found', code: -32601 }, + id, + }); + } - const result = await handler(method, params); + const result = await handler(method, params); - if (result instanceof JsonRpcError) { - return Messenger.errorResponse({ id, error: result }); - } + if (result instanceof JsonRpcError) { + return Messenger.errorResponse({ id, error: result }); + } - return Messenger.successResponse({ id, result }); + return Messenger.successResponse({ id, result }); } function handleResponse(response: Messenger.JsonRpcResponse): void { - let event: Event; - - if (response.type === 'error') { - event = new ErrorEvent(`response:${response.payload.id}`, { - error: response.payload, - }); - } else { - event = new CustomEvent(`response:${response.payload.id}`, { - detail: response.payload, - }); - } - - Messenger.RPCResponseObserver.dispatchEvent(event); + let event: Event; + + if (response.type === 'error') { + event = new ErrorEvent(`response:${response.payload.id}`, { + error: response.payload, + }); + } else { + event = new CustomEvent(`response:${response.payload.id}`, { + detail: response.payload, + }); + } + + Messenger.RPCResponseObserver.dispatchEvent(event); } async function main() { - Messenger.sendNotification({ method: 'ready' }); - - for await (const message of decoder.decodeStream(Deno.stdin.readable)) { - try { - // Process PING command first as it is not JSON RPC - if (message === COMMAND_PING) { - void Messenger.pongResponse(); - void sendMetrics(); - continue; - } - - const JSONRPCMessage = Messenger.parseMessage(message as Record); - - if (Messenger.isRequest(JSONRPCMessage)) { - void requestRouter(JSONRPCMessage); - continue; - } - - if (Messenger.isResponse(JSONRPCMessage)) { - handleResponse(JSONRPCMessage); - } - } catch (error) { - if (Messenger.isErrorResponse(error)) { - await Messenger.errorResponse(error); - } else { - await Messenger.sendParseError(); - } - } - } + Messenger.sendNotification({ method: 'ready' }); + + for await (const message of decoder.decodeStream(Deno.stdin.readable)) { + try { + // Process PING command first as it is not JSON RPC + if (message === COMMAND_PING) { + void Messenger.pongResponse(); + void sendMetrics(); + continue; + } + + const JSONRPCMessage = Messenger.parseMessage(message as Record); + + if (Messenger.isRequest(JSONRPCMessage)) { + void requestRouter(JSONRPCMessage); + continue; + } + + if (Messenger.isResponse(JSONRPCMessage)) { + handleResponse(JSONRPCMessage); + } + } catch (error) { + if (Messenger.isErrorResponse(error)) { + await Messenger.errorResponse(error); + } else { + await Messenger.sendParseError(); + } + } + } } registerErrorListeners(); diff --git a/packages/apps-engine/package.json b/packages/apps-engine/package.json index fff088de1f0dd..07a47f5b0cc40 100644 --- a/packages/apps-engine/package.json +++ b/packages/apps-engine/package.json @@ -1,128 +1,130 @@ { - "name": "@rocket.chat/apps-engine", - "version": "1.52.0", - "description": "The engine code for the Rocket.Chat Apps which manages, runs, translates, coordinates and all of that.", - "main": "index", - "typings": "index", - "scripts": { - "start": "run-s .:build:clean .:build:watch", - "testunit": "run-p .:test:node .:test:deno", - ".:test:node": "NODE_ENV=test ts-node ./tests/runner.ts", - ".:test:deno": "cd deno-runtime && deno task test", - ".:lint:eslint": "eslint .", - ".:lint:deno": "deno lint --ignore=deno-runtime/.deno deno-runtime/", - "lint": "yarn .:lint:eslint && yarn .:lint:deno", - "fix-lint": "eslint . --fix", - "build": "run-s .:build:clean .:build:default .:build:deno-cache", - ".:build:clean": "rimraf client definition server", - ".:build:default": "tsc -p tsconfig.json", - ".:build:deno-cache": "node scripts/deno-cache.js", - ".:build:watch": "yarn .:build:default --watch", - "typecheck": "tsc -p tsconfig.json --noEmit", - "bundle": "node scripts/bundle.js", - "gen-doc": "typedoc", - "prepack": "yarn bundle" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/RocketChat/Rocket.Chat.Apps-engine.git" - }, - "keywords": [ - "rocket.chat", - "team chat", - "apps engine" - ], - "files": [ - "client/**", - "definition/**", - "deno-runtime/**", - "lib/**", - "scripts/**", - "server/**" - ], - "publishConfig": { - "access": "public" - }, - "author": { - "name": "Rocket.Chat", - "url": "https://rocket.chat/" - }, - "contributors": [ - { - "name": "Bradley Hilton", - "email": "bradley.hilton@rocket.chat" - }, - { - "name": "Rodrigo Nascimento", - "email": "rodrigo.nascimento@rocket.chat" - }, - { - "name": "Douglas Gubert", - "email": "douglas.gubert@rocket.chat" - } - ], - "license": "MIT", - "bugs": { - "url": "https://github.com/RocketChat/Rocket.Chat.Apps-engine/issues" - }, - "homepage": "https://github.com/RocketChat/Rocket.Chat.Apps-engine#readme", - "devDependencies": { - "@rocket.chat/eslint-config": "workspace:~", - "@rocket.chat/ui-kit": "workspace:~", - "@types/adm-zip": "^0.5.6", - "@types/debug": "^4.1.12", - "@types/lodash.clonedeep": "^4.5.9", - "@types/nedb": "^1.8.16", - "@types/node": "~22.14.0", - "@types/semver": "^7.5.8", - "@types/stack-trace": "0.0.33", - "@types/uuid": "~10.0.0", - "@typescript-eslint/eslint-plugin": "~5.60.1", - "@typescript-eslint/parser": "~5.60.1", - "alsatian": "^2.4.0", - "browserify": "^16.5.2", - "eslint": "~8.45.0", - "nedb": "^1.8.0", - "npm-run-all": "^4.1.5", - "nyc": "^17.1.0", - "rimraf": "^6.0.1", - "tap-bark": "^1.0.0", - "ts-node": "^6.2.0", - "typedoc": "~0.24.8", - "typescript": "~5.8.3", - "uglify-es": "^3.3.10" - }, - "dependencies": { - "@msgpack/msgpack": "3.0.0-beta2", - "adm-zip": "^0.5.16", - "debug": "^4.3.7", - "esbuild": "^0.25.0", - "jose": "^4.15.9", - "jsonrpc-lite": "^2.2.0", - "lodash.clonedeep": "^4.5.0", - "semver": "^7.6.3", - "stack-trace": "0.0.10", - "uuid": "~11.0.3" - }, - "nyc": { - "include": [ - "src/*.ts", - "src/server/**/*.ts" - ], - "extension": [ - ".ts" - ], - "reporter": [ - "lcov", - "json", - "html" - ], - "all": true - }, - "volta": { - "extends": "../../package.json" - }, - "installConfig": { - "hoistingLimits": "workspaces" - } + "name": "@rocket.chat/apps-engine", + "version": "1.52.0", + "description": "The engine code for the Rocket.Chat Apps which manages, runs, translates, coordinates and all of that.", + "main": "index", + "typings": "index", + "scripts": { + "start": "run-s .:build:clean .:build:watch", + "testunit": "run-p .:test:node .:test:deno", + ".:test:node": "NODE_ENV=test ts-node ./tests/runner.ts", + ".:test:deno": "cd deno-runtime && deno task test", + ".:lint:eslint": "eslint .", + ".:lint:deno": "deno lint --ignore=deno-runtime/.deno deno-runtime/", + "lint": "yarn .:lint:eslint && yarn .:lint:deno", + "fix-lint": "yarn .:eslint:fix && yarn .:deno-fmt:fix", + ".:eslint:fix": "eslint . --fix", + ".:deno-fmt:fix": "cd deno-runtime && deno fmt", + "build": "run-s .:build:clean .:build:default .:build:deno-cache", + ".:build:clean": "rimraf client definition server", + ".:build:default": "tsc -p tsconfig.json", + ".:build:deno-cache": "node scripts/deno-cache.js", + ".:build:watch": "yarn .:build:default --watch", + "typecheck": "tsc -p tsconfig.json --noEmit", + "bundle": "node scripts/bundle.js", + "gen-doc": "typedoc", + "prepack": "yarn bundle" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/RocketChat/Rocket.Chat.Apps-engine.git" + }, + "keywords": [ + "rocket.chat", + "team chat", + "apps engine" + ], + "files": [ + "client/**", + "definition/**", + "deno-runtime/**", + "lib/**", + "scripts/**", + "server/**" + ], + "publishConfig": { + "access": "public" + }, + "author": { + "name": "Rocket.Chat", + "url": "https://rocket.chat/" + }, + "contributors": [ + { + "name": "Bradley Hilton", + "email": "bradley.hilton@rocket.chat" + }, + { + "name": "Rodrigo Nascimento", + "email": "rodrigo.nascimento@rocket.chat" + }, + { + "name": "Douglas Gubert", + "email": "douglas.gubert@rocket.chat" + } + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/RocketChat/Rocket.Chat.Apps-engine/issues" + }, + "homepage": "https://github.com/RocketChat/Rocket.Chat.Apps-engine#readme", + "devDependencies": { + "@rocket.chat/eslint-config": "workspace:~", + "@rocket.chat/ui-kit": "workspace:~", + "@types/adm-zip": "^0.5.6", + "@types/debug": "^4.1.12", + "@types/lodash.clonedeep": "^4.5.9", + "@types/nedb": "^1.8.16", + "@types/node": "~22.14.0", + "@types/semver": "^7.5.8", + "@types/stack-trace": "0.0.33", + "@types/uuid": "~10.0.0", + "@typescript-eslint/eslint-plugin": "~5.60.1", + "@typescript-eslint/parser": "~5.60.1", + "alsatian": "^2.4.0", + "browserify": "^16.5.2", + "eslint": "~8.45.0", + "nedb": "^1.8.0", + "npm-run-all": "^4.1.5", + "nyc": "^17.1.0", + "rimraf": "^6.0.1", + "tap-bark": "^1.0.0", + "ts-node": "^6.2.0", + "typedoc": "~0.24.8", + "typescript": "~5.8.3", + "uglify-es": "^3.3.10" + }, + "dependencies": { + "@msgpack/msgpack": "3.0.0-beta2", + "adm-zip": "^0.5.16", + "debug": "^4.3.7", + "esbuild": "^0.25.0", + "jose": "^4.15.9", + "jsonrpc-lite": "^2.2.0", + "lodash.clonedeep": "^4.5.0", + "semver": "^7.6.3", + "stack-trace": "0.0.10", + "uuid": "~11.0.3" + }, + "nyc": { + "include": [ + "src/*.ts", + "src/server/**/*.ts" + ], + "extension": [ + ".ts" + ], + "reporter": [ + "lcov", + "json", + "html" + ], + "all": true + }, + "volta": { + "extends": "../../package.json" + }, + "installConfig": { + "hoistingLimits": "workspaces" + } } diff --git a/packages/apps-engine/scripts/bundle.js b/packages/apps-engine/scripts/bundle.js index a7f8932bec12c..e71268e97fce8 100644 --- a/packages/apps-engine/scripts/bundle.js +++ b/packages/apps-engine/scripts/bundle.js @@ -9,27 +9,27 @@ const targetDir = path.join(__dirname, '..', 'client'); // browserify accepts either a stream or a file path const glue = new Readable({ - read() { - console.log('read'); - this.push("window.AppsEngineUIClient = require('./AppsEngineUIClient').AppsEngineUIClient;"); - this.push(null); - }, + read() { + console.log('read'); + this.push("window.AppsEngineUIClient = require('./AppsEngineUIClient').AppsEngineUIClient;"); + this.push(null); + }, }); async function main() { - const bundle = await new Promise((resolve, reject) => - browserify(glue, { - basedir: targetDir, - }).bundle((err, bundle) => { - if (err) return reject(err); + const bundle = await new Promise((resolve, reject) => + browserify(glue, { + basedir: targetDir, + }).bundle((err, bundle) => { + if (err) return reject(err); - resolve(bundle.toString()); - }), - ); + resolve(bundle.toString()); + }), + ); - const result = minify(bundle); + const result = minify(bundle); - fs.writeFileSync(path.join(targetDir, 'AppsEngineUIClient.min.js'), result.code); + fs.writeFileSync(path.join(targetDir, 'AppsEngineUIClient.min.js'), result.code); } main(); diff --git a/packages/apps-engine/scripts/deno-cache.js b/packages/apps-engine/scripts/deno-cache.js index acf2f4b977b4d..1a331c5b9806a 100644 --- a/packages/apps-engine/scripts/deno-cache.js +++ b/packages/apps-engine/scripts/deno-cache.js @@ -2,13 +2,13 @@ const childProcess = require('child_process'); const path = require('path'); try { - childProcess.execSync('deno info'); + childProcess.execSync('deno info'); } catch (e) { - console.error( - 'Could not execute "deno" in the system. It is now a requirement for the Apps-Engine framework, and Rocket.Chat apps will not work without it.\n', - 'Make sure to install Deno and run the installation process for the Apps-Engine again. More info on https://docs.deno.com/runtime/manual/getting_started/installation', - ); - process.exit(1); + console.error( + 'Could not execute "deno" in the system. It is now a requirement for the Apps-Engine framework, and Rocket.Chat apps will not work without it.\n', + 'Make sure to install Deno and run the installation process for the Apps-Engine again. More info on https://docs.deno.com/runtime/manual/getting_started/installation', + ); + process.exit(1); } const rootPath = path.join(__dirname, '..'); @@ -16,10 +16,10 @@ const denoRuntimePath = path.join(rootPath, 'deno-runtime'); const DENO_DIR = process.env.DENO_DIR ?? path.join(rootPath, '.deno-cache'); childProcess.execSync('deno cache main.ts', { - cwd: denoRuntimePath, - env: { - DENO_DIR, - PATH: process.env.PATH, - }, - stdio: 'inherit', + cwd: denoRuntimePath, + env: { + DENO_DIR, + PATH: process.env.PATH, + }, + stdio: 'inherit', }); diff --git a/packages/apps-engine/src/client/AppClientManager.ts b/packages/apps-engine/src/client/AppClientManager.ts index 1bd89cfde8a1e..8d2cb55420eb3 100644 --- a/packages/apps-engine/src/client/AppClientManager.ts +++ b/packages/apps-engine/src/client/AppClientManager.ts @@ -3,29 +3,29 @@ import { AppsEngineUIHost } from './AppsEngineUIHost'; import type { IAppInfo } from '../definition/metadata'; export class AppClientManager { - private apps: Array; + private apps: Array; - constructor( - private readonly appsEngineUIHost: AppsEngineUIHost, - private readonly communicator?: AppServerCommunicator, - ) { - if (!(appsEngineUIHost instanceof AppsEngineUIHost)) { - throw new Error('The appClientUIHost must extend appClientUIHost'); - } + constructor( + private readonly appsEngineUIHost: AppsEngineUIHost, + private readonly communicator?: AppServerCommunicator, + ) { + if (!(appsEngineUIHost instanceof AppsEngineUIHost)) { + throw new Error('The appClientUIHost must extend appClientUIHost'); + } - if (communicator && !(communicator instanceof AppServerCommunicator)) { - throw new Error('The communicator must extend AppServerCommunicator'); - } + if (communicator && !(communicator instanceof AppServerCommunicator)) { + throw new Error('The communicator must extend AppServerCommunicator'); + } - this.apps = []; - } + this.apps = []; + } - public async load(): Promise { - this.apps = await this.communicator.getEnabledApps(); - console.log('Enabled apps:', this.apps); - } + public async load(): Promise { + this.apps = await this.communicator.getEnabledApps(); + console.log('Enabled apps:', this.apps); + } - public async initialize(): Promise { - this.appsEngineUIHost.initialize(); - } + public async initialize(): Promise { + this.appsEngineUIHost.initialize(); + } } diff --git a/packages/apps-engine/src/client/AppServerCommunicator.ts b/packages/apps-engine/src/client/AppServerCommunicator.ts index fae400bc7ff77..bb4a0538f1d03 100644 --- a/packages/apps-engine/src/client/AppServerCommunicator.ts +++ b/packages/apps-engine/src/client/AppServerCommunicator.ts @@ -1,16 +1,16 @@ import type { IAppInfo } from '../definition/metadata'; export abstract class AppServerCommunicator { - public abstract getEnabledApps(): Promise>; + public abstract getEnabledApps(): Promise>; - public abstract getDisabledApps(): Promise>; + public abstract getDisabledApps(): Promise>; - // Map> - public abstract getLanguageAdditions(): Promise>>; + // Map> + public abstract getLanguageAdditions(): Promise>>; - // Map> - public abstract getSlashCommands(): Promise>>; + // Map> + public abstract getSlashCommands(): Promise>>; - // Map> - public abstract getContextualBarButtons(): Promise>>; + // Map> + public abstract getContextualBarButtons(): Promise>>; } diff --git a/packages/apps-engine/src/client/AppsEngineUIClient.ts b/packages/apps-engine/src/client/AppsEngineUIClient.ts index 620be5e21d011..09e87f3da34e7 100644 --- a/packages/apps-engine/src/client/AppsEngineUIClient.ts +++ b/packages/apps-engine/src/client/AppsEngineUIClient.ts @@ -7,64 +7,64 @@ import { randomString } from './utils'; * Represents the SDK provided to the external component. */ export class AppsEngineUIClient { - private listener: (this: Window, ev: MessageEvent) => any; + private listener: (this: Window, ev: MessageEvent) => any; - private callbacks: Map any>; + private callbacks: Map any>; - constructor() { - this.listener = () => console.log('init'); - this.callbacks = new Map(); - } + constructor() { + this.listener = () => console.log('init'); + this.callbacks = new Map(); + } - /** - * Get the current user's information. - * - * @return the information of the current user. - */ - public getUserInfo(): Promise { - return this.call(AppsEngineUIMethods.GET_USER_INFO); - } + /** + * Get the current user's information. + * + * @return the information of the current user. + */ + public getUserInfo(): Promise { + return this.call(AppsEngineUIMethods.GET_USER_INFO); + } - /** - * Get the current room's information. - * - * @return the information of the current room. - */ - public getRoomInfo(): Promise { - return this.call(AppsEngineUIMethods.GET_ROOM_INFO); - } + /** + * Get the current room's information. + * + * @return the information of the current room. + */ + public getRoomInfo(): Promise { + return this.call(AppsEngineUIMethods.GET_ROOM_INFO); + } - /** - * Initialize the app SDK for communicating with Rocket.Chat - */ - public init(): void { - this.listener = ({ data }) => { - if (!data?.hasOwnProperty(MESSAGE_ID)) { - return; - } + /** + * Initialize the app SDK for communicating with Rocket.Chat + */ + public init(): void { + this.listener = ({ data }) => { + if (!data?.hasOwnProperty(MESSAGE_ID)) { + return; + } - const { - [MESSAGE_ID]: { id, payload }, - } = data; + const { + [MESSAGE_ID]: { id, payload }, + } = data; - if (this.callbacks.has(id)) { - const resolve = this.callbacks.get(id); + if (this.callbacks.has(id)) { + const resolve = this.callbacks.get(id); - if (typeof resolve === 'function') { - resolve(payload); - } - this.callbacks.delete(id); - } - }; - window.addEventListener('message', this.listener); - } + if (typeof resolve === 'function') { + resolve(payload); + } + this.callbacks.delete(id); + } + }; + window.addEventListener('message', this.listener); + } - private call(action: string, payload?: any): Promise { - return new Promise((resolve) => { - const id = randomString(ACTION_ID_LENGTH); + private call(action: string, payload?: any): Promise { + return new Promise((resolve) => { + const id = randomString(ACTION_ID_LENGTH); - window.parent.postMessage({ [MESSAGE_ID]: { action, payload, id } }, '*'); - this.callbacks.set(id, resolve); - }); - } + window.parent.postMessage({ [MESSAGE_ID]: { action, payload, id } }, '*'); + this.callbacks.set(id, resolve); + }); + } } diff --git a/packages/apps-engine/src/client/AppsEngineUIHost.ts b/packages/apps-engine/src/client/AppsEngineUIHost.ts index 02f82f236ed2d..c10067e6624bc 100644 --- a/packages/apps-engine/src/client/AppsEngineUIHost.ts +++ b/packages/apps-engine/src/client/AppsEngineUIHost.ts @@ -8,71 +8,71 @@ type HandleActionData = IExternalComponentUserInfo | IExternalComponentRoomInfo; * Represents the host which handles API calls from external components. */ export abstract class AppsEngineUIHost { - /** - * The message emitter who calling the API. - */ - private responseDestination!: Window; + /** + * The message emitter who calling the API. + */ + private responseDestination!: Window; - constructor() { - this.initialize(); - } + constructor() { + this.initialize(); + } - /** - * initialize the AppClientUIHost by registering window `message` listener - */ - public initialize() { - window.addEventListener('message', async ({ data, source }) => { - if (!data?.hasOwnProperty(MESSAGE_ID)) { - return; - } + /** + * initialize the AppClientUIHost by registering window `message` listener + */ + public initialize() { + window.addEventListener('message', async ({ data, source }) => { + if (!data?.hasOwnProperty(MESSAGE_ID)) { + return; + } - this.responseDestination = source as Window; + this.responseDestination = source as Window; - const { - [MESSAGE_ID]: { action, id }, - } = data; + const { + [MESSAGE_ID]: { action, id }, + } = data; - switch (action) { - case AppsEngineUIMethods.GET_USER_INFO: - this.handleAction(action, id, await this.getClientUserInfo()); - break; - case AppsEngineUIMethods.GET_ROOM_INFO: - this.handleAction(action, id, await this.getClientRoomInfo()); - break; - } - }); - } + switch (action) { + case AppsEngineUIMethods.GET_USER_INFO: + this.handleAction(action, id, await this.getClientUserInfo()); + break; + case AppsEngineUIMethods.GET_ROOM_INFO: + this.handleAction(action, id, await this.getClientRoomInfo()); + break; + } + }); + } - /** - * Get the current user's information. - */ - public abstract getClientUserInfo(): Promise; + /** + * Get the current user's information. + */ + public abstract getClientUserInfo(): Promise; - /** - * Get the opened room's information. - */ - public abstract getClientRoomInfo(): Promise; + /** + * Get the opened room's information. + */ + public abstract getClientRoomInfo(): Promise; - /** - * Handle the action sent from the external component. - * @param action the name of the action - * @param id the unique id of the API call - * @param data The data that will return to the caller - */ - private async handleAction(action: AppsEngineUIMethods, id: string, data: HandleActionData): Promise { - if (this.responseDestination instanceof MessagePort || this.responseDestination instanceof ServiceWorker) { - return; - } + /** + * Handle the action sent from the external component. + * @param action the name of the action + * @param id the unique id of the API call + * @param data The data that will return to the caller + */ + private async handleAction(action: AppsEngineUIMethods, id: string, data: HandleActionData): Promise { + if (this.responseDestination instanceof MessagePort || this.responseDestination instanceof ServiceWorker) { + return; + } - this.responseDestination.postMessage( - { - [MESSAGE_ID]: { - id, - action, - payload: data, - } as IAppsEngineUIResponse, - }, - '*', - ); - } + this.responseDestination.postMessage( + { + [MESSAGE_ID]: { + id, + action, + payload: data, + } as IAppsEngineUIResponse, + }, + '*', + ); + } } diff --git a/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts b/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts index df150f9ce62b6..6eb3fb908e5a1 100644 --- a/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts +++ b/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts @@ -2,6 +2,6 @@ * The actions provided by the AppClientSDK. */ export enum AppsEngineUIMethods { - GET_USER_INFO = 'getUserInfo', - GET_ROOM_INFO = 'getRoomInfo', + GET_USER_INFO = 'getUserInfo', + GET_ROOM_INFO = 'getRoomInfo', } diff --git a/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts b/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts index dff7289226a42..d8690b9b31781 100644 --- a/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts +++ b/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts @@ -4,16 +4,16 @@ import type { IExternalComponentRoomInfo, IExternalComponentUserInfo } from './i * The response to the AppClientSDK's API call. */ export interface IAppsEngineUIResponse { - /** - * The name of the action - */ - action: string; - /** - * The unique id of the API call - */ - id: string; - /** - * The data that will return to the caller - */ - payload: IExternalComponentUserInfo | IExternalComponentRoomInfo; + /** + * The name of the action + */ + action: string; + /** + * The unique id of the API call + */ + id: string; + /** + * The data that will return to the caller + */ + payload: IExternalComponentUserInfo | IExternalComponentRoomInfo; } diff --git a/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts b/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts index 6f08b425c378b..a7743dcae8a47 100644 --- a/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts +++ b/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts @@ -8,9 +8,9 @@ type ClientRoomInfo = Pick; * external component. */ export interface IExternalComponentRoomInfo extends ClientRoomInfo { - /** - * the list that contains all the users belonging - * to this room. - */ - members: Array; + /** + * the list that contains all the users belonging + * to this room. + */ + members: Array; } diff --git a/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts b/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts index 9212f5b398760..4cd9061347750 100644 --- a/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts +++ b/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts @@ -7,8 +7,8 @@ type ClientUserInfo = Pick; * the external component. */ export interface IExternalComponentUserInfo extends ClientUserInfo { - /** - * the avatar URL of the Rocket.Chat user - */ - avatarUrl: string; + /** + * the avatar URL of the Rocket.Chat user + */ + avatarUrl: string; } diff --git a/packages/apps-engine/src/client/utils/index.ts b/packages/apps-engine/src/client/utils/index.ts index f5e851e7d50f9..ff726ee5934f4 100644 --- a/packages/apps-engine/src/client/utils/index.ts +++ b/packages/apps-engine/src/client/utils/index.ts @@ -3,16 +3,16 @@ * @param length the length for the generated random string. */ export function randomString(length: number): string { - const buffer: Array = []; - const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const buffer: Array = []; + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < length; i++) { - buffer.push(chars[getRandomInt(chars.length)]); - } + for (let i = 0; i < length; i++) { + buffer.push(chars[getRandomInt(chars.length)]); + } - return buffer.join(''); + return buffer.join(''); } function getRandomInt(max: number): number { - return Math.floor(Math.random() * Math.floor(max)); + return Math.floor(Math.random() * Math.floor(max)); } diff --git a/packages/apps-engine/src/definition/App.ts b/packages/apps-engine/src/definition/App.ts index dd93ba984b746..12a22f7e0bdac 100644 --- a/packages/apps-engine/src/definition/App.ts +++ b/packages/apps-engine/src/definition/App.ts @@ -1,18 +1,18 @@ import { AppStatus } from './AppStatus'; import type { IApp } from './IApp'; import type { - IAppAccessors, - IAppInstallationContext, - IAppUninstallationContext, - IConfigurationExtend, - IConfigurationModify, - IEnvironmentRead, - IHttp, - ILogger, - IModify, - IPersistence, - IRead, - IAppUpdateContext, + IAppAccessors, + IAppInstallationContext, + IAppUninstallationContext, + IConfigurationExtend, + IConfigurationModify, + IEnvironmentRead, + IHttp, + ILogger, + IModify, + IPersistence, + IRead, + IAppUpdateContext, } from './accessors'; import type { IAppAuthorInfo } from './metadata/IAppAuthorInfo'; import type { IAppInfo } from './metadata/IAppInfo'; @@ -20,221 +20,238 @@ import type { ISetting } from './settings'; import type { ISettingUpdateContext } from './settings/ISettingUpdateContext'; export abstract class App implements IApp { - private status: AppStatus = AppStatus.UNKNOWN; - - /** - * Create a new App, this is called whenever the server starts up and initiates the Apps. - * Note, your implementation of this class should call `super(name, id, version)` so we have it. - * Also, please use the `initialize()` method to do items instead of the constructor as the constructor - * *might* be called more than once but the `initialize()` will only be called once. - */ - public constructor( - private readonly info: IAppInfo, - private readonly logger: ILogger, - private readonly accessors?: IAppAccessors, - ) { - this.logger.debug( - `Constructed the App ${this.info.name} (${this.info.id})`, - `v${this.info.version} which depends on the API v${this.info.requiredApiVersion}!`, - `Created by ${this.info.author.name}`, - ); - - this.setStatus(AppStatus.CONSTRUCTED); - } - - public async getStatus(): Promise { - return this.status; - } - - /** - * Get the name of this App. - * - * @return {string} the name - */ - public getName(): string { - return this.info.name; - } - - /** - * Gets the sluggified name of this App. - * - * @return {string} the name slugged - */ - public getNameSlug(): string { - return this.info.nameSlug; - } - - /** - * Gets the username of this App's app user. - * - * @return {string} the username of the app user - * - * @deprecated This method will be removed in the next major version. - * Please use read.getUserReader().getAppUser() instead. - */ - public getAppUserUsername(): string { - return `${this.info.nameSlug}.bot`; - } - - /** - * Get the ID of this App, please see for how to obtain an ID for your App. - * - * @return {number} the ID - */ - public getID(): string { - return this.info.id; - } - - /** - * Get the version of this App, using http://semver.org/. - * - * @return {string} the version - */ - public getVersion(): string { - return this.info.version; - } - - /** - * Get the description of this App, mostly used to show to the clients/administrators. - * - * @return {string} the description - */ - public getDescription(): string { - return this.info.description; - } - - /** - * Gets the API Version which this App depends on (http://semver.org/). - * This property is used for the dependency injections. - * - * @return {string} the required api version - */ - public getRequiredApiVersion(): string { - return this.info.requiredApiVersion; - } - - /** - * Gets the information regarding the author/maintainer of this App. - * - * @return author information - */ - public getAuthorInfo(): IAppAuthorInfo { - return this.info.author; - } - - /** - * Gets the entirity of the App's information. - * - * @return App information - */ - public getInfo(): IAppInfo { - return this.info; - } - - /** - * Gets the ILogger instance for this App. - * - * @return the logger instance - */ - public getLogger(): ILogger { - return this.logger; - } - - public getAccessors(): IAppAccessors { - return this.accessors; - } - - /** - * Method which will be called when the App is initialized. This is the recommended place - * to add settings and slash commands. If an error is thrown, all commands will be unregistered. - */ - public async initialize(configurationExtend: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { - await this.extendConfiguration(configurationExtend, environmentRead); - } - - /** - * Method which is called when this App is enabled and can be called several - * times during this instance's life time. Once after the `initialize()` is called, - * pending it doesn't throw an error, and then anytime the App is enabled by the user. - * If this method, `onEnable()`, returns false, then this App will not - * actually be enabled (ex: a setting isn't configured). - * - * @return whether the App should be enabled or not - */ - public async onEnable(environment: IEnvironmentRead, configurationModify: IConfigurationModify): Promise { - return true; - } - - /** - * Method which is called when this App is disabled and it can be called several times. - * If this App was enabled and then the user disabled it, this method will be called. - */ - public async onDisable(configurationModify: IConfigurationModify): Promise {} - - /** - * Method which is called when the App is uninstalled and it is called one single time. - * - * This method will NOT be called when an App is getting disabled manually, ONLY when - * it's being uninstalled from Rocket.Chat. - */ - public async onUninstall(context: IAppUninstallationContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} - - /** - * Method which is called when the App is installed and it is called one single time. - * - * This method is NOT called when the App is updated. - */ - public async onInstall(context: IAppInstallationContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} - - /** - * Method which is called when the App is updated and it is called one single time. - * - * This method is NOT called when the App is installed. - */ - public async onUpdate(context: IAppUpdateContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} - - /** - * Method which is called whenever a setting which belongs to this App has been updated - * by an external system and not this App itself. The setting passed is the newly updated one. - * - * @param setting the setting which was updated - * @param configurationModify the accessor to modifiy the system - * @param reader the reader accessor - * @param http an accessor to the outside world - */ - public async onSettingUpdated(setting: ISetting, configurationModify: IConfigurationModify, read: IRead, http: IHttp): Promise {} - - /** - * Method which is called before a setting which belongs to this App is going to be updated - * by an external system and not this App itself. The setting passed is the newly updated one. - * - * @param setting the setting which is going to be updated - * @param configurationModify the accessor to modifiy the system - * @param reader the reader accessor - * @param http an accessor to the outside world - */ - public async onPreSettingUpdate(context: ISettingUpdateContext, configurationModify: IConfigurationModify, read: IRead, http: IHttp): Promise { - return context.newSetting; - } - - /** - * Method will be called during initialization. It allows for adding custom configuration options and defaults - * @param configuration - */ - protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise {} - - /** - * Sets the status this App is now at, use only when 100% true (it's protected for a reason). - * - * @param status the new status of this App - */ - protected async setStatus(status: AppStatus): Promise { - this.logger.debug(`The status is now: ${status}`); - this.status = status; - } - - // Avoid leaking references if object is serialized (e.g. to be sent over IPC) - public toJSON(): Record { - return this.info; - } + private status: AppStatus = AppStatus.UNKNOWN; + + /** + * Create a new App, this is called whenever the server starts up and initiates the Apps. + * Note, your implementation of this class should call `super(name, id, version)` so we have it. + * Also, please use the `initialize()` method to do items instead of the constructor as the constructor + * *might* be called more than once but the `initialize()` will only be called once. + */ + public constructor( + private readonly info: IAppInfo, + private readonly logger: ILogger, + private readonly accessors?: IAppAccessors, + ) { + this.logger.debug( + `Constructed the App ${this.info.name} (${this.info.id})`, + `v${this.info.version} which depends on the API v${this.info.requiredApiVersion}!`, + `Created by ${this.info.author.name}`, + ); + + this.setStatus(AppStatus.CONSTRUCTED); + } + + public async getStatus(): Promise { + return this.status; + } + + /** + * Get the name of this App. + * + * @return {string} the name + */ + public getName(): string { + return this.info.name; + } + + /** + * Gets the sluggified name of this App. + * + * @return {string} the name slugged + */ + public getNameSlug(): string { + return this.info.nameSlug; + } + + /** + * Gets the username of this App's app user. + * + * @return {string} the username of the app user + * + * @deprecated This method will be removed in the next major version. + * Please use read.getUserReader().getAppUser() instead. + */ + public getAppUserUsername(): string { + return `${this.info.nameSlug}.bot`; + } + + /** + * Get the ID of this App, please see for how to obtain an ID for your App. + * + * @return {number} the ID + */ + public getID(): string { + return this.info.id; + } + + /** + * Get the version of this App, using http://semver.org/. + * + * @return {string} the version + */ + public getVersion(): string { + return this.info.version; + } + + /** + * Get the description of this App, mostly used to show to the clients/administrators. + * + * @return {string} the description + */ + public getDescription(): string { + return this.info.description; + } + + /** + * Gets the API Version which this App depends on (http://semver.org/). + * This property is used for the dependency injections. + * + * @return {string} the required api version + */ + public getRequiredApiVersion(): string { + return this.info.requiredApiVersion; + } + + /** + * Gets the information regarding the author/maintainer of this App. + * + * @return author information + */ + public getAuthorInfo(): IAppAuthorInfo { + return this.info.author; + } + + /** + * Gets the entirity of the App's information. + * + * @return App information + */ + public getInfo(): IAppInfo { + return this.info; + } + + /** + * Gets the ILogger instance for this App. + * + * @return the logger instance + */ + public getLogger(): ILogger { + return this.logger; + } + + public getAccessors(): IAppAccessors { + return this.accessors; + } + + /** + * Method which will be called when the App is initialized. This is the recommended place + * to add settings and slash commands. If an error is thrown, all commands will be unregistered. + */ + public async initialize(configurationExtend: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { + await this.extendConfiguration(configurationExtend, environmentRead); + } + + /** + * Method which is called when this App is enabled and can be called several + * times during this instance's life time. Once after the `initialize()` is called, + * pending it doesn't throw an error, and then anytime the App is enabled by the user. + * If this method, `onEnable()`, returns false, then this App will not + * actually be enabled (ex: a setting isn't configured). + * + * @return whether the App should be enabled or not + */ + public async onEnable(environment: IEnvironmentRead, configurationModify: IConfigurationModify): Promise { + return true; + } + + /** + * Method which is called when this App is disabled and it can be called several times. + * If this App was enabled and then the user disabled it, this method will be called. + */ + public async onDisable(configurationModify: IConfigurationModify): Promise {} + + /** + * Method which is called when the App is uninstalled and it is called one single time. + * + * This method will NOT be called when an App is getting disabled manually, ONLY when + * it's being uninstalled from Rocket.Chat. + */ + public async onUninstall( + context: IAppUninstallationContext, + read: IRead, + http: IHttp, + persistence: IPersistence, + modify: IModify, + ): Promise {} + + /** + * Method which is called when the App is installed and it is called one single time. + * + * This method is NOT called when the App is updated. + */ + public async onInstall( + context: IAppInstallationContext, + read: IRead, + http: IHttp, + persistence: IPersistence, + modify: IModify, + ): Promise {} + + /** + * Method which is called when the App is updated and it is called one single time. + * + * This method is NOT called when the App is installed. + */ + public async onUpdate(context: IAppUpdateContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} + + /** + * Method which is called whenever a setting which belongs to this App has been updated + * by an external system and not this App itself. The setting passed is the newly updated one. + * + * @param setting the setting which was updated + * @param configurationModify the accessor to modifiy the system + * @param reader the reader accessor + * @param http an accessor to the outside world + */ + public async onSettingUpdated(setting: ISetting, configurationModify: IConfigurationModify, read: IRead, http: IHttp): Promise {} + + /** + * Method which is called before a setting which belongs to this App is going to be updated + * by an external system and not this App itself. The setting passed is the newly updated one. + * + * @param setting the setting which is going to be updated + * @param configurationModify the accessor to modifiy the system + * @param reader the reader accessor + * @param http an accessor to the outside world + */ + public async onPreSettingUpdate( + context: ISettingUpdateContext, + configurationModify: IConfigurationModify, + read: IRead, + http: IHttp, + ): Promise { + return context.newSetting; + } + + /** + * Method will be called during initialization. It allows for adding custom configuration options and defaults + * @param configuration + */ + protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise {} + + /** + * Sets the status this App is now at, use only when 100% true (it's protected for a reason). + * + * @param status the new status of this App + */ + protected async setStatus(status: AppStatus): Promise { + this.logger.debug(`The status is now: ${status}`); + this.status = status; + } + + // Avoid leaking references if object is serialized (e.g. to be sent over IPC) + public toJSON(): Record { + return this.info; + } } diff --git a/packages/apps-engine/src/definition/AppStatus.ts b/packages/apps-engine/src/definition/AppStatus.ts index 31638a8d0f1cd..18b40acf70010 100644 --- a/packages/apps-engine/src/definition/AppStatus.ts +++ b/packages/apps-engine/src/definition/AppStatus.ts @@ -1,65 +1,65 @@ export enum AppStatus { - /** The status is known, aka not been constructed the proper way. */ - UNKNOWN = 'unknown', - /** The App has been constructed but that's it. */ - CONSTRUCTED = 'constructed', - /** The App's `initialize()` was called and returned true. */ - INITIALIZED = 'initialized', - /** The App's `onEnable()` was called, returned true, and this was done automatically (system start up). */ - AUTO_ENABLED = 'auto_enabled', - /** The App's `onEnable()` was called, returned true, and this was done by the user such as installing a new one. */ - MANUALLY_ENABLED = 'manually_enabled', - /** - * The App was disabled due to an error while attempting to compile it. - * An attempt to enable it again will fail, as it needs to be updated. - */ - COMPILER_ERROR_DISABLED = 'compiler_error_disabled', - /** - * The App was disable due to its license being invalid - */ - INVALID_LICENSE_DISABLED = 'invalid_license_disabled', - /** - * The app was disabled due to an invalid installation or validation in its signature. - */ - INVALID_INSTALLATION_DISABLED = 'invalid_installation_disabled', - /** The App was disabled due to an unrecoverable error being thrown. */ - ERROR_DISABLED = 'error_disabled', - /** The App was manually disabled by a user. */ - MANUALLY_DISABLED = 'manually_disabled', - INVALID_SETTINGS_DISABLED = 'invalid_settings_disabled', - /** The App was disabled due to other circumstances. */ - DISABLED = 'disabled', + /** The status is known, aka not been constructed the proper way. */ + UNKNOWN = 'unknown', + /** The App has been constructed but that's it. */ + CONSTRUCTED = 'constructed', + /** The App's `initialize()` was called and returned true. */ + INITIALIZED = 'initialized', + /** The App's `onEnable()` was called, returned true, and this was done automatically (system start up). */ + AUTO_ENABLED = 'auto_enabled', + /** The App's `onEnable()` was called, returned true, and this was done by the user such as installing a new one. */ + MANUALLY_ENABLED = 'manually_enabled', + /** + * The App was disabled due to an error while attempting to compile it. + * An attempt to enable it again will fail, as it needs to be updated. + */ + COMPILER_ERROR_DISABLED = 'compiler_error_disabled', + /** + * The App was disable due to its license being invalid + */ + INVALID_LICENSE_DISABLED = 'invalid_license_disabled', + /** + * The app was disabled due to an invalid installation or validation in its signature. + */ + INVALID_INSTALLATION_DISABLED = 'invalid_installation_disabled', + /** The App was disabled due to an unrecoverable error being thrown. */ + ERROR_DISABLED = 'error_disabled', + /** The App was manually disabled by a user. */ + MANUALLY_DISABLED = 'manually_disabled', + INVALID_SETTINGS_DISABLED = 'invalid_settings_disabled', + /** The App was disabled due to other circumstances. */ + DISABLED = 'disabled', } export class AppStatusUtilsDef { - public isEnabled(status: AppStatus): boolean { - switch (status) { - case AppStatus.AUTO_ENABLED: - case AppStatus.MANUALLY_ENABLED: - return true; - default: - return false; - } - } + public isEnabled(status: AppStatus): boolean { + switch (status) { + case AppStatus.AUTO_ENABLED: + case AppStatus.MANUALLY_ENABLED: + return true; + default: + return false; + } + } - public isDisabled(status: AppStatus): boolean { - switch (status) { - case AppStatus.COMPILER_ERROR_DISABLED: - case AppStatus.ERROR_DISABLED: - case AppStatus.MANUALLY_DISABLED: - case AppStatus.INVALID_SETTINGS_DISABLED: - case AppStatus.INVALID_LICENSE_DISABLED: - case AppStatus.INVALID_INSTALLATION_DISABLED: - case AppStatus.DISABLED: - return true; - default: - return false; - } - } + public isDisabled(status: AppStatus): boolean { + switch (status) { + case AppStatus.COMPILER_ERROR_DISABLED: + case AppStatus.ERROR_DISABLED: + case AppStatus.MANUALLY_DISABLED: + case AppStatus.INVALID_SETTINGS_DISABLED: + case AppStatus.INVALID_LICENSE_DISABLED: + case AppStatus.INVALID_INSTALLATION_DISABLED: + case AppStatus.DISABLED: + return true; + default: + return false; + } + } - public isError(status: AppStatus): boolean { - return [AppStatus.ERROR_DISABLED, AppStatus.COMPILER_ERROR_DISABLED].includes(status); - } + public isError(status: AppStatus): boolean { + return [AppStatus.ERROR_DISABLED, AppStatus.COMPILER_ERROR_DISABLED].includes(status); + } } export const AppStatusUtils = new AppStatusUtilsDef(); diff --git a/packages/apps-engine/src/definition/IApp.ts b/packages/apps-engine/src/definition/IApp.ts index 53faff9647f4f..2de0e2e966f74 100644 --- a/packages/apps-engine/src/definition/IApp.ts +++ b/packages/apps-engine/src/definition/IApp.ts @@ -5,86 +5,86 @@ import type { IAppAuthorInfo } from './metadata/IAppAuthorInfo'; import type { IAppInfo } from './metadata/IAppInfo'; export interface IApp { - /** - * Gets the status of this App. - * - * @return {AppStatus} the status/state of the App - */ - getStatus(): Promise; + /** + * Gets the status of this App. + * + * @return {AppStatus} the status/state of the App + */ + getStatus(): Promise; - /** - * Get the name of this App. - * - * @return {string} the name - */ - getName(): string; + /** + * Get the name of this App. + * + * @return {string} the name + */ + getName(): string; - /** - * Gets the sluggified name of this App. - * - * @return {string} the name slugged - */ - getNameSlug(): string; + /** + * Gets the sluggified name of this App. + * + * @return {string} the name slugged + */ + getNameSlug(): string; - /** - * Gets the username of this App's app user. - * - * @return {string} the username of the app user - * - * @deprecated This method will be removed in the next major version. - * Please use read.getAppUser instead. - */ - getAppUserUsername(): string; + /** + * Gets the username of this App's app user. + * + * @return {string} the username of the app user + * + * @deprecated This method will be removed in the next major version. + * Please use read.getAppUser instead. + */ + getAppUserUsername(): string; - /** - * Get the ID of this App, please see for how to obtain an ID for your App. - * - * @return {number} the ID - */ - getID(): string; + /** + * Get the ID of this App, please see for how to obtain an ID for your App. + * + * @return {number} the ID + */ + getID(): string; - /** - * Get the version of this App, using http://semver.org/. - * - * @return {string} the version - */ - getVersion(): string; + /** + * Get the version of this App, using http://semver.org/. + * + * @return {string} the version + */ + getVersion(): string; - /** - * Get the description of this App, mostly used to show to the clients/administrators. - * - * @return {string} the description - */ - getDescription(): string; + /** + * Get the description of this App, mostly used to show to the clients/administrators. + * + * @return {string} the description + */ + getDescription(): string; - /** - * Gets the API Version which this App depends on (http://semver.org/). - * This property is used for the dependency injections. - * - * @return {string} the required api version - */ - getRequiredApiVersion(): string; + /** + * Gets the API Version which this App depends on (http://semver.org/). + * This property is used for the dependency injections. + * + * @return {string} the required api version + */ + getRequiredApiVersion(): string; - /** - * Gets the information regarding the author/maintainer of this App. - * - * @return author information - */ - getAuthorInfo(): IAppAuthorInfo; + /** + * Gets the information regarding the author/maintainer of this App. + * + * @return author information + */ + getAuthorInfo(): IAppAuthorInfo; - /** - * Gets the entirity of the App's information. - * - * @return App information - */ - getInfo(): IAppInfo; + /** + * Gets the entirity of the App's information. + * + * @return App information + */ + getInfo(): IAppInfo; - /** - * Gets the ILogger instance for this App. - * - * @return the logger instance - */ - getLogger(): ILogger; + /** + * Gets the ILogger instance for this App. + * + * @return the logger instance + */ + getLogger(): ILogger; - getAccessors(): IAppAccessors; + getAccessors(): IAppAccessors; } diff --git a/packages/apps-engine/src/definition/accessors/IApiExtend.ts b/packages/apps-engine/src/definition/accessors/IApiExtend.ts index ab3210105e9c8..8e8bcec76ffd2 100644 --- a/packages/apps-engine/src/definition/accessors/IApiExtend.ts +++ b/packages/apps-engine/src/definition/accessors/IApiExtend.ts @@ -6,11 +6,11 @@ import type { IApi } from '../api'; */ export interface IApiExtend { - /** - * Adds an api which can be called by external services lateron. - * Should an api already exists an error will be thrown. - * - * @param api the command information - */ - provideApi(api: IApi): Promise; + /** + * Adds an api which can be called by external services lateron. + * Should an api already exists an error will be thrown. + * + * @param api the command information + */ + provideApi(api: IApi): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IAppAccessors.ts b/packages/apps-engine/src/definition/accessors/IAppAccessors.ts index c2ea3bfcacea5..297c11d82f86f 100644 --- a/packages/apps-engine/src/definition/accessors/IAppAccessors.ts +++ b/packages/apps-engine/src/definition/accessors/IAppAccessors.ts @@ -3,9 +3,9 @@ import type { IApiEndpointMetadata } from '../api'; import type { IEnvironmentWrite } from './IEnvironmentWrite'; export interface IAppAccessors { - readonly environmentReader: IEnvironmentRead; - readonly environmentWriter: IEnvironmentWrite; - readonly reader: IRead; - readonly http: IHttp; - readonly providedApiEndpoints: Array; + readonly environmentReader: IEnvironmentRead; + readonly environmentWriter: IEnvironmentWrite; + readonly reader: IRead; + readonly http: IHttp; + readonly providedApiEndpoints: Array; } diff --git a/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts b/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts index 0ca1c08ba0dc7..799d105539b53 100644 --- a/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts +++ b/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts @@ -1,5 +1,5 @@ import type { IUser } from '../users'; export interface IAppInstallationContext { - user: IUser; + user: IUser; } diff --git a/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts b/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts index 96ddbfa03298b..037a0ed080471 100644 --- a/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts +++ b/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts @@ -1,5 +1,5 @@ import type { IUser } from '../users'; export interface IAppUninstallationContext { - user: IUser; + user: IUser; } diff --git a/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts b/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts index d0bcf7ea280b1..8eb7bdfa7acba 100644 --- a/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts +++ b/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts @@ -1,6 +1,6 @@ import type { IUser } from '../users'; export interface IAppUpdateContext { - user?: IUser; - oldAppVersion: string; + user?: IUser; + oldAppVersion: string; } diff --git a/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts b/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts index c78749fae59be..798abbda71dc2 100644 --- a/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts +++ b/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts @@ -12,13 +12,13 @@ import type { IWorkspaceToken } from '../cloud/IWorkspaceToken'; * usually received as a parameter wherever it's available. */ export interface ICloudWorkspaceRead { - /** - * Returns an access token that can be used to access - * Cloud Services on the workspace's behalf. - * - * @param scope The scope that the token should be authorized with - * - * @RequiresPermission cloud.workspace-token; scopes: Array - */ - getWorkspaceToken(scope: string): Promise; + /** + * Returns an access token that can be used to access + * Cloud Services on the workspace's behalf. + * + * @param scope The scope that the token should be authorized with + * + * @RequiresPermission cloud.workspace-token; scopes: Array + */ + getWorkspaceToken(scope: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts b/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts index a58f127a04213..c6390bdee2066 100644 --- a/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts +++ b/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts @@ -12,25 +12,25 @@ import type { IVideoConfProvidersExtend } from './IVideoConfProvidersExtend'; * of your App. It is provided during initialization of your App. */ export interface IConfigurationExtend { - /** Accessor for customing the handling of IHttp requests and responses your App causes. */ - readonly http: IHttpExtend; + /** Accessor for customing the handling of IHttp requests and responses your App causes. */ + readonly http: IHttpExtend; - /** Accessor for declaring the settings your App provides. */ - readonly settings: ISettingsExtend; + /** Accessor for declaring the settings your App provides. */ + readonly settings: ISettingsExtend; - /** Accessor for declaring the commands which your App provides. */ - readonly slashCommands: ISlashCommandsExtend; + /** Accessor for declaring the commands which your App provides. */ + readonly slashCommands: ISlashCommandsExtend; - /** Accessor for declaring api endpoints. */ - readonly api: IApiExtend; + /** Accessor for declaring api endpoints. */ + readonly api: IApiExtend; - readonly externalComponents: IExternalComponentsExtend; + readonly externalComponents: IExternalComponentsExtend; - /** Accessor for declaring tasks that can be scheduled (like cron) */ - readonly scheduler: ISchedulerExtend; - /** Accessor for registering different elements in the host UI */ - readonly ui: IUIExtend; + /** Accessor for declaring tasks that can be scheduled (like cron) */ + readonly scheduler: ISchedulerExtend; + /** Accessor for registering different elements in the host UI */ + readonly ui: IUIExtend; - /** Accessor for declaring the videoconf providers which your App provides. */ - readonly videoConfProviders: IVideoConfProvidersExtend; + /** Accessor for declaring the videoconf providers which your App provides. */ + readonly videoConfProviders: IVideoConfProvidersExtend; } diff --git a/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts b/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts index d0f818e2e0289..e3c77abbaf2ec 100644 --- a/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts +++ b/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts @@ -7,12 +7,12 @@ import type { ISlashCommandsModify } from './ISlashCommandsModify'; * of Rocket.Chat. It is provided during "onEnable" of your App. */ export interface IConfigurationModify { - /** Accessor for modifying the settings inside of Rocket.Chat. */ - readonly serverSettings: IServerSettingsModify; + /** Accessor for modifying the settings inside of Rocket.Chat. */ + readonly serverSettings: IServerSettingsModify; - /** Accessor for modifying the slash commands inside of Rocket.Chat. */ - readonly slashCommands: ISlashCommandsModify; + /** Accessor for modifying the slash commands inside of Rocket.Chat. */ + readonly slashCommands: ISlashCommandsModify; - /** Accessor for modifying schedulers */ - readonly scheduler: ISchedulerModify; + /** Accessor for modifying schedulers */ + readonly scheduler: ISchedulerModify; } diff --git a/packages/apps-engine/src/definition/accessors/IContactCreator.ts b/packages/apps-engine/src/definition/accessors/IContactCreator.ts index d2d13c4d6bf13..1c65335972b28 100644 --- a/packages/apps-engine/src/definition/accessors/IContactCreator.ts +++ b/packages/apps-engine/src/definition/accessors/IContactCreator.ts @@ -1,7 +1,13 @@ import type { ILivechatContact } from '../livechat'; export interface IContactCreator { - verifyContact(verifyContactChannelParams: { contactId: string; field: string; value: string; visitorId: string; roomId: string }): Promise; + verifyContact(verifyContactChannelParams: { + contactId: string; + field: string; + value: string; + visitorId: string; + roomId: string; + }): Promise; - addContactEmail(contactId: ILivechatContact['_id'], email: string): Promise; + addContactEmail(contactId: ILivechatContact['_id'], email: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IContactRead.ts b/packages/apps-engine/src/definition/accessors/IContactRead.ts index efc0c2c49d663..695782ab787aa 100644 --- a/packages/apps-engine/src/definition/accessors/IContactRead.ts +++ b/packages/apps-engine/src/definition/accessors/IContactRead.ts @@ -1,5 +1,5 @@ import type { ILivechatContact } from '../livechat'; export interface IContactRead { - getById(contactId: ILivechatContact['_id']): Promise; + getById(contactId: ILivechatContact['_id']): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts b/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts index 51dc0c2c4f92c..b97c549b83c98 100644 --- a/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts +++ b/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts @@ -9,17 +9,17 @@ import type { IRoom } from '../rooms'; * be able to successfully save the room object. */ export interface IDiscussionBuilder extends IRoomBuilder { - kind: RocketChatAssociationModel.DISCUSSION; + kind: RocketChatAssociationModel.DISCUSSION; - setParentRoom(parentRoom: IRoom): IDiscussionBuilder; + setParentRoom(parentRoom: IRoom): IDiscussionBuilder; - getParentRoom(): IRoom; + getParentRoom(): IRoom; - setParentMessage(parentMessage: IMessage): IDiscussionBuilder; + setParentMessage(parentMessage: IMessage): IDiscussionBuilder; - getParentMessage(): IMessage; + getParentMessage(): IMessage; - setReply(reply: string): IDiscussionBuilder; + setReply(reply: string): IDiscussionBuilder; - getReply(): string; + getReply(): string; } diff --git a/packages/apps-engine/src/definition/accessors/IEmailCreator.ts b/packages/apps-engine/src/definition/accessors/IEmailCreator.ts index d5d051bc2dff6..877f461531037 100644 --- a/packages/apps-engine/src/definition/accessors/IEmailCreator.ts +++ b/packages/apps-engine/src/definition/accessors/IEmailCreator.ts @@ -1,10 +1,10 @@ import type { IEmail } from '../email'; export interface IEmailCreator { - /** - * Sends an email through Rocket.Chat - * - * @param email the email data - */ - send(email: IEmail): Promise; + /** + * Sends an email through Rocket.Chat + * + * @param email the email data + */ + send(email: IEmail): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts b/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts index 81b50bee77c48..cac315791744c 100644 --- a/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts +++ b/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts @@ -8,20 +8,20 @@ import type { ISettingRead } from './ISettingRead'; * variables all of which are not user created. */ export interface IEnvironmentRead { - /** Gets an instance of the App's settings reader. */ - getSettings(): ISettingRead; + /** Gets an instance of the App's settings reader. */ + getSettings(): ISettingRead; - /** - * Gets an instance of the Server's Settings reader. - * Please note: Due to security concerns, only a subset of settings - * are accessible. - */ - getServerSettings(): IServerSettingRead; + /** + * Gets an instance of the Server's Settings reader. + * Please note: Due to security concerns, only a subset of settings + * are accessible. + */ + getServerSettings(): IServerSettingRead; - /** - * Gets an instance of the Environmental Variables reader. - * Please note: Due to security concerns, only a subset of - * them are readable. - */ - getEnvironmentVariables(): IEnvironmentalVariableRead; + /** + * Gets an instance of the Environmental Variables reader. + * Please note: Due to security concerns, only a subset of + * them are readable. + */ + getEnvironmentVariables(): IEnvironmentalVariableRead; } diff --git a/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts b/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts index ab1869ab67cb2..43f431507dd13 100644 --- a/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts +++ b/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts @@ -5,6 +5,6 @@ import type { ISettingUpdater } from './ISettingUpdater'; * Allows write-access to the App's settings, */ export interface IEnvironmentWrite { - getSettings(): ISettingUpdater; - getServerSettings(): IServerSettingUpdater; + getSettings(): ISettingUpdater; + getServerSettings(): IServerSettingUpdater; } diff --git a/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts b/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts index 3bb77b033e83a..8f4f1b18312da 100644 --- a/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts +++ b/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts @@ -1,11 +1,11 @@ /** A reader for reading the Environmental Variables. */ export interface IEnvironmentalVariableRead { - /** Gets the value for a variable. */ - getValueByName(envVarName: string): Promise; + /** Gets the value for a variable. */ + getValueByName(envVarName: string): Promise; - /** Checks to see if Apps can access the given variable name. */ - isReadable(envVarName: string): Promise; + /** Checks to see if Apps can access the given variable name. */ + isReadable(envVarName: string): Promise; - /** Checks to see if any value is set for the given variable name. */ - isSet(envVarName: string): Promise; + /** Checks to see if any value is set for the given variable name. */ + isSet(envVarName: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts b/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts index 6a3dc781056fa..3f55dd656aeef 100644 --- a/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts +++ b/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts @@ -5,13 +5,13 @@ import type { IExternalComponent } from '../externalComponent'; * components. This is provided during the initialization of your App. */ export interface IExternalComponentsExtend { - /** - * Register an external component to the system. - * If you call this method twice and the component - * has the same name as before, the first one will be - * overwritten as the names provided **must** be unique. - * - * @param externalComponent the external component to be registered - */ - register(externalComponent: IExternalComponent): Promise; + /** + * Register an external component to the system. + * If you call this method twice and the component + * has the same name as before, the first one will be + * overwritten as the names provided **must** be unique. + * + * @param externalComponent the external component to be registered + */ + register(externalComponent: IExternalComponent): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IHttp.ts b/packages/apps-engine/src/definition/accessors/IHttp.ts index 8c5eeb9a4d555..d9a72e19558b0 100644 --- a/packages/apps-engine/src/definition/accessors/IHttp.ts +++ b/packages/apps-engine/src/definition/accessors/IHttp.ts @@ -6,197 +6,197 @@ import type { IRead } from './IRead'; * Based off of: https://github.com/meteor-typings/meteor/blob/master/1.4/main.d.ts#L869 */ export interface IHttp { - get(url: string, options?: IHttpRequest): Promise; + get(url: string, options?: IHttpRequest): Promise; - post(url: string, options?: IHttpRequest): Promise; + post(url: string, options?: IHttpRequest): Promise; - put(url: string, options?: IHttpRequest): Promise; + put(url: string, options?: IHttpRequest): Promise; - del(url: string, options?: IHttpRequest): Promise; + del(url: string, options?: IHttpRequest): Promise; - patch(url: string, options?: IHttpRequest): Promise; + patch(url: string, options?: IHttpRequest): Promise; } export enum RequestMethod { - GET = 'get', - POST = 'post', - PUT = 'put', - DELETE = 'delete', - HEAD = 'head', - OPTIONS = 'options', - PATCH = 'patch', + GET = 'get', + POST = 'post', + PUT = 'put', + DELETE = 'delete', + HEAD = 'head', + OPTIONS = 'options', + PATCH = 'patch', } export interface IHttpRequest { - content?: string; - data?: any; - query?: string; - params?: { - [key: string]: string; - }; - auth?: string; - headers?: { - [key: string]: string; - }; - timeout?: number; - /** - * The encoding to be used on response data. - * - * If null, the body is returned as a Buffer. Anything else (including the default value of undefined) - * will be passed as the encoding parameter to toString() (meaning this is effectively 'utf8' by default). - * (Note: if you expect binary data, you should set encoding: null.) - */ - encoding?: string | null; - /** - * if `true`, requires SSL certificates be valid. - * - * Defaul: `true`; - */ - strictSSL?: boolean; - /** - * If `true`, the server certificate is verified against the list of supplied CAs. - * - * Default: `true`. - * - * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback - */ - rejectUnauthorized?: boolean; + content?: string; + data?: any; + query?: string; + params?: { + [key: string]: string; + }; + auth?: string; + headers?: { + [key: string]: string; + }; + timeout?: number; + /** + * The encoding to be used on response data. + * + * If null, the body is returned as a Buffer. Anything else (including the default value of undefined) + * will be passed as the encoding parameter to toString() (meaning this is effectively 'utf8' by default). + * (Note: if you expect binary data, you should set encoding: null.) + */ + encoding?: string | null; + /** + * if `true`, requires SSL certificates be valid. + * + * Defaul: `true`; + */ + strictSSL?: boolean; + /** + * If `true`, the server certificate is verified against the list of supplied CAs. + * + * Default: `true`. + * + * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback + */ + rejectUnauthorized?: boolean; } export interface IHttpResponse { - url: string; - method: RequestMethod; - statusCode: number; - headers?: { - [key: string]: string; - }; - content?: string; - data?: any; + url: string; + method: RequestMethod; + statusCode: number; + headers?: { + [key: string]: string; + }; + content?: string; + data?: any; } export interface IHttpExtend { - /** - * A method for providing a single header which is added to every request. - * - * @param key the name of the header - * @param value the header's content - */ - provideDefaultHeader(key: string, value: string): void; - - /** - * A method for providing more than one header which are added to every request. - * - * @param headers an object with strings as the keys (header name) and strings as values (header content) - */ - provideDefaultHeaders(headers: { [key: string]: string }): void; - - /** - * A method for providing a single query parameter which is added to every request. - * - * @param key the name of the query parameter - * @param value the query parameter's content - */ - provideDefaultParam(key: string, value: string): void; - - /** - * A method for providing more than one query parameters which are added to every request. - * - * @param headers an object with strings as the keys (parameter name) and strings as values (parameter content) - */ - provideDefaultParams(params: { [key: string]: string }): void; - - /** - * Method for providing a function which is called before every request is called out to the final destination. - * This can be called more than once which means there can be more than one handler. The order provided is the order called. - * Note: if this handler throws an error when it is executed then the request will be aborted. - * - * @param handler the instance of the IHttpPreRequestHandler - */ - providePreRequestHandler(handler: IHttpPreRequestHandler): void; - - /** - * Method for providing a function which is called after every response is got from the url and before the result is returned. - * This can be called more than once which means there can be more than one handler. The order provided is the order called. - * Note: if this handler throws an error when it is executed then the respone will not be returned - * - * @param handler the instance of the IHttpPreResponseHandler - */ - providePreResponseHandler(handler: IHttpPreResponseHandler): void; - - /** - * A method for getting all of the default headers provided, the value is a readonly and any modifications done will be ignored. - * Please use the provider methods for adding them. - */ - getDefaultHeaders(): Map; - - /** - * A method for getting all of the default parameters provided, the value is a readonly and any modifications done will be ignored. - * Please use the provider methods for adding them. - */ - getDefaultParams(): Map; - - /** - * A method for getting all of the pre-request handlers provided, the value is a readonly and any modifications done will be ignored. - * Please use the provider methods for adding them. - */ - getPreRequestHandlers(): Array; - - /** - * A method for getting all of the pre-response handlers provided, the value is a readonly and any modifications done will be ignored. - * Please use the provider methods for adding them. - */ - getPreResponseHandlers(): Array; + /** + * A method for providing a single header which is added to every request. + * + * @param key the name of the header + * @param value the header's content + */ + provideDefaultHeader(key: string, value: string): void; + + /** + * A method for providing more than one header which are added to every request. + * + * @param headers an object with strings as the keys (header name) and strings as values (header content) + */ + provideDefaultHeaders(headers: { [key: string]: string }): void; + + /** + * A method for providing a single query parameter which is added to every request. + * + * @param key the name of the query parameter + * @param value the query parameter's content + */ + provideDefaultParam(key: string, value: string): void; + + /** + * A method for providing more than one query parameters which are added to every request. + * + * @param headers an object with strings as the keys (parameter name) and strings as values (parameter content) + */ + provideDefaultParams(params: { [key: string]: string }): void; + + /** + * Method for providing a function which is called before every request is called out to the final destination. + * This can be called more than once which means there can be more than one handler. The order provided is the order called. + * Note: if this handler throws an error when it is executed then the request will be aborted. + * + * @param handler the instance of the IHttpPreRequestHandler + */ + providePreRequestHandler(handler: IHttpPreRequestHandler): void; + + /** + * Method for providing a function which is called after every response is got from the url and before the result is returned. + * This can be called more than once which means there can be more than one handler. The order provided is the order called. + * Note: if this handler throws an error when it is executed then the respone will not be returned + * + * @param handler the instance of the IHttpPreResponseHandler + */ + providePreResponseHandler(handler: IHttpPreResponseHandler): void; + + /** + * A method for getting all of the default headers provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getDefaultHeaders(): Map; + + /** + * A method for getting all of the default parameters provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getDefaultParams(): Map; + + /** + * A method for getting all of the pre-request handlers provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getPreRequestHandlers(): Array; + + /** + * A method for getting all of the pre-response handlers provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getPreResponseHandlers(): Array; } export interface IHttpPreRequestHandler { - executePreHttpRequest(url: string, request: IHttpRequest, read: IRead, persistence: IPersistence): Promise; + executePreHttpRequest(url: string, request: IHttpRequest, read: IRead, persistence: IPersistence): Promise; } export interface IHttpPreResponseHandler { - executePreHttpResponse(response: IHttpResponse, read: IRead, persistence: IPersistence): Promise; + executePreHttpResponse(response: IHttpResponse, read: IRead, persistence: IPersistence): Promise; } export enum HttpStatusCode { - CONTINUE = 100, - SWITCHING_PROTOCOLS = 101, - OK = 200, - CREATED = 201, - ACCEPTED = 202, - NON_AUTHORITATIVE_INFORMATION = 203, - NO_CONTENT = 204, - RESET_CONTENT = 205, - PARTIAL_CONTENT = 206, - MULTIPLE_CHOICES = 300, - MOVED_PERMANENTLY = 301, - FOUND = 302, - SEE_OTHER = 303, - NOT_MODIFIED = 304, - USE_PROXY = 305, - TEMPORARY_REDIRECT = 307, - BAD_REQUEST = 400, - UNAUTHORIZED = 401, - PAYMENT_REQUIRED = 402, - FORBIDDEN = 403, - NOT_FOUND = 404, - METHOD_NOT_ALLOWED = 405, - NOT_ACCEPTABLE = 406, - PROXY_AUTHENTICATION_REQUIRED = 407, - REQUEST_TIMEOUT = 408, - CONFLICT = 409, - GONE = 410, - LENGTH_REQUIRED = 411, - PRECONDITION_FAILED = 412, - REQUEST_ENTITY_TOO_LARGE = 413, - REQUEST_URI_TOO_LONG = 414, - UNSUPPORTED_MEDIA_TYPE = 415, - REQUESTED_RANGE_NOT_SATISFIABLE = 416, - EXPECTATION_FAILED = 417, - UNPROCESSABLE_ENTITY = 422, - TOO_MANY_REQUESTS = 429, - INTERNAL_SERVER_ERROR = 500, - NOT_IMPLEMENTED = 501, - BAD_GATEWAY = 502, - SERVICE_UNAVAILABLE = 503, - GATEWAY_TIMEOUT = 504, - HTTP_VERSION_NOT_SUPPORTED = 505, + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + TEMPORARY_REDIRECT = 307, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + REQUEST_ENTITY_TOO_LARGE = 413, + REQUEST_URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + REQUESTED_RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + UNPROCESSABLE_ENTITY = 422, + TOO_MANY_REQUESTS = 429, + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, } diff --git a/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts b/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts index 56a3ec17ec270..c1843f30b22eb 100644 --- a/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts +++ b/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts @@ -2,42 +2,42 @@ import type { ILivechatRoom, IVisitor } from '../livechat'; import type { IUser } from '../users'; export interface IExtraRoomParams { - source?: ILivechatRoom['source']; - customFields?: { - [key: string]: unknown; - }; + source?: ILivechatRoom['source']; + customFields?: { + [key: string]: unknown; + }; } export interface ILivechatCreator { - /** - * Creates a room to connect the `visitor` to an `agent`. - * - * This method uses the Livechat routing method configured - * in the server - * - * @param visitor The Livechat Visitor that started the conversation - * @param agent The agent responsible for the room - */ - createRoom(visitor: IVisitor, agent: IUser, extraParams?: IExtraRoomParams): Promise; + /** + * Creates a room to connect the `visitor` to an `agent`. + * + * This method uses the Livechat routing method configured + * in the server + * + * @param visitor The Livechat Visitor that started the conversation + * @param agent The agent responsible for the room + */ + createRoom(visitor: IVisitor, agent: IUser, extraParams?: IExtraRoomParams): Promise; - /** - * @deprecated Use `createAndReturnVisitor` instead. - * Creates a Livechat visitor - * - * @param visitor Data of the visitor to be created - */ - createVisitor(visitor: IVisitor): Promise; + /** + * @deprecated Use `createAndReturnVisitor` instead. + * Creates a Livechat visitor + * + * @param visitor Data of the visitor to be created + */ + createVisitor(visitor: IVisitor): Promise; - /** - * Creates a Livechat visitor - * - * @param visitor Data of the visitor to be created - */ - createAndReturnVisitor(visitor: IVisitor): Promise; + /** + * Creates a Livechat visitor + * + * @param visitor Data of the visitor to be created + */ + createAndReturnVisitor(visitor: IVisitor): Promise; - /** - * Creates a token to be used when - * creating a new livechat visitor - */ - createToken(): string; + /** + * Creates a token to be used when + * creating a new livechat visitor + */ + createToken(): string; } diff --git a/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts b/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts index c36b078f53a6f..804bcf06d7227 100644 --- a/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts +++ b/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts @@ -11,209 +11,209 @@ import type { IMessageBuilder } from './IMessageBuilder'; * be able to successfully save the message object. */ export interface ILivechatMessageBuilder { - kind: RocketChatAssociationModel.LIVECHAT_MESSAGE; - - /** - * Provides a convient way to set the data for the message. - * Note: Providing an "id" field here will be ignored. - * - * @param message the message data to set - */ - setData(message: ILivechatMessage): ILivechatMessageBuilder; - - /** - * Sets the room where this message should be sent to. - * - * @param room the room where to send - */ - setRoom(room: IRoom): ILivechatMessageBuilder; - - /** - * Gets the room where this message was sent to. - */ - getRoom(): IRoom; - - /** - * Sets the sender of this message. - * - * @param sender the user sending the message - */ - setSender(sender: IUser): ILivechatMessageBuilder; - - /** - * Gets the User which sent the message. - */ - getSender(): IUser; - - /** - * Sets the text of the message. - * - * @param text the actual text - */ - setText(text: string): ILivechatMessageBuilder; - - /** - * Gets the message text. - */ - getText(): string; - - /** - * Sets the emoji to use for the avatar, this overwrites the current avatar - * whether it be the user's or the avatar url provided. - * - * @param emoji the emoji code - */ - setEmojiAvatar(emoji: string): ILivechatMessageBuilder; - - /** - * Gets the emoji used for the avatar. - */ - getEmojiAvatar(): string; - - /** - * Sets the url which to display for the avatar, this overwrites the current - * avatar whether it be the user's or an emoji one. - * - * @param avatarUrl image url to use as the avatar - */ - setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder; - - /** - * Gets the url used for the avatar. - */ - getAvatarUrl(): string; - - /** - * Sets the display text of the sender's username that is visible. - * - * @param alias the username alias to display - */ - setUsernameAlias(alias: string): ILivechatMessageBuilder; - - /** - * Gets the display text of the sender's username that is visible. - */ - getUsernameAlias(): string; - - /** - * Adds one attachment to the message's list of attachments, this will not - * overwrite any existing ones but just adds. - * - * @param attachment the attachment to add - */ - addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder; - - /** - * Sets the attachments for the message, replacing and destroying all of the current attachments. - * - * @param attachments array of the attachments - */ - setAttachments(attachments: Array): ILivechatMessageBuilder; - - /** - * Gets the attachments array for the message - */ - getAttachments(): Array; - - /** - * Replaces an attachment at the given position (index). - * If there is no attachment at that position, there will be an error thrown. - * - * @param position the index of the attachment to replace - * @param attachment the attachment to replace with - */ - replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder; - - /** - * Removes an attachment at the given position (index). - * If there is no attachment at that position, there will be an error thrown. - * - * @param position the index of the attachment to remove - */ - removeAttachment(position: number): ILivechatMessageBuilder; - - /** - * Sets the user who is editing this message. - * This is required if you are modifying an existing message. - * - * @param user the editor - */ - setEditor(user: IUser): ILivechatMessageBuilder; - - /** - * Gets the user who edited the message - */ - getEditor(): IUser; - - /** - * Sets whether this message can group with others. - * This is desirable if you want to avoid confusion with other integrations. - * - * @param groupable whether this message can group with others - */ - setGroupable(groupable: boolean): ILivechatMessageBuilder; - - /** - * Gets whether this message can group with others. - */ - getGroupable(): boolean; - - /** - * Sets whether this message should have any URLs in the text - * parsed by Rocket.Chat and get the details added to the message's - * attachments. - * - * @param parseUrls whether URLs should be parsed in this message - */ - setParseUrls(parseUrls: boolean): ILivechatMessageBuilder; - - /** - * Gets whether this message should have its URLs parsed - */ - getParseUrls(): boolean; - - /** - * Set the token of the livechat visitor that - * sent the message - * - * @param token The Livechat visitor's token - */ - setToken(token: string): ILivechatMessageBuilder; - - /** - * Gets the token of the livechat visitor that - * sent the message - */ - getToken(): string; - - /** - * If the sender of the message is a Livechat Visitor, - * set the visitor who sent the message. - * - * If you set the visitor property of a message, the - * sender will be emptied - * - * @param visitor The visitor who sent the message - */ - setVisitor(visitor: IVisitor): ILivechatMessageBuilder; - - /** - * Get the visitor who sent the message, - * if any - */ - getVisitor(): IVisitor; - - /** - * Gets the resulting message that has been built up to the point of calling it. - * - * *Note:* This will error out if the Room has not been defined OR if the room - * is not of type RoomType.LIVE_CHAT. - */ - getMessage(): ILivechatMessage; - - /** - * Returns a message builder based on the - * livechat message of this builder - */ - getMessageBuilder(): IMessageBuilder; + kind: RocketChatAssociationModel.LIVECHAT_MESSAGE; + + /** + * Provides a convient way to set the data for the message. + * Note: Providing an "id" field here will be ignored. + * + * @param message the message data to set + */ + setData(message: ILivechatMessage): ILivechatMessageBuilder; + + /** + * Sets the room where this message should be sent to. + * + * @param room the room where to send + */ + setRoom(room: IRoom): ILivechatMessageBuilder; + + /** + * Gets the room where this message was sent to. + */ + getRoom(): IRoom; + + /** + * Sets the sender of this message. + * + * @param sender the user sending the message + */ + setSender(sender: IUser): ILivechatMessageBuilder; + + /** + * Gets the User which sent the message. + */ + getSender(): IUser; + + /** + * Sets the text of the message. + * + * @param text the actual text + */ + setText(text: string): ILivechatMessageBuilder; + + /** + * Gets the message text. + */ + getText(): string; + + /** + * Sets the emoji to use for the avatar, this overwrites the current avatar + * whether it be the user's or the avatar url provided. + * + * @param emoji the emoji code + */ + setEmojiAvatar(emoji: string): ILivechatMessageBuilder; + + /** + * Gets the emoji used for the avatar. + */ + getEmojiAvatar(): string; + + /** + * Sets the url which to display for the avatar, this overwrites the current + * avatar whether it be the user's or an emoji one. + * + * @param avatarUrl image url to use as the avatar + */ + setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder; + + /** + * Gets the url used for the avatar. + */ + getAvatarUrl(): string; + + /** + * Sets the display text of the sender's username that is visible. + * + * @param alias the username alias to display + */ + setUsernameAlias(alias: string): ILivechatMessageBuilder; + + /** + * Gets the display text of the sender's username that is visible. + */ + getUsernameAlias(): string; + + /** + * Adds one attachment to the message's list of attachments, this will not + * overwrite any existing ones but just adds. + * + * @param attachment the attachment to add + */ + addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder; + + /** + * Sets the attachments for the message, replacing and destroying all of the current attachments. + * + * @param attachments array of the attachments + */ + setAttachments(attachments: Array): ILivechatMessageBuilder; + + /** + * Gets the attachments array for the message + */ + getAttachments(): Array; + + /** + * Replaces an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to replace + * @param attachment the attachment to replace with + */ + replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder; + + /** + * Removes an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to remove + */ + removeAttachment(position: number): ILivechatMessageBuilder; + + /** + * Sets the user who is editing this message. + * This is required if you are modifying an existing message. + * + * @param user the editor + */ + setEditor(user: IUser): ILivechatMessageBuilder; + + /** + * Gets the user who edited the message + */ + getEditor(): IUser; + + /** + * Sets whether this message can group with others. + * This is desirable if you want to avoid confusion with other integrations. + * + * @param groupable whether this message can group with others + */ + setGroupable(groupable: boolean): ILivechatMessageBuilder; + + /** + * Gets whether this message can group with others. + */ + getGroupable(): boolean; + + /** + * Sets whether this message should have any URLs in the text + * parsed by Rocket.Chat and get the details added to the message's + * attachments. + * + * @param parseUrls whether URLs should be parsed in this message + */ + setParseUrls(parseUrls: boolean): ILivechatMessageBuilder; + + /** + * Gets whether this message should have its URLs parsed + */ + getParseUrls(): boolean; + + /** + * Set the token of the livechat visitor that + * sent the message + * + * @param token The Livechat visitor's token + */ + setToken(token: string): ILivechatMessageBuilder; + + /** + * Gets the token of the livechat visitor that + * sent the message + */ + getToken(): string; + + /** + * If the sender of the message is a Livechat Visitor, + * set the visitor who sent the message. + * + * If you set the visitor property of a message, the + * sender will be emptied + * + * @param visitor The visitor who sent the message + */ + setVisitor(visitor: IVisitor): ILivechatMessageBuilder; + + /** + * Get the visitor who sent the message, + * if any + */ + getVisitor(): IVisitor; + + /** + * Gets the resulting message that has been built up to the point of calling it. + * + * *Note:* This will error out if the Room has not been defined OR if the room + * is not of type RoomType.LIVE_CHAT. + */ + getMessage(): ILivechatMessage; + + /** + * Returns a message builder based on the + * livechat message of this builder + */ + getMessageBuilder(): IMessageBuilder; } diff --git a/packages/apps-engine/src/definition/accessors/ILivechatRead.ts b/packages/apps-engine/src/definition/accessors/ILivechatRead.ts index a756d162c3377..2642a029abaef 100644 --- a/packages/apps-engine/src/definition/accessors/ILivechatRead.ts +++ b/packages/apps-engine/src/definition/accessors/ILivechatRead.ts @@ -4,35 +4,35 @@ import type { IVisitor } from '../livechat/IVisitor'; import type { IMessage } from '../messages'; export interface ILivechatRead { - /** - * Gets online status of the livechat. - * @param departmentId (optional) the id of the livechat department - * @deprecated use `isOnlineAsync` instead - */ - isOnline(departmentId?: string): boolean; - /** - * Gets online status of the livechat. - * @param departmentId (optional) the id of the livechat department - */ - isOnlineAsync(departmentId?: string): Promise; - getDepartmentsEnabledWithAgents(): Promise>; - getLivechatRooms(visitor: IVisitor, departmentId?: string): Promise>; - getLivechatOpenRoomsByAgentId(agentId: string): Promise>; - getLivechatTotalOpenRoomsByAgentId(agentId: string): Promise; - /** - * @deprecated This method does not adhere to the conversion practices applied - * elsewhere in the Apps-Engine and will be removed in the next major version. - * Prefer the alternative methods to fetch visitors. - */ - getLivechatVisitors(query: object): Promise>; - getLivechatVisitorById(id: string): Promise; - getLivechatVisitorByEmail(email: string): Promise; - getLivechatVisitorByToken(token: string): Promise; - getLivechatVisitorByPhoneNumber(phoneNumber: string): Promise; - getLivechatDepartmentByIdOrName(value: string): Promise; - /** - * @experimental we do not encourage the wider usage of this method, - * as we're evaluating its performance and fit for the API. - */ - _fetchLivechatRoomMessages(roomId: string): Promise>; + /** + * Gets online status of the livechat. + * @param departmentId (optional) the id of the livechat department + * @deprecated use `isOnlineAsync` instead + */ + isOnline(departmentId?: string): boolean; + /** + * Gets online status of the livechat. + * @param departmentId (optional) the id of the livechat department + */ + isOnlineAsync(departmentId?: string): Promise; + getDepartmentsEnabledWithAgents(): Promise>; + getLivechatRooms(visitor: IVisitor, departmentId?: string): Promise>; + getLivechatOpenRoomsByAgentId(agentId: string): Promise>; + getLivechatTotalOpenRoomsByAgentId(agentId: string): Promise; + /** + * @deprecated This method does not adhere to the conversion practices applied + * elsewhere in the Apps-Engine and will be removed in the next major version. + * Prefer the alternative methods to fetch visitors. + */ + getLivechatVisitors(query: object): Promise>; + getLivechatVisitorById(id: string): Promise; + getLivechatVisitorByEmail(email: string): Promise; + getLivechatVisitorByToken(token: string): Promise; + getLivechatVisitorByPhoneNumber(phoneNumber: string): Promise; + getLivechatDepartmentByIdOrName(value: string): Promise; + /** + * @experimental we do not encourage the wider usage of this method, + * as we're evaluating its performance and fit for the API. + */ + _fetchLivechatRoomMessages(roomId: string): Promise>; } diff --git a/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts b/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts index fb75cf9ecf3b0..c0ee2cc145bb7 100644 --- a/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts +++ b/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts @@ -3,31 +3,31 @@ import type { IRoom } from '../rooms'; import type { IUser } from '../users'; export interface ILivechatUpdater { - /** - * Transfer a Livechat visitor to another room - * - * @param visitor Visitor to be transferred - * @param transferData The data to execute the transferring - */ - transferVisitor(visitor: IVisitor, transferData: ILivechatTransferData): Promise; + /** + * Transfer a Livechat visitor to another room + * + * @param visitor Visitor to be transferred + * @param transferData The data to execute the transferring + */ + transferVisitor(visitor: IVisitor, transferData: ILivechatTransferData): Promise; - /** - * Closes a Livechat room - * - * @param room The room to be closed - * @param comment The comment explaining the reason for closing the room - * @param closer The user that closes the room - */ - closeRoom(room: IRoom, comment: string, closer?: IUser): Promise; + /** + * Closes a Livechat room + * + * @param room The room to be closed + * @param comment The comment explaining the reason for closing the room + * @param closer The user that closes the room + */ + closeRoom(room: IRoom, comment: string, closer?: IUser): Promise; - /** - * Set a livechat visitor's custom fields by its token - * @param token The visitor's token - * @param key The key in the custom fields - * @param value The value to be set - * @param overwrite Whether overwrite or not - * - * @returns Promise to whether success or not - */ - setCustomFields(token: IVisitor['token'], key: string, value: string, overwrite: boolean): Promise; + /** + * Set a livechat visitor's custom fields by its token + * @param token The visitor's token + * @param key The key in the custom fields + * @param value The value to be set + * @param overwrite Whether overwrite or not + * + * @returns Promise to whether success or not + */ + setCustomFields(token: IVisitor['token'], key: string, value: string, overwrite: boolean): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ILogEntry.ts b/packages/apps-engine/src/definition/accessors/ILogEntry.ts index 4dc46693b6d9d..55d6dcfec6b25 100644 --- a/packages/apps-engine/src/definition/accessors/ILogEntry.ts +++ b/packages/apps-engine/src/definition/accessors/ILogEntry.ts @@ -1,22 +1,22 @@ export enum LogMessageSeverity { - DEBUG = 'debug', - INFORMATION = 'info', - LOG = 'log', - WARNING = 'warning', - ERROR = 'error', - SUCCESS = 'success', + DEBUG = 'debug', + INFORMATION = 'info', + LOG = 'log', + WARNING = 'warning', + ERROR = 'error', + SUCCESS = 'success', } /** * Message which will be passed to a UI (either in a log or in the application's UI) */ export interface ILogEntry { - /** The function name who did this logging, this is automatically added (can be null). */ - caller?: string; - /** The severity rate, this is automatically added. */ - severity: LogMessageSeverity; - /** When this entry was made. */ - timestamp: Date; - /** The items which were logged. */ - args: Array; + /** The function name who did this logging, this is automatically added (can be null). */ + caller?: string; + /** The severity rate, this is automatically added. */ + severity: LogMessageSeverity; + /** When this entry was made. */ + timestamp: Date; + /** The items which were logged. */ + args: Array; } diff --git a/packages/apps-engine/src/definition/accessors/ILogger.ts b/packages/apps-engine/src/definition/accessors/ILogger.ts index 227cb617fa77b..f630719ac37e4 100644 --- a/packages/apps-engine/src/definition/accessors/ILogger.ts +++ b/packages/apps-engine/src/definition/accessors/ILogger.ts @@ -7,23 +7,23 @@ import type { AppMethod } from '../metadata/AppMethod'; * allow people to easily see what happened (users) or debug what went wrong. */ export interface ILogger { - method: `${AppMethod}`; + method: `${AppMethod}`; - debug(...items: Array): void; - info(...items: Array): void; - log(...items: Array): void; - warn(...items: Array): void; - error(...items: Array): void; - success(...items: Array): void; + debug(...items: Array): void; + info(...items: Array): void; + log(...items: Array): void; + warn(...items: Array): void; + error(...items: Array): void; + success(...items: Array): void; - /** Gets the entries logged. */ - getEntries(): Array; - /** Gets the method which this logger is for. */ - getMethod(): `${AppMethod}`; - /** Gets when this logger was constructed. */ - getStartTime(): Date; - /** Gets the end time, usually Date.now(). */ - getEndTime(): Date; - /** Gets the amount of time this was a logger, start - Date.now(). */ - getTotalTime(): number; + /** Gets the entries logged. */ + getEntries(): Array; + /** Gets the method which this logger is for. */ + getMethod(): `${AppMethod}`; + /** Gets when this logger was constructed. */ + getStartTime(): Date; + /** Gets the end time, usually Date.now(). */ + getEndTime(): Date; + /** Gets the amount of time this was a logger, start - Date.now(). */ + getTotalTime(): number; } diff --git a/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts b/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts index 024a4b123ff81..cb11ee431045f 100644 --- a/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts +++ b/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts @@ -12,225 +12,225 @@ import type { IUser } from '../users'; * be able to successfully save the message object. */ export interface IMessageBuilder { - kind: RocketChatAssociationModel.MESSAGE; - - /** - * Provides a convenient way to set the data for the message. - * Note: Providing an "id" field here will be ignored. - * - * @param message the message data to set - */ - setData(message: IMessage): IMessageBuilder; - - /** - * Provides a convenient way to set the data for the message - * keeping the "id" field so as to update the message later. - * - * @param message the message data to set - * @param editor the user who edited the updated message - */ - setUpdateData(message: IMessage, editor: IUser): IMessageBuilder; - - /** - * Sets the thread to which this message belongs, if any. - * - * @param threadId The id of the thread - */ - setThreadId(threadId: string): IMessageBuilder; - - /** - * Retrieves the threadId to which this message belongs, - * if any. - * - * If you would like to retrieve the actual message that - * the thread originated from, you can use the - * `IMessageRead.getById()` method - */ - getThreadId(): string; - - /** - * Sets the room where this message should be sent to. - * - * @param room the room where to send - */ - setRoom(room: IRoom): IMessageBuilder; - - /** - * Gets the room where this message was sent to. - */ - getRoom(): IRoom; - - /** - * Sets the sender of this message. - * - * @param sender the user sending the message - */ - setSender(sender: IUser): IMessageBuilder; - - /** - * Gets the User which sent the message. - */ - getSender(): IUser; - - /** - * Sets the text of the message. - * - * @param text the actual text - */ - setText(text: string): IMessageBuilder; - - /** - * Gets the message text. - */ - getText(): string; - - /** - * Sets the emoji to use for the avatar, this overwrites the current avatar - * whether it be the user's or the avatar url provided. - * - * @param emoji the emoji code - */ - setEmojiAvatar(emoji: string): IMessageBuilder; - - /** - * Gets the emoji used for the avatar. - */ - getEmojiAvatar(): string; - - /** - * Sets the url which to display for the avatar, this overwrites the current - * avatar whether it be the user's or an emoji one. - * - * @param avatarUrl image url to use as the avatar - */ - setAvatarUrl(avatarUrl: string): IMessageBuilder; - - /** - * Gets the url used for the avatar. - */ - getAvatarUrl(): string; - - /** - * Sets the display text of the sender's username that is visible. - * - * @param alias the username alias to display - */ - setUsernameAlias(alias: string): IMessageBuilder; - - /** - * Gets the display text of the sender's username that is visible. - */ - getUsernameAlias(): string; - - /** - * Adds one attachment to the message's list of attachments, this will not - * overwrite any existing ones but just adds. - * - * @param attachment the attachment to add - */ - addAttachment(attachment: IMessageAttachment): IMessageBuilder; - - /** - * Sets the attachments for the message, replacing and destroying all of the current attachments. - * - * @param attachments array of the attachments - */ - setAttachments(attachments: Array): IMessageBuilder; - - /** - * Gets the attachments array for the message - */ - getAttachments(): Array; - - /** - * Replaces an attachment at the given position (index). - * If there is no attachment at that position, there will be an error thrown. - * - * @param position the index of the attachment to replace - * @param attachment the attachment to replace with - */ - replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder; - - /** - * Removes an attachment at the given position (index). - * If there is no attachment at that position, there will be an error thrown. - * - * @param position the index of the attachment to remove - */ - removeAttachment(position: number): IMessageBuilder; - - /** - * Sets the user who is editing this message. - * This is required if you are modifying an existing message. - * - * @param user the editor - */ - setEditor(user: IUser): IMessageBuilder; - - /** - * Gets the user who edited the message - */ - getEditor(): IUser; - - /** - * Sets whether this message can group with others. - * This is desirable if you want to avoid confusion with other integrations. - * - * @param groupable whether this message can group with others - */ - setGroupable(groupable: boolean): IMessageBuilder; - - /** - * Gets whether this message can group with others. - */ - getGroupable(): boolean; - - /** - * Sets whether this message should have any URLs in the text - * parsed by Rocket.Chat and get the details added to the message's - * attachments. - * - * @param parseUrls whether URLs should be parsed in this message - */ - setParseUrls(parseUrls: boolean): IMessageBuilder; - - /** - * Gets whether this message should have its URLs parsed - */ - getParseUrls(): boolean; - - /** - * Gets the resulting message that has been built up to the point of calling it. - * - * *Note:* This will error out if the Room has not been defined. - */ - getMessage(): IMessage; - - /** - * Adds a block collection to the message's - * own collection - */ - addBlocks(blocks: BlockBuilder | Array): IMessageBuilder; - - /** - * Sets the block collection of the message - * - * @param blocks - */ - setBlocks(blocks: BlockBuilder | Array): IMessageBuilder; - - /** - * Gets the block collection of the message - */ - getBlocks(): Array; - - /** - * Adds a custom field to the message. - * Note: This key can not already exist or it will throw an error. - * Note: The key must not contain a period in it, an error will be thrown. - * - * @param key the name of the custom field - * @param value the value of this custom field - */ - addCustomField(key: string, value: any): IMessageBuilder; + kind: RocketChatAssociationModel.MESSAGE; + + /** + * Provides a convenient way to set the data for the message. + * Note: Providing an "id" field here will be ignored. + * + * @param message the message data to set + */ + setData(message: IMessage): IMessageBuilder; + + /** + * Provides a convenient way to set the data for the message + * keeping the "id" field so as to update the message later. + * + * @param message the message data to set + * @param editor the user who edited the updated message + */ + setUpdateData(message: IMessage, editor: IUser): IMessageBuilder; + + /** + * Sets the thread to which this message belongs, if any. + * + * @param threadId The id of the thread + */ + setThreadId(threadId: string): IMessageBuilder; + + /** + * Retrieves the threadId to which this message belongs, + * if any. + * + * If you would like to retrieve the actual message that + * the thread originated from, you can use the + * `IMessageRead.getById()` method + */ + getThreadId(): string; + + /** + * Sets the room where this message should be sent to. + * + * @param room the room where to send + */ + setRoom(room: IRoom): IMessageBuilder; + + /** + * Gets the room where this message was sent to. + */ + getRoom(): IRoom; + + /** + * Sets the sender of this message. + * + * @param sender the user sending the message + */ + setSender(sender: IUser): IMessageBuilder; + + /** + * Gets the User which sent the message. + */ + getSender(): IUser; + + /** + * Sets the text of the message. + * + * @param text the actual text + */ + setText(text: string): IMessageBuilder; + + /** + * Gets the message text. + */ + getText(): string; + + /** + * Sets the emoji to use for the avatar, this overwrites the current avatar + * whether it be the user's or the avatar url provided. + * + * @param emoji the emoji code + */ + setEmojiAvatar(emoji: string): IMessageBuilder; + + /** + * Gets the emoji used for the avatar. + */ + getEmojiAvatar(): string; + + /** + * Sets the url which to display for the avatar, this overwrites the current + * avatar whether it be the user's or an emoji one. + * + * @param avatarUrl image url to use as the avatar + */ + setAvatarUrl(avatarUrl: string): IMessageBuilder; + + /** + * Gets the url used for the avatar. + */ + getAvatarUrl(): string; + + /** + * Sets the display text of the sender's username that is visible. + * + * @param alias the username alias to display + */ + setUsernameAlias(alias: string): IMessageBuilder; + + /** + * Gets the display text of the sender's username that is visible. + */ + getUsernameAlias(): string; + + /** + * Adds one attachment to the message's list of attachments, this will not + * overwrite any existing ones but just adds. + * + * @param attachment the attachment to add + */ + addAttachment(attachment: IMessageAttachment): IMessageBuilder; + + /** + * Sets the attachments for the message, replacing and destroying all of the current attachments. + * + * @param attachments array of the attachments + */ + setAttachments(attachments: Array): IMessageBuilder; + + /** + * Gets the attachments array for the message + */ + getAttachments(): Array; + + /** + * Replaces an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to replace + * @param attachment the attachment to replace with + */ + replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder; + + /** + * Removes an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to remove + */ + removeAttachment(position: number): IMessageBuilder; + + /** + * Sets the user who is editing this message. + * This is required if you are modifying an existing message. + * + * @param user the editor + */ + setEditor(user: IUser): IMessageBuilder; + + /** + * Gets the user who edited the message + */ + getEditor(): IUser; + + /** + * Sets whether this message can group with others. + * This is desirable if you want to avoid confusion with other integrations. + * + * @param groupable whether this message can group with others + */ + setGroupable(groupable: boolean): IMessageBuilder; + + /** + * Gets whether this message can group with others. + */ + getGroupable(): boolean; + + /** + * Sets whether this message should have any URLs in the text + * parsed by Rocket.Chat and get the details added to the message's + * attachments. + * + * @param parseUrls whether URLs should be parsed in this message + */ + setParseUrls(parseUrls: boolean): IMessageBuilder; + + /** + * Gets whether this message should have its URLs parsed + */ + getParseUrls(): boolean; + + /** + * Gets the resulting message that has been built up to the point of calling it. + * + * *Note:* This will error out if the Room has not been defined. + */ + getMessage(): IMessage; + + /** + * Adds a block collection to the message's + * own collection + */ + addBlocks(blocks: BlockBuilder | Array): IMessageBuilder; + + /** + * Sets the block collection of the message + * + * @param blocks + */ + setBlocks(blocks: BlockBuilder | Array): IMessageBuilder; + + /** + * Gets the block collection of the message + */ + getBlocks(): Array; + + /** + * Adds a custom field to the message. + * Note: This key can not already exist or it will throw an error. + * Note: The key must not contain a period in it, an error will be thrown. + * + * @param key the name of the custom field + * @param value the value of this custom field + */ + addCustomField(key: string, value: any): IMessageBuilder; } diff --git a/packages/apps-engine/src/definition/accessors/IMessageExtender.ts b/packages/apps-engine/src/definition/accessors/IMessageExtender.ts index 7db010bae0819..400db11de67cc 100644 --- a/packages/apps-engine/src/definition/accessors/IMessageExtender.ts +++ b/packages/apps-engine/src/definition/accessors/IMessageExtender.ts @@ -2,35 +2,35 @@ import type { IMessage, IMessageAttachment } from '../messages'; import type { RocketChatAssociationModel } from '../metadata'; export interface IMessageExtender { - kind: RocketChatAssociationModel.MESSAGE; + kind: RocketChatAssociationModel.MESSAGE; - /** - * Adds a custom field to the message. - * Note: This key can not already exist or it will throw an error. - * Note: The key must not contain a period in it, an error will be thrown. - * - * @param key the name of the custom field - * @param value the value of this custom field - */ - addCustomField(key: string, value: any): IMessageExtender; + /** + * Adds a custom field to the message. + * Note: This key can not already exist or it will throw an error. + * Note: The key must not contain a period in it, an error will be thrown. + * + * @param key the name of the custom field + * @param value the value of this custom field + */ + addCustomField(key: string, value: any): IMessageExtender; - /** - * Adds a single attachment to the message. - * - * @param attachment the item to add - */ - addAttachment(attachment: IMessageAttachment): IMessageExtender; + /** + * Adds a single attachment to the message. + * + * @param attachment the item to add + */ + addAttachment(attachment: IMessageAttachment): IMessageExtender; - /** - * Adds all of the provided attachments to the message. - * - * @param attachments an array of attachments - */ - addAttachments(attachments: Array): IMessageExtender; + /** + * Adds all of the provided attachments to the message. + * + * @param attachments an array of attachments + */ + addAttachments(attachments: Array): IMessageExtender; - /** - * Gets the resulting message that has been extended at the point of calling it. - * Note: modifying the returned value will have no effect. - */ - getMessage(): IMessage; + /** + * Gets the resulting message that has been extended at the point of calling it. + * Note: modifying the returned value will have no effect. + */ + getMessage(): IMessage; } diff --git a/packages/apps-engine/src/definition/accessors/IMessageRead.ts b/packages/apps-engine/src/definition/accessors/IMessageRead.ts index 10c99d26388b6..86fc2701c9dd9 100644 --- a/packages/apps-engine/src/definition/accessors/IMessageRead.ts +++ b/packages/apps-engine/src/definition/accessors/IMessageRead.ts @@ -7,9 +7,9 @@ import type { IUser } from '../users/IUser'; * messages in a read-only-fashion. */ export interface IMessageRead { - getById(id: string): Promise; + getById(id: string): Promise; - getSenderUser(messageId: string): Promise; + getSenderUser(messageId: string): Promise; - getRoom(messageId: string): Promise; + getRoom(messageId: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts b/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts index b21baacae04f7..ba8cd71504221 100644 --- a/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts +++ b/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts @@ -1,21 +1,21 @@ import type { Reaction } from '../messages'; export interface IMessageUpdater { - /** - * Add a reaction to a message - * - * @param messageId the id of the message - * @param userId the id of the user - * @param reaction the reaction - */ - addReaction(messageId: string, userId: string, reaction: Reaction): Promise; + /** + * Add a reaction to a message + * + * @param messageId the id of the message + * @param userId the id of the user + * @param reaction the reaction + */ + addReaction(messageId: string, userId: string, reaction: Reaction): Promise; - /** - * Remove a reaction from a message - * - * @param messageId the id of the message - * @param userId the id of the user - * @param reaction the reaction - */ - removeReaction(messageId: string, userId: string, reaction: Reaction): Promise; + /** + * Remove a reaction from a message + * + * @param messageId the id of the message + * @param userId the id of the user + * @param reaction the reaction + */ + removeReaction(messageId: string, userId: string, reaction: Reaction): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IModerationModify.ts b/packages/apps-engine/src/definition/accessors/IModerationModify.ts index 6b0f54968a043..4786a189fb2bb 100644 --- a/packages/apps-engine/src/definition/accessors/IModerationModify.ts +++ b/packages/apps-engine/src/definition/accessors/IModerationModify.ts @@ -2,26 +2,26 @@ import type { IMessage } from '../messages'; import type { IUser } from '../users'; export interface IModerationModify { - /** - * Provides a way for Apps to report a message. - * @param messageId the messageId to report - * @param description the description of the report - * @param userId the userId to be reported - * @param appId the app id - */ - report(messageId: string, description: string, userId: string, appId: string): Promise; + /** + * Provides a way for Apps to report a message. + * @param messageId the messageId to report + * @param description the description of the report + * @param userId the userId to be reported + * @param appId the app id + */ + report(messageId: string, description: string, userId: string, appId: string): Promise; - /** - * Provides a way for Apps to dismiss reports by message id. - * @param messageId the messageId to dismiss reports - * @param appId the app id - */ - dismissReportsByMessageId(messageId: IMessage['id'], reason: string, action: string, appId: string): Promise; + /** + * Provides a way for Apps to dismiss reports by message id. + * @param messageId the messageId to dismiss reports + * @param appId the app id + */ + dismissReportsByMessageId(messageId: IMessage['id'], reason: string, action: string, appId: string): Promise; - /** - * Provides a way for Apps to dismiss reports by user id. - * @param userId the userId to dismiss reports - * @param appId the app id - */ - dismissReportsByUserId(userId: IUser['id'], reason: string, action: string, appId: string): Promise; + /** + * Provides a way for Apps to dismiss reports by user id. + * @param userId the userId to dismiss reports + * @param appId the app id + */ + dismissReportsByUserId(userId: IUser['id'], reason: string, action: string, appId: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IModify.ts b/packages/apps-engine/src/definition/accessors/IModify.ts index e76e4cc768246..16ac42977a5b8 100644 --- a/packages/apps-engine/src/definition/accessors/IModify.ts +++ b/packages/apps-engine/src/definition/accessors/IModify.ts @@ -9,37 +9,37 @@ import type { ISchedulerModify } from './ISchedulerModify'; import type { IUIController } from './IUIController'; export interface IModify { - getCreator(): IModifyCreator; + getCreator(): IModifyCreator; - getDeleter(): IModifyDeleter; + getDeleter(): IModifyDeleter; - getExtender(): IModifyExtender; + getExtender(): IModifyExtender; - getUpdater(): IModifyUpdater; + getUpdater(): IModifyUpdater; - /** - * Gets the accessor for sending notifications to a user or users in a room. - * - * @returns the notifier accessor - */ - getNotifier(): INotifier; - /** - * Gets the accessor for interacting with the UI - */ - getUiController(): IUIController; + /** + * Gets the accessor for sending notifications to a user or users in a room. + * + * @returns the notifier accessor + */ + getNotifier(): INotifier; + /** + * Gets the accessor for interacting with the UI + */ + getUiController(): IUIController; - /** - * Gets the accessor for creating scheduled jobs - */ - getScheduler(): ISchedulerModify; + /** + * Gets the accessor for creating scheduled jobs + */ + getScheduler(): ISchedulerModify; - /** - * Gets the accessor for creating OAuth apps - */ - getOAuthAppsModifier(): IOAuthAppsModify; - /** - * Gets the accessor for modifying moderation - * @returns the moderation accessor - */ - getModerationModifier(): IModerationModify; + /** + * Gets the accessor for creating OAuth apps + */ + getOAuthAppsModifier(): IOAuthAppsModify; + /** + * Gets the accessor for modifying moderation + * @returns the moderation accessor + */ + getModerationModifier(): IModerationModify; } diff --git a/packages/apps-engine/src/definition/accessors/IModifyCreator.ts b/packages/apps-engine/src/definition/accessors/IModifyCreator.ts index 27033b2cf3540..851d020cba290 100644 --- a/packages/apps-engine/src/definition/accessors/IModifyCreator.ts +++ b/packages/apps-engine/src/definition/accessors/IModifyCreator.ts @@ -16,91 +16,93 @@ import type { IUserBuilder } from './IUserBuilder'; import type { IVideoConferenceBuilder } from './IVideoConferenceBuilder'; export interface IModifyCreator { - /** - * Get the creator object responsible for the - * Livechat integrations - */ - getLivechatCreator(): ILivechatCreator; + /** + * Get the creator object responsible for the + * Livechat integrations + */ + getLivechatCreator(): ILivechatCreator; - /** - * Get the creator object responsible for the upload. - */ - getUploadCreator(): IUploadCreator; + /** + * Get the creator object responsible for the upload. + */ + getUploadCreator(): IUploadCreator; - /** - * Gets the creator object responsible for email sending - */ - getEmailCreator(): IEmailCreator; + /** + * Gets the creator object responsible for email sending + */ + getEmailCreator(): IEmailCreator; - /** - * Gets the creator object responsible for contact related operations. - */ - getContactCreator(): IContactCreator; + /** + * Gets the creator object responsible for contact related operations. + */ + getContactCreator(): IContactCreator; - /** - * @deprecated please prefer the rocket.chat/ui-kit components - * - * Gets a new instance of a BlockBuilder - */ - getBlockBuilder(): BlockBuilder; - /** - * Starts the process for building a new message object. - * - * @param data (optional) the initial data to pass into the builder, - * the `id` property will be ignored - * @return an IMessageBuilder instance - */ - startMessage(data?: IMessage): IMessageBuilder; + /** + * @deprecated please prefer the rocket.chat/ui-kit components + * + * Gets a new instance of a BlockBuilder + */ + getBlockBuilder(): BlockBuilder; + /** + * Starts the process for building a new message object. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IMessageBuilder instance + */ + startMessage(data?: IMessage): IMessageBuilder; - /** - * Starts the process for building a new livechat message object. - * - * @param data (optional) the initial data to pass into the builder, - * the `id` property will be ignored - * @return an IMessageBuilder instance - */ - startLivechatMessage(data?: ILivechatMessage): ILivechatMessageBuilder; + /** + * Starts the process for building a new livechat message object. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IMessageBuilder instance + */ + startLivechatMessage(data?: ILivechatMessage): ILivechatMessageBuilder; - /** - * Starts the process for building a new room. - * - * @param data (optional) the initial data to pass into the builder, - * the `id` property will be ignored - * @return an IRoomBuilder instance - */ - startRoom(data?: IRoom): IRoomBuilder; + /** + * Starts the process for building a new room. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IRoomBuilder instance + */ + startRoom(data?: IRoom): IRoomBuilder; - /** - * Starts the process for building a new discussion. - * - * @param data (optional) the initial data to pass into the builder, - * the `id` property will be ignored - * @return an IDiscussionBuilder instance - */ - startDiscussion(data?: Partial): IDiscussionBuilder; + /** + * Starts the process for building a new discussion. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IDiscussionBuilder instance + */ + startDiscussion(data?: Partial): IDiscussionBuilder; - /** - * Starts the process for building a new video conference. - * - * @param data (optional) the initial data to pass into the builder, - * @return an IVideoConferenceBuilder instance - */ - startVideoConference(data?: Partial): IVideoConferenceBuilder; + /** + * Starts the process for building a new video conference. + * + * @param data (optional) the initial data to pass into the builder, + * @return an IVideoConferenceBuilder instance + */ + startVideoConference(data?: Partial): IVideoConferenceBuilder; - /** - * Starts the process for building a new bot user. - * - * @param data (optional) the initial data to pass into the builder, - * the `id` property will be ignored - * @return an IUserBuilder instance - */ - startBotUser(data?: Partial): IUserBuilder; + /** + * Starts the process for building a new bot user. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IUserBuilder instance + */ + startBotUser(data?: Partial): IUserBuilder; - /** - * Finishes the creating process, saving the object to the database. - * - * @param builder the builder instance - * @return the resulting `id` of the resulting object - */ - finish(builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder): Promise; + /** + * Finishes the creating process, saving the object to the database. + * + * @param builder the builder instance + * @return the resulting `id` of the resulting object + */ + finish( + builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder, + ): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts b/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts index 7d1103ba13f3e..0659ced2930af 100644 --- a/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts +++ b/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts @@ -2,11 +2,11 @@ import type { IMessage } from '../messages'; import type { IUser, UserType } from '../users'; export interface IModifyDeleter { - deleteRoom(roomId: string): Promise; + deleteRoom(roomId: string): Promise; - deleteUsers(appId: Exclude, userType: UserType.APP | UserType.BOT): Promise; + deleteUsers(appId: Exclude, userType: UserType.APP | UserType.BOT): Promise; - deleteMessage(message: IMessage, user: IUser): Promise; + deleteMessage(message: IMessage, user: IUser): Promise; - removeUsersFromRoom(roomId: string, usernames: Array): Promise; + removeUsersFromRoom(roomId: string, usernames: Array): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IModifyExtender.ts b/packages/apps-engine/src/definition/accessors/IModifyExtender.ts index 786b239754076..d0e62d0095804 100644 --- a/packages/apps-engine/src/definition/accessors/IModifyExtender.ts +++ b/packages/apps-engine/src/definition/accessors/IModifyExtender.ts @@ -4,37 +4,37 @@ import type { IRoomExtender } from './IRoomExtender'; import type { IVideoConferenceExtender } from './IVideoConferenceExtend'; export interface IModifyExtender { - /** - * Modifies a message in a non-destructive way: Properties can be added to it, - * but existing properties cannot be changed. - * - * @param messageId the id of the message to be extended - * @param updater the user who is updating/extending the message - * @return the extender instance for the message - */ - extendMessage(messageId: string, updater: IUser): Promise; + /** + * Modifies a message in a non-destructive way: Properties can be added to it, + * but existing properties cannot be changed. + * + * @param messageId the id of the message to be extended + * @param updater the user who is updating/extending the message + * @return the extender instance for the message + */ + extendMessage(messageId: string, updater: IUser): Promise; - /** - * Modifies a room in a non-destructive way: Properties can be added to it, - * but existing properties cannot be changed. - * - * @param roomId the id of the room to be extended - * @param updater the user who is updating/extending the room - * @return the extender instance for the room - */ - extendRoom(roomId: string, updater: IUser): Promise; + /** + * Modifies a room in a non-destructive way: Properties can be added to it, + * but existing properties cannot be changed. + * + * @param roomId the id of the room to be extended + * @param updater the user who is updating/extending the room + * @return the extender instance for the room + */ + extendRoom(roomId: string, updater: IUser): Promise; - /** - * Modifies a video conference in a non-destructive way: Properties can be added to it, - * but existing properties cannot be changed. - */ - extendVideoConference(id: string): Promise; + /** + * Modifies a video conference in a non-destructive way: Properties can be added to it, + * but existing properties cannot be changed. + */ + extendVideoConference(id: string): Promise; - /** - * Finishes the extending process, saving the object to the database. - * Note: If there is an issue or error while updating, this will throw an error. - * - * @param extender the extender instance - */ - finish(extender: IRoomExtender | IMessageExtender | IVideoConferenceExtender): Promise; + /** + * Finishes the extending process, saving the object to the database. + * Note: If there is an issue or error while updating, this will throw an error. + * + * @param extender the extender instance + */ + finish(extender: IRoomExtender | IMessageExtender | IVideoConferenceExtender): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts b/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts index 60dcf90b2df77..a57eb7fa52f55 100644 --- a/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts +++ b/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts @@ -6,47 +6,47 @@ import type { IRoomBuilder } from './IRoomBuilder'; import type { IUserUpdater } from './IUserUpdater'; export interface IModifyUpdater { - /** - * Get the updater object responsible for the - * Livechat integrations - */ - getLivechatUpdater(): ILivechatUpdater; + /** + * Get the updater object responsible for the + * Livechat integrations + */ + getLivechatUpdater(): ILivechatUpdater; - /** - * Gets the update object responsible for - * methods that update users - */ - getUserUpdater(): IUserUpdater; + /** + * Gets the update object responsible for + * methods that update users + */ + getUserUpdater(): IUserUpdater; - /** - * Get the updater object responsible for - * methods that update messages - */ - getMessageUpdater(): IMessageUpdater; + /** + * Get the updater object responsible for + * methods that update messages + */ + getMessageUpdater(): IMessageUpdater; - /** - * Modifies an existing message. - * Raises an exception if a non-existent messageId is supplied - * - * @param messageId the id of the existing message to modfiy and build - * @param updater the user who is updating the message - */ - message(messageId: string, updater: IUser): Promise; + /** + * Modifies an existing message. + * Raises an exception if a non-existent messageId is supplied + * + * @param messageId the id of the existing message to modfiy and build + * @param updater the user who is updating the message + */ + message(messageId: string, updater: IUser): Promise; - /** - * Modifies an existing room. - * Raises an exception if a non-existent roomId is supplied - * - * @param roomId the id of the existing room to modify and build - * @param updater the user who is updating the room - */ - room(roomId: string, updater: IUser): Promise; + /** + * Modifies an existing room. + * Raises an exception if a non-existent roomId is supplied + * + * @param roomId the id of the existing room to modify and build + * @param updater the user who is updating the room + */ + room(roomId: string, updater: IUser): Promise; - /** - * Finishes the updating process, saving the object to the database. - * Note: If there is an issue or error while updating, this will throw an error. - * - * @param builder the builder instance - */ - finish(builder: IMessageBuilder | IRoomBuilder): Promise; + /** + * Finishes the updating process, saving the object to the database. + * Note: If there is an issue or error while updating, this will throw an error. + * + * @param builder the builder instance + */ + finish(builder: IMessageBuilder | IRoomBuilder): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/INotifier.ts b/packages/apps-engine/src/definition/accessors/INotifier.ts index a41fb22c4ff6e..cf776fb55cda5 100644 --- a/packages/apps-engine/src/definition/accessors/INotifier.ts +++ b/packages/apps-engine/src/definition/accessors/INotifier.ts @@ -4,60 +4,60 @@ import type { IUser } from '../users'; import type { IMessageBuilder } from './IMessageBuilder'; export enum TypingScope { - Room = 'room', + Room = 'room', } export interface ITypingOptions { - /** - * The typing scope where the typing message should be presented, - * TypingScope.Room by default. - */ - scope?: TypingScope; - /** - * The id of the typing scope - * - * TypingScope.Room <-> room.id - */ - id: string; - /** - * The name of the user who is typing the message - * - * **Note**: If not provided, it will use app assigned - * user's name by default. - */ - username?: string; + /** + * The typing scope where the typing message should be presented, + * TypingScope.Room by default. + */ + scope?: TypingScope; + /** + * The id of the typing scope + * + * TypingScope.Room <-> room.id + */ + id: string; + /** + * The name of the user who is typing the message + * + * **Note**: If not provided, it will use app assigned + * user's name by default. + */ + username?: string; } export interface INotifier { - /** - * Notifies the provided user of the provided message. - * - * **Note**: Notifications only are shown to the user if they are - * online and it only stays around for the duration of their session. - * - * @param user The user who should be notified - * @param message The message with the content to notify the user about - */ - notifyUser(user: IUser, message: IMessage): Promise; + /** + * Notifies the provided user of the provided message. + * + * **Note**: Notifications only are shown to the user if they are + * online and it only stays around for the duration of their session. + * + * @param user The user who should be notified + * @param message The message with the content to notify the user about + */ + notifyUser(user: IUser, message: IMessage): Promise; - /** - * Notifies all of the users in the provided room. - * - * **Note**: Notifications only are shown to those online - * and it only stays around for the duration of their session. - * - * @param room The room which to notify the users in - * @param message The message content to notify users about - */ - notifyRoom(room: IRoom, message: IMessage): Promise; + /** + * Notifies all of the users in the provided room. + * + * **Note**: Notifications only are shown to those online + * and it only stays around for the duration of their session. + * + * @param room The room which to notify the users in + * @param message The message content to notify users about + */ + notifyRoom(room: IRoom, message: IMessage): Promise; - /** - * Notifies all of the users a typing indicator in the provided scope. - * - * @returns a cancellation function to stop typing - */ - typing(options: ITypingOptions): Promise<() => Promise>; + /** + * Notifies all of the users a typing indicator in the provided scope. + * + * @returns a cancellation function to stop typing + */ + typing(options: ITypingOptions): Promise<() => Promise>; - /** Gets a new message builder for building a notification message. */ - getMessageBuilder(): IMessageBuilder; + /** Gets a new message builder for building a notification message. */ + getMessageBuilder(): IMessageBuilder; } diff --git a/packages/apps-engine/src/definition/accessors/IOAuthApp.ts b/packages/apps-engine/src/definition/accessors/IOAuthApp.ts index 1c2edbe19c958..4f356bebb627d 100644 --- a/packages/apps-engine/src/definition/accessors/IOAuthApp.ts +++ b/packages/apps-engine/src/definition/accessors/IOAuthApp.ts @@ -1,13 +1,13 @@ export interface IOAuthApp { - id: string; - name: string; - active: boolean; - clientId?: string; - clientSecret?: string; - redirectUri: string; - createdAt?: string; - updatedAt?: string; - createdBy: { username: string; id: string }; + id: string; + name: string; + active: boolean; + clientId?: string; + clientSecret?: string; + redirectUri: string; + createdAt?: string; + updatedAt?: string; + createdBy: { username: string; id: string }; } export type IOAuthAppParams = Omit; diff --git a/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts b/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts index 72d0a4ddce5a8..5fd908e558388 100644 --- a/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts +++ b/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts @@ -1,23 +1,23 @@ import type { IOAuthAppParams } from './IOAuthApp'; export interface IOAuthAppsModify { - /** - * Create an OAuthApp - * @param OAuthApp - the OAuth app to create, in case the clientId and the clientSecret is not sent it will generate automatically - * @param appId - the app id - */ - createOAuthApp(OAuthApp: IOAuthAppParams, appId: string): Promise; - /** - * Update the OAuth app info - * @param OAuthApp - OAuth data that will be updated - * @param id - OAuth app id - * @param appId - the app id - */ - updateOAuthApp(OAuthApp: IOAuthAppParams, id: string, appId: string): Promise; - /** - * Deletes the OAuth app - * @param id - OAuth app id - * @param appId - the app id - */ - deleteOAuthApp(id: string, appId: string): Promise; + /** + * Create an OAuthApp + * @param OAuthApp - the OAuth app to create, in case the clientId and the clientSecret is not sent it will generate automatically + * @param appId - the app id + */ + createOAuthApp(OAuthApp: IOAuthAppParams, appId: string): Promise; + /** + * Update the OAuth app info + * @param OAuthApp - OAuth data that will be updated + * @param id - OAuth app id + * @param appId - the app id + */ + updateOAuthApp(OAuthApp: IOAuthAppParams, id: string, appId: string): Promise; + /** + * Deletes the OAuth app + * @param id - OAuth app id + * @param appId - the app id + */ + deleteOAuthApp(id: string, appId: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts b/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts index 97d544cd93668..9b9436650fde0 100644 --- a/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts +++ b/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts @@ -1,16 +1,16 @@ import type { IOAuthApp } from './IOAuthApp'; export interface IOAuthAppsReader { - /** - * Returns the OAuth app info by its id - * @param id - OAuth app id - * @param appId - the app id - */ - getOAuthAppById(id: string, appId: string): Promise; - /** - * Returns the OAuth app info by its name - * @param name - OAuth app name - * @param appId - the app id - */ - getOAuthAppByName(name: string, appId: string): Promise>; + /** + * Returns the OAuth app info by its id + * @param id - OAuth app id + * @param appId - the app id + */ + getOAuthAppById(id: string, appId: string): Promise; + /** + * Returns the OAuth app info by its name + * @param name - OAuth app name + * @param appId - the app id + */ + getOAuthAppByName(name: string, appId: string): Promise>; } diff --git a/packages/apps-engine/src/definition/accessors/IPersistence.ts b/packages/apps-engine/src/definition/accessors/IPersistence.ts index 30f1d676539e4..fda208e69ee07 100644 --- a/packages/apps-engine/src/definition/accessors/IPersistence.ts +++ b/packages/apps-engine/src/definition/accessors/IPersistence.ts @@ -6,92 +6,92 @@ import type { RocketChatAssociationRecord } from '../metadata'; * have access to any other App's. */ export interface IPersistence { - /** - * Creates a new record in the App's persistent storage, returning the resulting "id". - * - * @param data the actual data to store, must be an object otherwise it will error out. - * @return the resulting record's id - */ - create(data: object): Promise; + /** + * Creates a new record in the App's persistent storage, returning the resulting "id". + * + * @param data the actual data to store, must be an object otherwise it will error out. + * @return the resulting record's id + */ + create(data: object): Promise; - /** - * Creates a new record in the App's persistent storage with the associated information - * being provided. - * - * @param data the actual data to store, must be an object otherwise it will error out - * @param association the association data which includes the model and record id - * @return the resulting record's id - */ - createWithAssociation(data: object, association: RocketChatAssociationRecord): Promise; + /** + * Creates a new record in the App's persistent storage with the associated information + * being provided. + * + * @param data the actual data to store, must be an object otherwise it will error out + * @param association the association data which includes the model and record id + * @return the resulting record's id + */ + createWithAssociation(data: object, association: RocketChatAssociationRecord): Promise; - /** - * Creates a new record in the App's persistent storage with the data being - * associated with more than one Rocket.Chat record. - * - * @param data the actual data to store, must be an object otherwise it will error out - * @param associations an array of association data which includes the model and record id - * @return the resulting record's id - */ - createWithAssociations(data: object, associations: Array): Promise; + /** + * Creates a new record in the App's persistent storage with the data being + * associated with more than one Rocket.Chat record. + * + * @param data the actual data to store, must be an object otherwise it will error out + * @param associations an array of association data which includes the model and record id + * @return the resulting record's id + */ + createWithAssociations(data: object, associations: Array): Promise; - /** - * Updates an existing record with the data provided in the App's persistent storage. - * This will throw an error if the record doesn't currently exist or if the data is not an object. - * - * @param id the data record's id - * @param data the actual data to store, must be an object otherwise it will error out - * @param upsert whether a record should be created if the id to be updated does not exist - * @return the id of the updated/upserted record - */ - update(id: string, data: object, upsert?: boolean): Promise; + /** + * Updates an existing record with the data provided in the App's persistent storage. + * This will throw an error if the record doesn't currently exist or if the data is not an object. + * + * @param id the data record's id + * @param data the actual data to store, must be an object otherwise it will error out + * @param upsert whether a record should be created if the id to be updated does not exist + * @return the id of the updated/upserted record + */ + update(id: string, data: object, upsert?: boolean): Promise; - /** - * Updates an existing record with the data provided in the App's persistent storage which are - * associated with provided information. - * This will throw an error if the record doesn't currently exist or if the data is not an object. - * - * @param association the association record - * @param data the actual data to store, must be an object otherwise it will error out - * @param upsert whether a record should be created if the id to be updated does not exist - * @return the id of the updated/upserted record - */ - updateByAssociation(association: RocketChatAssociationRecord, data: object, upsert?: boolean): Promise; + /** + * Updates an existing record with the data provided in the App's persistent storage which are + * associated with provided information. + * This will throw an error if the record doesn't currently exist or if the data is not an object. + * + * @param association the association record + * @param data the actual data to store, must be an object otherwise it will error out + * @param upsert whether a record should be created if the id to be updated does not exist + * @return the id of the updated/upserted record + */ + updateByAssociation(association: RocketChatAssociationRecord, data: object, upsert?: boolean): Promise; - /** - * Updates an existing record with the data provided in the App's persistent storage which are - * associated with more than one Rocket.Chat record. - * This will throw an error if the record doesn't currently exist or if the data is not an object. - * - * @param associations an array of association data which includes the model and record id - * @param data the actual data to store, must be an object otherwise it will error out - * @param upsert whether a record should be created if the id to be updated does not exist - * @return the id of the updated/upserted record - */ - updateByAssociations(associations: Array, data: object, upsert?: boolean): Promise; + /** + * Updates an existing record with the data provided in the App's persistent storage which are + * associated with more than one Rocket.Chat record. + * This will throw an error if the record doesn't currently exist or if the data is not an object. + * + * @param associations an array of association data which includes the model and record id + * @param data the actual data to store, must be an object otherwise it will error out + * @param upsert whether a record should be created if the id to be updated does not exist + * @return the id of the updated/upserted record + */ + updateByAssociations(associations: Array, data: object, upsert?: boolean): Promise; - /** - * Removes a record by the provided id and returns the removed record. - * - * @param id of the record to remove - * @return the data record which was removed - */ - remove(id: string): Promise; + /** + * Removes a record by the provided id and returns the removed record. + * + * @param id of the record to remove + * @return the data record which was removed + */ + remove(id: string): Promise; - /** - * Removes all of the records in persistent storage which are associated with the provided information. - * - * @param association the information about the association for the records to be removed - * @return the data of the removed records - */ - removeByAssociation(association: RocketChatAssociationRecord): Promise>; + /** + * Removes all of the records in persistent storage which are associated with the provided information. + * + * @param association the information about the association for the records to be removed + * @return the data of the removed records + */ + removeByAssociation(association: RocketChatAssociationRecord): Promise>; - /** - * Removes all of the records in persistent storage which are associated with the provided information. - * More than one association acts like an AND which means a record in persistent storage must have all - * of the associations to be considered a match. - * - * @param associations the information about the associations for the records to be removed - * @return the data of the removed records - */ - removeByAssociations(associations: Array): Promise>; + /** + * Removes all of the records in persistent storage which are associated with the provided information. + * More than one association acts like an AND which means a record in persistent storage must have all + * of the associations to be considered a match. + * + * @param associations the information about the associations for the records to be removed + * @return the data of the removed records + */ + removeByAssociations(associations: Array): Promise>; } diff --git a/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts b/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts index d0d1178a44d08..2867bf8a936e1 100644 --- a/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts +++ b/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts @@ -6,35 +6,35 @@ import type { RocketChatAssociationRecord } from '../metadata'; * have access to any other App's. */ export interface IPersistenceRead { - /** - * Retrieves a record from the App's persistent storage by the provided id. - * A "falsey" value (undefined or null or false) is returned should nothing exist - * in the storage by the provided id. - * - * @param id the record to get's id - * @return the record if it exists, falsey if not - */ - read(id: string): Promise; + /** + * Retrieves a record from the App's persistent storage by the provided id. + * A "falsey" value (undefined or null or false) is returned should nothing exist + * in the storage by the provided id. + * + * @param id the record to get's id + * @return the record if it exists, falsey if not + */ + read(id: string): Promise; - /** - * Retrieves a record from the App's persistent storage by the provided id. - * An empty array is returned should there be no records associated with the - * data provided. - * - * @param association the association record to query the persistent storage for - * @return array of the records if any exists, empty array if none exist - */ - readByAssociation(association: RocketChatAssociationRecord): Promise>; + /** + * Retrieves a record from the App's persistent storage by the provided id. + * An empty array is returned should there be no records associated with the + * data provided. + * + * @param association the association record to query the persistent storage for + * @return array of the records if any exists, empty array if none exist + */ + readByAssociation(association: RocketChatAssociationRecord): Promise>; - /** - * Retrieves a record from the App's persistent storage by the provided id. - * Providing more than one association record acts like an AND which means a record - * in persistent storage must have all of the associations to be considered a match. - * An empty array is returned should there be no records associated with the - * data provided. - * - * @param associations the association records to query the persistent storage for - * @return array of the records if any exists, empty array if none exist - */ - readByAssociations(associations: Array): Promise>; + /** + * Retrieves a record from the App's persistent storage by the provided id. + * Providing more than one association record acts like an AND which means a record + * in persistent storage must have all of the associations to be considered a match. + * An empty array is returned should there be no records associated with the + * data provided. + * + * @param associations the association records to query the persistent storage for + * @return array of the records if any exists, empty array if none exist + */ + readByAssociations(associations: Array): Promise>; } diff --git a/packages/apps-engine/src/definition/accessors/IRead.ts b/packages/apps-engine/src/definition/accessors/IRead.ts index 2f5c55baf258b..e4894e3a14fab 100644 --- a/packages/apps-engine/src/definition/accessors/IRead.ts +++ b/packages/apps-engine/src/definition/accessors/IRead.ts @@ -19,36 +19,36 @@ import type { IVideoConferenceRead } from './IVideoConferenceRead'; * It is safe to be injected in multiple places, idempotent and extensible */ export interface IRead { - /** Gets the IEnvironmentRead instance, contains settings and environmental variables. */ - getEnvironmentReader(): IEnvironmentRead; + /** Gets the IEnvironmentRead instance, contains settings and environmental variables. */ + getEnvironmentReader(): IEnvironmentRead; - /** Gets the IThreadRead instance */ + /** Gets the IThreadRead instance */ - getThreadReader(): IThreadRead; + getThreadReader(): IThreadRead; - /** Gets the IMessageRead instance. */ - getMessageReader(): IMessageRead; + /** Gets the IMessageRead instance. */ + getMessageReader(): IMessageRead; - /** Gets the IPersistenceRead instance. */ - getPersistenceReader(): IPersistenceRead; + /** Gets the IPersistenceRead instance. */ + getPersistenceReader(): IPersistenceRead; - /** Gets the IRoomRead instance. */ - getRoomReader(): IRoomRead; + /** Gets the IRoomRead instance. */ + getRoomReader(): IRoomRead; - /** Gets the IUserRead instance. */ - getUserReader(): IUserRead; + /** Gets the IUserRead instance. */ + getUserReader(): IUserRead; - /** Gets the INotifier for notifying users/rooms. */ - getNotifier(): INotifier; + /** Gets the INotifier for notifying users/rooms. */ + getNotifier(): INotifier; - getLivechatReader(): ILivechatRead; - getUploadReader(): IUploadRead; - getCloudWorkspaceReader(): ICloudWorkspaceRead; + getLivechatReader(): ILivechatRead; + getUploadReader(): IUploadRead; + getCloudWorkspaceReader(): ICloudWorkspaceRead; - getVideoConferenceReader(): IVideoConferenceRead; + getVideoConferenceReader(): IVideoConferenceRead; - getOAuthAppsReader(): IOAuthAppsReader; + getOAuthAppsReader(): IOAuthAppsReader; - getRoleReader(): IRoleRead; - getContactReader(): IContactRead; + getRoleReader(): IRoleRead; + getContactReader(): IContactRead; } diff --git a/packages/apps-engine/src/definition/accessors/IRoleRead.ts b/packages/apps-engine/src/definition/accessors/IRoleRead.ts index fb56ed306a327..8ad83da396a91 100644 --- a/packages/apps-engine/src/definition/accessors/IRoleRead.ts +++ b/packages/apps-engine/src/definition/accessors/IRoleRead.ts @@ -4,24 +4,24 @@ import type { IRole } from '../roles'; * Interface for reading roles. */ export interface IRoleRead { - /** - * Retrieves a role by its id or name. - * @param idOrName The id or name of the role to retrieve. - * @param appId The id of the app. - * @returns The role, if found. - * @returns null if no role is found. - * @throws If there is an error while retrieving the role. - */ - getOneByIdOrName(idOrName: IRole['id'] | IRole['name'], appId: string): Promise; + /** + * Retrieves a role by its id or name. + * @param idOrName The id or name of the role to retrieve. + * @param appId The id of the app. + * @returns The role, if found. + * @returns null if no role is found. + * @throws If there is an error while retrieving the role. + */ + getOneByIdOrName(idOrName: IRole['id'] | IRole['name'], appId: string): Promise; - /** - * Retrieves all custom roles. - * @param appId The id of the app. - * @returns All custom roles. - * @throws If there is an error while retrieving the roles. - * @throws If the app does not have the necessary permissions. - * @see IRole.protected - * @see AppPermissions.role.read - */ - getCustomRoles(appId: string): Promise>; + /** + * Retrieves all custom roles. + * @param appId The id of the app. + * @returns All custom roles. + * @throws If there is an error while retrieving the roles. + * @throws If the app does not have the necessary permissions. + * @see IRole.protected + * @see AppPermissions.role.read + */ + getCustomRoles(appId: string): Promise>; } diff --git a/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts b/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts index b92955896380f..1f2f17a5bd4f5 100644 --- a/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts +++ b/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts @@ -8,179 +8,179 @@ import type { IUser } from '../users'; * be able to successfully save the room object. */ export interface IRoomBuilder { - kind: RocketChatAssociationModel.ROOM | RocketChatAssociationModel.DISCUSSION; - - /** - * Provides a convient way to set the data for the room. - * Note: Providing an "id" field here will be ignored. - * - * @param room the room data to set - */ - setData(room: Partial): IRoomBuilder; - - /** - * Sets the display name of this room. - * - * @param name the display name of the room - */ - setDisplayName(name: string): IRoomBuilder; - - /** - * Gets the display name of this room. - */ - getDisplayName(): string; - - /** - * Sets the slugified name of this room, it must align to the rules of Rocket.Chat room - * names otherwise there will be an error thrown (no spaces, special characters, etc). - * - * @param name the slugified name - */ - setSlugifiedName(name: string): IRoomBuilder; - - /** - * Gets the slugified name of this room. - */ - getSlugifiedName(): string; - - /** - * Sets the room's type. - * - * @param type the room type - */ - setType(type: RoomType): IRoomBuilder; - - /** - * Gets the room's type. - */ - getType(): RoomType; - - /** - * Sets the creator of the room. - * - * @param creator the user who created the room - */ - setCreator(creator: IUser): IRoomBuilder; - - /** - * Gets the room's creator. - */ - getCreator(): IUser; - - /** - * Adds a user to the room, these are by username until further notice. - * - * @param username the user's username to add to the room - * @deprecated in favor of `addMemberToBeAddedByUsername`. This method will be removed on version 2.0.0 - */ - addUsername(username: string): IRoomBuilder; - - /** - * Sets the usernames of who are joined to the room. - * - * @param usernames the list of usernames - * @deprecated in favor of `setMembersByUsernames`. This method will be removed on version 2.0.0 - */ - setUsernames(usernames: Array): IRoomBuilder; - - /** - * Gets the usernames of users in the room. - * @deprecated in favor of `getMembersUsernames`. This method will be removed on version 2.0.0 - */ - getUsernames(): Array; - - /** - * Adds a member to the room by username - * - * @param username the user's username to add to the room - */ - addMemberToBeAddedByUsername(username: string): IRoomBuilder; - - /** - * Sets a list of members to the room by usernames - * - * @param usernames the list of usernames - */ - setMembersToBeAddedByUsernames(usernames: Array): IRoomBuilder; - - /** - * Gets the list of usernames of the members who are been added to the room - */ - getMembersToBeAddedUsernames(): Array; - - /** - * Sets whether this room should be a default room or not. - * This means that new users will automatically join this room - * when they join the server. - * - * @param isDefault room should be default or not - */ - setDefault(isDefault: boolean): IRoomBuilder; - - /** - * Gets whether this room is a default room or not. - */ - getIsDefault(): boolean; - - /** - * Sets whether this room should be in read only state or not. - * This means that users without the required permission to talk when - * a room is muted will not be able to talk but instead will only be - * able to read the contents of the room. - * - * @param isReadOnly whether it should be read only or not - */ - setReadOnly(isReadOnly: boolean): IRoomBuilder; - - /** - * Gets whether this room is on read only state or not. - */ - getIsReadOnly(): boolean; - - /** - * Sets whether this room should display the system messages (like user join, etc) - * or not. This means that whenever a system event, such as joining or leaving, happens - * then Rocket.Chat won't send the message to the channel. - * - * @param displaySystemMessages whether the messages should display or not - */ - setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder; - - /** - * Gets whether this room should display the system messages or not. - */ - getDisplayingOfSystemMessages(): boolean; - - /** - * Adds a custom field to the room. - * Note: This will replace an existing field with the same key should it exist already. - * - * @param key the name of the key - * @param value the value of the custom field - */ - addCustomField(key: string, value: object): IRoomBuilder; - - /** - * Sets the entire custom field property to an object provided. This will overwrite - * every existing key/values which are unrecoverable. - * - * @param fields the data to set - */ - setCustomFields(fields: { [key: string]: object }): IRoomBuilder; - - /** - * Gets the custom field property of the room. - */ - getCustomFields(): { [key: string]: object }; - - /** - * Gets user ids of members from a direct message - */ - getUserIds(): Array; - - /** - * Gets the resulting room that has been built up to the point of calling this method. - * Note: modifying the returned value will have no effect. - */ - getRoom(): IRoom; + kind: RocketChatAssociationModel.ROOM | RocketChatAssociationModel.DISCUSSION; + + /** + * Provides a convient way to set the data for the room. + * Note: Providing an "id" field here will be ignored. + * + * @param room the room data to set + */ + setData(room: Partial): IRoomBuilder; + + /** + * Sets the display name of this room. + * + * @param name the display name of the room + */ + setDisplayName(name: string): IRoomBuilder; + + /** + * Gets the display name of this room. + */ + getDisplayName(): string; + + /** + * Sets the slugified name of this room, it must align to the rules of Rocket.Chat room + * names otherwise there will be an error thrown (no spaces, special characters, etc). + * + * @param name the slugified name + */ + setSlugifiedName(name: string): IRoomBuilder; + + /** + * Gets the slugified name of this room. + */ + getSlugifiedName(): string; + + /** + * Sets the room's type. + * + * @param type the room type + */ + setType(type: RoomType): IRoomBuilder; + + /** + * Gets the room's type. + */ + getType(): RoomType; + + /** + * Sets the creator of the room. + * + * @param creator the user who created the room + */ + setCreator(creator: IUser): IRoomBuilder; + + /** + * Gets the room's creator. + */ + getCreator(): IUser; + + /** + * Adds a user to the room, these are by username until further notice. + * + * @param username the user's username to add to the room + * @deprecated in favor of `addMemberToBeAddedByUsername`. This method will be removed on version 2.0.0 + */ + addUsername(username: string): IRoomBuilder; + + /** + * Sets the usernames of who are joined to the room. + * + * @param usernames the list of usernames + * @deprecated in favor of `setMembersByUsernames`. This method will be removed on version 2.0.0 + */ + setUsernames(usernames: Array): IRoomBuilder; + + /** + * Gets the usernames of users in the room. + * @deprecated in favor of `getMembersUsernames`. This method will be removed on version 2.0.0 + */ + getUsernames(): Array; + + /** + * Adds a member to the room by username + * + * @param username the user's username to add to the room + */ + addMemberToBeAddedByUsername(username: string): IRoomBuilder; + + /** + * Sets a list of members to the room by usernames + * + * @param usernames the list of usernames + */ + setMembersToBeAddedByUsernames(usernames: Array): IRoomBuilder; + + /** + * Gets the list of usernames of the members who are been added to the room + */ + getMembersToBeAddedUsernames(): Array; + + /** + * Sets whether this room should be a default room or not. + * This means that new users will automatically join this room + * when they join the server. + * + * @param isDefault room should be default or not + */ + setDefault(isDefault: boolean): IRoomBuilder; + + /** + * Gets whether this room is a default room or not. + */ + getIsDefault(): boolean; + + /** + * Sets whether this room should be in read only state or not. + * This means that users without the required permission to talk when + * a room is muted will not be able to talk but instead will only be + * able to read the contents of the room. + * + * @param isReadOnly whether it should be read only or not + */ + setReadOnly(isReadOnly: boolean): IRoomBuilder; + + /** + * Gets whether this room is on read only state or not. + */ + getIsReadOnly(): boolean; + + /** + * Sets whether this room should display the system messages (like user join, etc) + * or not. This means that whenever a system event, such as joining or leaving, happens + * then Rocket.Chat won't send the message to the channel. + * + * @param displaySystemMessages whether the messages should display or not + */ + setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder; + + /** + * Gets whether this room should display the system messages or not. + */ + getDisplayingOfSystemMessages(): boolean; + + /** + * Adds a custom field to the room. + * Note: This will replace an existing field with the same key should it exist already. + * + * @param key the name of the key + * @param value the value of the custom field + */ + addCustomField(key: string, value: object): IRoomBuilder; + + /** + * Sets the entire custom field property to an object provided. This will overwrite + * every existing key/values which are unrecoverable. + * + * @param fields the data to set + */ + setCustomFields(fields: { [key: string]: object }): IRoomBuilder; + + /** + * Gets the custom field property of the room. + */ + getCustomFields(): { [key: string]: object }; + + /** + * Gets user ids of members from a direct message + */ + getUserIds(): Array; + + /** + * Gets the resulting room that has been built up to the point of calling this method. + * Note: modifying the returned value will have no effect. + */ + getRoom(): IRoom; } diff --git a/packages/apps-engine/src/definition/accessors/IRoomExtender.ts b/packages/apps-engine/src/definition/accessors/IRoomExtender.ts index 4135c63edd13c..1ed37d1bca6dc 100644 --- a/packages/apps-engine/src/definition/accessors/IRoomExtender.ts +++ b/packages/apps-engine/src/definition/accessors/IRoomExtender.ts @@ -3,38 +3,38 @@ import type { IRoom } from '../rooms'; import type { IUser } from '../users'; export interface IRoomExtender { - kind: RocketChatAssociationModel.ROOM; + kind: RocketChatAssociationModel.ROOM; - /** - * Adds a custom field to the room. - * Note: This key can not already exist or it will throw an error. - * Note: The key must not contain a period in it, an error will be thrown. - * - * @param key the name of the custom field - * @param value the value of this custom field - */ - addCustomField(key: string, value: any): IRoomExtender; + /** + * Adds a custom field to the room. + * Note: This key can not already exist or it will throw an error. + * Note: The key must not contain a period in it, an error will be thrown. + * + * @param key the name of the custom field + * @param value the value of this custom field + */ + addCustomField(key: string, value: any): IRoomExtender; - /** - * Adds a user to the room. - * - * @param user the user which is to be added to the room - */ - addMember(user: IUser): IRoomExtender; + /** + * Adds a user to the room. + * + * @param user the user which is to be added to the room + */ + addMember(user: IUser): IRoomExtender; - /** - * Get a list of users being added to the room. - */ - getMembersBeingAdded(): Array; + /** + * Get a list of users being added to the room. + */ + getMembersBeingAdded(): Array; - /** - * Get a list of usernames of users being added to the room. - */ - getUsernamesOfMembersBeingAdded(): Array; + /** + * Get a list of usernames of users being added to the room. + */ + getUsernamesOfMembersBeingAdded(): Array; - /** - * Gets the resulting room that has been extended at the point of calling this. - * Note: modifying the returned value will have no effect. - */ - getRoom(): IRoom; + /** + * Gets the resulting room that has been extended at the point of calling this. + * Note: modifying the returned value will have no effect. + */ + getRoom(): IRoom; } diff --git a/packages/apps-engine/src/definition/accessors/IRoomRead.ts b/packages/apps-engine/src/definition/accessors/IRoomRead.ts index 8a21c27156b3a..0b540d0a5c1e7 100644 --- a/packages/apps-engine/src/definition/accessors/IRoomRead.ts +++ b/packages/apps-engine/src/definition/accessors/IRoomRead.ts @@ -8,108 +8,108 @@ import type { IUser } from '../users/index'; * rooms in a read-only-fashion. */ export interface IRoomRead { - /** - * Gets a room by an id. - * - * @param id the id of the room - * @returns the room - */ - getById(id: string): Promise; + /** + * Gets a room by an id. + * + * @param id the id of the room + * @returns the room + */ + getById(id: string): Promise; - /** - * Gets just the creator of the room by the room's id. - * - * @param id the id of the room - * @returns the creator of the room - */ - getCreatorUserById(id: string): Promise; + /** + * Gets just the creator of the room by the room's id. + * + * @param id the id of the room + * @returns the creator of the room + */ + getCreatorUserById(id: string): Promise; - /** - * Gets a room by its name. - * - * @param name the name of the room - * @returns the room - */ - getByName(name: string): Promise; + /** + * Gets a room by its name. + * + * @param name the name of the room + * @returns the room + */ + getByName(name: string): Promise; - /** - * Gets just the creator of the room by the room's name. - * - * @param name the name of the room - * @returns the creator of the room - */ - getCreatorUserByName(name: string): Promise; + /** + * Gets just the creator of the room by the room's name. + * + * @param name the name of the room + * @returns the creator of the room + */ + getCreatorUserByName(name: string): Promise; - /** - * Retrieves an array of messages from the specified room. - * - * @param roomId The unique identifier of the room from which to retrieve messages. - * @param options Optional parameters for retrieving messages: - * - limit: The maximum number of messages to retrieve. Maximum 100 - * - skip: The number of messages to skip (for pagination). - * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either "asc" for ascending order or "desc" for descending order. - * - showThreadMessages: Whether to include thread messages in the results. Defaults to true. - * @returns A Promise that resolves to an array of IMessage objects representing the messages in the room. - */ - getMessages(roomId: string, options?: Partial): Promise>; + /** + * Retrieves an array of messages from the specified room. + * + * @param roomId The unique identifier of the room from which to retrieve messages. + * @param options Optional parameters for retrieving messages: + * - limit: The maximum number of messages to retrieve. Maximum 100 + * - skip: The number of messages to skip (for pagination). + * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either "asc" for ascending order or "desc" for descending order. + * - showThreadMessages: Whether to include thread messages in the results. Defaults to true. + * @returns A Promise that resolves to an array of IMessage objects representing the messages in the room. + */ + getMessages(roomId: string, options?: Partial): Promise>; - /** - * Gets an iterator for all of the users in the provided room. - * - * @param roomId the room's id - * @returns an iterator for the users in the room - */ - getMembers(roomId: string): Promise>; + /** + * Gets an iterator for all of the users in the provided room. + * + * @param roomId the room's id + * @returns an iterator for the users in the room + */ + getMembers(roomId: string): Promise>; - /** - * Gets a direct room with all usernames - * @param usernames all usernames belonging to the direct room - * @returns the room - */ - getDirectByUsernames(usernames: Array): Promise; + /** + * Gets a direct room with all usernames + * @param usernames all usernames belonging to the direct room + * @returns the room + */ + getDirectByUsernames(usernames: Array): Promise; - /** - * Get a list of the moderators of a given room - * - * @param roomId the room's id - * @returns a list of the users with the moderator role in the room - */ - getModerators(roomId: string): Promise>; + /** + * Get a list of the moderators of a given room + * + * @param roomId the room's id + * @returns a list of the users with the moderator role in the room + */ + getModerators(roomId: string): Promise>; - /** - * Get a list of the owners of a given room - * - * @param roomId the room's id - * @returns a list of the users with the owner role in the room - */ - getOwners(roomId: string): Promise>; + /** + * Get a list of the owners of a given room + * + * @param roomId the room's id + * @returns a list of the users with the owner role in the room + */ + getOwners(roomId: string): Promise>; - /** - * Get a list of the leaders of a given room - * - * @param roomId the room's id - * @returns a list of the users with the leader role in the room - */ - getLeaders(roomId: string): Promise>; + /** + * Get a list of the leaders of a given room + * + * @param roomId the room's id + * @returns a list of the users with the leader role in the room + */ + getLeaders(roomId: string): Promise>; - /** - * Retrieves an array of unread messages for a specific user in a specific room. - * - * @param roomId The unique identifier of the room from which to retrieve unread messages. - * @param uid The unique identifier of the user for whom to retrieve unread messages. - * @param options Optional parameters for retrieving messages: - * - limit: The maximum number of messages to retrieve. If more than 100 is passed, it defaults to 100. - * - skip: The number of messages to skip (for pagination). - * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either 'asc' for ascending order or 'desc' for descending order. - * - showThreadMessages: Whether to include thread messages in the results. Defaults to true. - * @returns A Promise that resolves to an array of IMessage objects representing the unread messages for the specified user in the specified room. - */ - getUnreadByUser(roomId: string, uid: string, options?: Partial): Promise; + /** + * Retrieves an array of unread messages for a specific user in a specific room. + * + * @param roomId The unique identifier of the room from which to retrieve unread messages. + * @param uid The unique identifier of the user for whom to retrieve unread messages. + * @param options Optional parameters for retrieving messages: + * - limit: The maximum number of messages to retrieve. If more than 100 is passed, it defaults to 100. + * - skip: The number of messages to skip (for pagination). + * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either 'asc' for ascending order or 'desc' for descending order. + * - showThreadMessages: Whether to include thread messages in the results. Defaults to true. + * @returns A Promise that resolves to an array of IMessage objects representing the unread messages for the specified user in the specified room. + */ + getUnreadByUser(roomId: string, uid: string, options?: Partial): Promise; - /** - * Gets the user's unread messages count in a room. - * @param roomId room's id - * @param uid user's id - */ - getUserUnreadMessageCount(roomId: string, uid: string): Promise; + /** + * Gets the user's unread messages count in a room. + * @param roomId room's id + * @param uid user's id + */ + getUserUnreadMessageCount(roomId: string, uid: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts b/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts index fc003e34b5872..5ec66a0b2c7c8 100644 --- a/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts +++ b/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts @@ -1,11 +1,11 @@ import type { IProcessor } from '../scheduler'; export interface ISchedulerExtend { - /** - * Register processors that can be scheduled to run - * - * @param {Array} processors An array of processors - * @returns List of task ids run at startup, or void no startup run is set - */ - registerProcessors(processors: Array): Promise>; + /** + * Register processors that can be scheduled to run + * + * @param {Array} processors An array of processors + * @returns List of task ids run at startup, or void no startup run is set + */ + registerProcessors(processors: Array): Promise>; } diff --git a/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts b/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts index 04faa8700799e..162cbaa49fea6 100644 --- a/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts +++ b/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts @@ -4,28 +4,28 @@ import type { IOnetimeSchedule, IRecurringSchedule } from '../scheduler'; * This accessor provides methods to work with the Job Scheduler */ export interface ISchedulerModify { - /** - * Schedules a registered processor to run _once_. - * - * @param {IOnetimeSchedule} job - * @returns jobid as string - */ - scheduleOnce(job: IOnetimeSchedule): Promise; - /** - * Schedules a registered processor to run in recurrencly according to a given interval - * - * @param {IRecurringSchedule} job - * @returns jobid as string - */ - scheduleRecurring(job: IRecurringSchedule): Promise; - /** - * Cancels a running job given its jobId - * - * @param {string} jobId - */ - cancelJob(jobId: string): Promise; - /** - * Cancels all the running jobs from the app - */ - cancelAllJobs(): Promise; + /** + * Schedules a registered processor to run _once_. + * + * @param {IOnetimeSchedule} job + * @returns jobid as string + */ + scheduleOnce(job: IOnetimeSchedule): Promise; + /** + * Schedules a registered processor to run in recurrencly according to a given interval + * + * @param {IRecurringSchedule} job + * @returns jobid as string + */ + scheduleRecurring(job: IRecurringSchedule): Promise; + /** + * Cancels a running job given its jobId + * + * @param {string} jobId + */ + cancelJob(jobId: string): Promise; + /** + * Cancels all the running jobs from the app + */ + cancelAllJobs(): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts b/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts index ecb7af2792412..96bea6ac67fb5 100644 --- a/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts +++ b/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts @@ -5,39 +5,39 @@ import type { ISetting } from '../settings/ISetting'; * Only a subset of them are exposed to Apps. */ export interface IServerSettingRead { - /** - * Gets a server setting by id. - * Please note: a error will be thrown if not found - * or trying to access one that isn't exposed. - * - * @param id the id of the setting to get - * @return the setting - */ - getOneById(id: string): Promise; + /** + * Gets a server setting by id. + * Please note: a error will be thrown if not found + * or trying to access one that isn't exposed. + * + * @param id the id of the setting to get + * @return the setting + */ + getOneById(id: string): Promise; - /** - * Gets a server setting's value by id. - * Please note: a error will be thrown if not found - * or trying to access one that isn't exposed. - * - * @param id the id of the setting to get - * @return the setting's value - */ - getValueById(id: string): Promise; + /** + * Gets a server setting's value by id. + * Please note: a error will be thrown if not found + * or trying to access one that isn't exposed. + * + * @param id the id of the setting to get + * @return the setting's value + */ + getValueById(id: string): Promise; - /** - * Gets all of the server settings which are exposed - * to the Apps. - * - * @return an iterator of the exposed settings - */ - getAll(): Promise>; + /** + * Gets all of the server settings which are exposed + * to the Apps. + * + * @return an iterator of the exposed settings + */ + getAll(): Promise>; - /** - * Checks if the server setting for the id provided is readable, - * will return true or false and won't throw an error. - * - * @param id the server setting id - */ - isReadableById(id: string): Promise; + /** + * Checks if the server setting for the id provided is readable, + * will return true or false and won't throw an error. + * + * @param id the server setting id + */ + isReadableById(id: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts b/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts index 766285c259535..d9bf10fb3da2c 100644 --- a/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts +++ b/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts @@ -1,6 +1,6 @@ import type { ISetting } from '../settings/ISetting'; export interface IServerSettingUpdater { - updateOne(setting: ISetting): Promise; - incrementValue(id: ISetting['id'], value?: number): Promise; + updateOne(setting: ISetting): Promise; + incrementValue(id: ISetting['id'], value?: number): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts b/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts index 400bd5ae211f8..bc51a51fb2484 100644 --- a/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts +++ b/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts @@ -6,35 +6,35 @@ import type { ISetting } from '../settings'; * your App's "onEnable". */ export interface IServerSettingsModify { - /** - * Hides an existing settings group. - * - * @param name The technical name of the group - */ - hideGroup(name: string): Promise; + /** + * Hides an existing settings group. + * + * @param name The technical name of the group + */ + hideGroup(name: string): Promise; - /** - * Hides a setting. This does not influence the actual functionality (the setting will still - * have its value and can be programatically read), but the administrator will not be able to see it anymore - * - * @param id the id of the setting to hide - */ - hideSetting(id: string): Promise; + /** + * Hides a setting. This does not influence the actual functionality (the setting will still + * have its value and can be programatically read), but the administrator will not be able to see it anymore + * + * @param id the id of the setting to hide + */ + hideSetting(id: string): Promise; - /** - * Modifies the configured value of another setting, please use it with caution as an invalid - * setting configuration could cause a Rocket.Chat instance to become unstable. - * - * @param setting the modified setting (id must be provided) - */ - modifySetting(setting: ISetting): Promise; + /** + * Modifies the configured value of another setting, please use it with caution as an invalid + * setting configuration could cause a Rocket.Chat instance to become unstable. + * + * @param setting the modified setting (id must be provided) + */ + modifySetting(setting: ISetting): Promise; - /** - * Increases the setting value by the specified amount. - * To be used only with statistic settings that track the amount of times an action has been performed - * - * @param id the id of the existing Rocket.Chat setting - * @param value how much should the count be increased by. Defaults to 1. - */ - incrementValue(id: ISetting['id'], value?: number): Promise; + /** + * Increases the setting value by the specified amount. + * To be used only with statistic settings that track the amount of times an action has been performed + * + * @param id the id of the existing Rocket.Chat setting + * @param value how much should the count be increased by. Defaults to 1. + */ + incrementValue(id: ISetting['id'], value?: number): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ISettingRead.ts b/packages/apps-engine/src/definition/accessors/ISettingRead.ts index 142ee895b1614..80308007d3541 100644 --- a/packages/apps-engine/src/definition/accessors/ISettingRead.ts +++ b/packages/apps-engine/src/definition/accessors/ISettingRead.ts @@ -5,19 +5,19 @@ import type { ISetting } from '../settings/index'; * App settings in a read-only-fashion. */ export interface ISettingRead { - /** - * Gets the App's setting by the provided id. - * Does not throw an error but instead will return undefined it doesn't exist. - * - * @param id the id of the setting - */ - getById(id: string): Promise; + /** + * Gets the App's setting by the provided id. + * Does not throw an error but instead will return undefined it doesn't exist. + * + * @param id the id of the setting + */ + getById(id: string): Promise; - /** - * Gets the App's setting value by the provided id. - * Note: this will throw an error if the setting doesn't exist - * - * @param id the id of the setting value to get - */ - getValueById(id: string): Promise; + /** + * Gets the App's setting value by the provided id. + * Note: this will throw an error if the setting doesn't exist + * + * @param id the id of the setting value to get + */ + getValueById(id: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts b/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts index 9cdc15c7b1464..be2e1538807cb 100644 --- a/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts +++ b/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts @@ -1,6 +1,6 @@ import type { ISetting } from '../settings/ISetting'; export interface ISettingUpdater { - updateValue(id: ISetting['id'], value: ISetting['value']): Promise; - updateSelectOptions(id: ISetting['id'], values: ISetting['values']): Promise; + updateValue(id: ISetting['id'], value: ISetting['value']): Promise; + updateSelectOptions(id: ISetting['id'], values: ISetting['values']): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts b/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts index 2497763796455..d7c18ebf72d19 100644 --- a/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts +++ b/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts @@ -6,12 +6,12 @@ import type { ISetting } from '../settings/index'; * This is provided on initialization of your App. */ export interface ISettingsExtend { - /** - * Adds a setting which can be configured by an administrator. - * Settings can only be added to groups which have been provided by this App earlier - * and if a group is not provided, the setting will appear outside of a group. - * - * @param setting the setting - */ - provideSetting(setting: ISetting): Promise; + /** + * Adds a setting which can be configured by an administrator. + * Settings can only be added to groups which have been provided by this App earlier + * and if a group is not provided, the setting will appear outside of a group. + * + * @param setting the setting + */ + provideSetting(setting: ISetting): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts b/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts index 4895e61bf96f8..df4f330a28dd3 100644 --- a/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts +++ b/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts @@ -6,11 +6,11 @@ import type { ISlashCommand } from '../slashcommands'; */ export interface ISlashCommandsExtend { - /** - * Adds a slash command which can be used during conversations lateron. - * Should a command already exists an error will be thrown. - * - * @param slashCommand the command information - */ - provideSlashCommand(slashCommand: ISlashCommand): Promise; + /** + * Adds a slash command which can be used during conversations lateron. + * Should a command already exists an error will be thrown. + * + * @param slashCommand the command information + */ + provideSlashCommand(slashCommand: ISlashCommand): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts b/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts index b9e3d4c3e6150..3e84a2cdb1063 100644 --- a/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts +++ b/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts @@ -5,26 +5,26 @@ import type { ISlashCommand } from '../slashcommands'; * It is provided during "onEnable" of your App. */ export interface ISlashCommandsModify { - /** - * Modifies an existing command. The command must either be your App's - * own command or a system command. One App can not modify another - * App's command. - * - * @param slashCommand the modified slash command - */ - modifySlashCommand(slashCommand: ISlashCommand): Promise; + /** + * Modifies an existing command. The command must either be your App's + * own command or a system command. One App can not modify another + * App's command. + * + * @param slashCommand the modified slash command + */ + modifySlashCommand(slashCommand: ISlashCommand): Promise; - /** - * Renders an existing slash command un-usable. - * - * @param command the command's usage without the slash - */ - disableSlashCommand(command: string): Promise; + /** + * Renders an existing slash command un-usable. + * + * @param command the command's usage without the slash + */ + disableSlashCommand(command: string): Promise; - /** - * Enables an existing slash command to be usable again. - * - * @param command the command's usage without the slash - */ - enableSlashCommand(command: string): Promise; + /** + * Enables an existing slash command to be usable again. + * + * @param command the command's usage without the slash + */ + enableSlashCommand(command: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IThreadRead.ts b/packages/apps-engine/src/definition/accessors/IThreadRead.ts index 72ceae996eec6..cd213409ee074 100644 --- a/packages/apps-engine/src/definition/accessors/IThreadRead.ts +++ b/packages/apps-engine/src/definition/accessors/IThreadRead.ts @@ -5,5 +5,5 @@ import type { IMessage } from '../messages/index'; * Thread messages in a read-only-fashion. */ export interface IThreadRead { - getThreadById(id: string): Promise | undefined>; + getThreadById(id: string): Promise | undefined>; } diff --git a/packages/apps-engine/src/definition/accessors/IUIController.ts b/packages/apps-engine/src/definition/accessors/IUIController.ts index be7e91f5a05b3..9c9a45caa7ee5 100644 --- a/packages/apps-engine/src/definition/accessors/IUIController.ts +++ b/packages/apps-engine/src/definition/accessors/IUIController.ts @@ -9,23 +9,23 @@ export type IUIKitErrorInteractionParam = Omit & Partial>; export interface IUIController { - /** - * @deprecated please prefer the `openSurfaceView` method - */ - openModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser): Promise; - /** - * @deprecated please prefer the `updateSurfaceView` method - */ - updateModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser): Promise; - /** - * @deprecated please prefer the `openSurfaceView` method - */ - openContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser): Promise; - /** - * @deprecated please prefer the `updateSurfaceView` method - */ - updateContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser): Promise; - setViewError(errorInteraction: IUIKitErrorInteractionParam, context: IUIKitInteractionParam, user: IUser): Promise; - openSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser): Promise; - updateSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `openSurfaceView` method + */ + openModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `updateSurfaceView` method + */ + updateModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `openSurfaceView` method + */ + openContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `updateSurfaceView` method + */ + updateContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + setViewError(errorInteraction: IUIKitErrorInteractionParam, context: IUIKitInteractionParam, user: IUser): Promise; + openSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + updateSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IUIExtend.ts b/packages/apps-engine/src/definition/accessors/IUIExtend.ts index 3dca2e32809b0..3713ad485c890 100644 --- a/packages/apps-engine/src/definition/accessors/IUIExtend.ts +++ b/packages/apps-engine/src/definition/accessors/IUIExtend.ts @@ -1,5 +1,5 @@ import type { IUIActionButtonDescriptor } from '../ui'; export interface IUIExtend { - registerButton(button: IUIActionButtonDescriptor): void; + registerButton(button: IUIActionButtonDescriptor): void; } diff --git a/packages/apps-engine/src/definition/accessors/IUploadCreator.ts b/packages/apps-engine/src/definition/accessors/IUploadCreator.ts index 25262b42e7d34..e1aae0c6c7846 100644 --- a/packages/apps-engine/src/definition/accessors/IUploadCreator.ts +++ b/packages/apps-engine/src/definition/accessors/IUploadCreator.ts @@ -2,11 +2,11 @@ import type { IUpload } from '../uploads'; import type { IUploadDescriptor } from '../uploads/IUploadDescriptor'; export interface IUploadCreator { - /** - * Create an upload to a room - * - * @param buffer A Buffer with the file's content (See [here](https://nodejs.org/api/buffer.html) - * @param descriptor The metadata about the upload - */ - uploadBuffer(buffer: Buffer, descriptor: IUploadDescriptor): Promise; + /** + * Create an upload to a room + * + * @param buffer A Buffer with the file's content (See [here](https://nodejs.org/api/buffer.html) + * @param descriptor The metadata about the upload + */ + uploadBuffer(buffer: Buffer, descriptor: IUploadDescriptor): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IUploadRead.ts b/packages/apps-engine/src/definition/accessors/IUploadRead.ts index ce4029a8c0c81..1d69fd9b65c14 100644 --- a/packages/apps-engine/src/definition/accessors/IUploadRead.ts +++ b/packages/apps-engine/src/definition/accessors/IUploadRead.ts @@ -1,7 +1,7 @@ import type { IUpload } from '../uploads'; export interface IUploadRead { - getById(id: string): Promise; - getBufferById(id: string): Promise; - getBuffer(upload: IUpload): Promise; + getById(id: string): Promise; + getBufferById(id: string): Promise; + getBuffer(upload: IUpload): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IUserBuilder.ts b/packages/apps-engine/src/definition/accessors/IUserBuilder.ts index 4e0c52aa893a2..06ea619c2f925 100644 --- a/packages/apps-engine/src/definition/accessors/IUserBuilder.ts +++ b/packages/apps-engine/src/definition/accessors/IUserBuilder.ts @@ -7,54 +7,54 @@ import type { IUser, IUserEmail } from '../users'; * be able to successfully save the user object. */ export interface IUserBuilder { - kind: RocketChatAssociationModel.USER; - - /** - * Provides a convient way to set the data for the user. - * Note: Providing an "id" field here will be ignored. - * - * @param user the user data to set - */ - setData(user: Partial): IUserBuilder; - - /** - * Sets emails of the user - * - * @param emails the array of email addresses of the user - */ - setEmails(emails: Array): IUserBuilder; - - /** - * Gets emails of the user - */ - getEmails(): Array; - - /** - * Sets the display name of this user. - * - * @param name the display name of the user - */ - setDisplayName(name: string): IUserBuilder; - - /** - * Gets the display name of this user. - */ - getDisplayName(): string; - - /** - * Sets the username for the user - * - * @param username username of the user - */ - setUsername(username: string): IUserBuilder; - - /** - * Gets the username of this user - */ - getUsername(): string; - - /** - * Gets the user - */ - getUser(): Partial; + kind: RocketChatAssociationModel.USER; + + /** + * Provides a convient way to set the data for the user. + * Note: Providing an "id" field here will be ignored. + * + * @param user the user data to set + */ + setData(user: Partial): IUserBuilder; + + /** + * Sets emails of the user + * + * @param emails the array of email addresses of the user + */ + setEmails(emails: Array): IUserBuilder; + + /** + * Gets emails of the user + */ + getEmails(): Array; + + /** + * Sets the display name of this user. + * + * @param name the display name of the user + */ + setDisplayName(name: string): IUserBuilder; + + /** + * Gets the display name of this user. + */ + getDisplayName(): string; + + /** + * Sets the username for the user + * + * @param username username of the user + */ + setUsername(username: string): IUserBuilder; + + /** + * Gets the username of this user + */ + getUsername(): string; + + /** + * Gets the user + */ + getUser(): Partial; } diff --git a/packages/apps-engine/src/definition/accessors/IUserRead.ts b/packages/apps-engine/src/definition/accessors/IUserRead.ts index 33c4c6e455e44..cd4ad3f91b2ef 100644 --- a/packages/apps-engine/src/definition/accessors/IUserRead.ts +++ b/packages/apps-engine/src/definition/accessors/IUserRead.ts @@ -5,18 +5,18 @@ import type { IUser } from '../users/index'; * users in a read-only-fashion. */ export interface IUserRead { - getById(id: string): Promise; + getById(id: string): Promise; - getByUsername(username: string): Promise; + getByUsername(username: string): Promise; - /** - * Gets the app user of this app. - */ - getAppUser(appId?: string): Promise; + /** + * Gets the app user of this app. + */ + getAppUser(appId?: string): Promise; - /** - * Gets the user's badge count (unread messages count). - * @param uid user's id - */ - getUserUnreadMessageCount(uid: string): Promise; + /** + * Gets the user's badge count (unread messages count). + * @param uid user's id + */ + getUserUnreadMessageCount(uid: string): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IUserUpdater.ts b/packages/apps-engine/src/definition/accessors/IUserUpdater.ts index 8c57b4dadfa83..2a869a5b99968 100644 --- a/packages/apps-engine/src/definition/accessors/IUserUpdater.ts +++ b/packages/apps-engine/src/definition/accessors/IUserUpdater.ts @@ -10,9 +10,9 @@ import type { IUser } from '../users/IUser'; * power and "take hold" of a server, for instance. */ export interface IUserUpdater { - updateStatusText(user: IUser, statusText: IUser['statusText']): Promise; - updateStatus(user: IUser, statusText: IUser['statusText'], status: IUser['status']): Promise; - updateBio(user: IUser, bio: IUser['bio']): Promise; - updateCustomFields(user: IUser, customFields: IUser['customFields']): Promise; - deactivate(userId: IUser['id'], confirmRelinquish: boolean): Promise; + updateStatusText(user: IUser, statusText: IUser['statusText']): Promise; + updateStatus(user: IUser, statusText: IUser['statusText'], status: IUser['status']): Promise; + updateBio(user: IUser, bio: IUser['bio']): Promise; + updateCustomFields(user: IUser, customFields: IUser['customFields']): Promise; + deactivate(userId: IUser['id'], confirmRelinquish: boolean): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts b/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts index c61224893e116..9fa1d1d79c8a6 100644 --- a/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts +++ b/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts @@ -6,10 +6,10 @@ import type { IVideoConfProvider } from '../videoConfProviders'; */ export interface IVideoConfProvidersExtend { - /** - * Adds a videoconf provider - * - * @param provider the provider information - */ - provideVideoConfProvider(provider: IVideoConfProvider): Promise; + /** + * Adds a videoconf provider + * + * @param provider the provider information + */ + provideVideoConfProvider(provider: IVideoConfProvider): Promise; } diff --git a/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts b/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts index 11b96da0e4ef2..649e6bd2c1ecb 100644 --- a/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts +++ b/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts @@ -2,33 +2,33 @@ import type { RocketChatAssociationModel } from '../metadata'; import type { AppVideoConference } from '../videoConferences'; export interface IVideoConferenceBuilder { - kind: RocketChatAssociationModel.VIDEO_CONFERENCE; + kind: RocketChatAssociationModel.VIDEO_CONFERENCE; - setData(call: Partial): IVideoConferenceBuilder; + setData(call: Partial): IVideoConferenceBuilder; - setRoomId(rid: string): IVideoConferenceBuilder; + setRoomId(rid: string): IVideoConferenceBuilder; - getRoomId(): string; + getRoomId(): string; - setCreatedBy(userId: string): IVideoConferenceBuilder; + setCreatedBy(userId: string): IVideoConferenceBuilder; - getCreatedBy(): string; + getCreatedBy(): string; - setProviderName(name: string): IVideoConferenceBuilder; + setProviderName(name: string): IVideoConferenceBuilder; - getProviderName(): string; + getProviderName(): string; - setProviderData(data: Record): IVideoConferenceBuilder; + setProviderData(data: Record): IVideoConferenceBuilder; - getProviderData(): Record; + getProviderData(): Record; - setTitle(name: string): IVideoConferenceBuilder; + setTitle(name: string): IVideoConferenceBuilder; - getTitle(): string; + getTitle(): string; - setDiscussionRid(rid: string | undefined): IVideoConferenceBuilder; + setDiscussionRid(rid: string | undefined): IVideoConferenceBuilder; - getDiscussionRid(): string | undefined; + getDiscussionRid(): string | undefined; - getVideoConference(): AppVideoConference; + getVideoConference(): AppVideoConference; } diff --git a/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts b/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts index d9b7e58383685..0cfa1d8707bc8 100644 --- a/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts +++ b/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts @@ -3,19 +3,19 @@ import type { IVideoConferenceUser, VideoConference } from '../videoConferences' import type { VideoConferenceMember } from '../videoConferences/IVideoConference'; export interface IVideoConferenceExtender { - kind: RocketChatAssociationModel.VIDEO_CONFERENCE; + kind: RocketChatAssociationModel.VIDEO_CONFERENCE; - setProviderData(value: Record): IVideoConferenceExtender; + setProviderData(value: Record): IVideoConferenceExtender; - setStatus(value: VideoConference['status']): IVideoConferenceExtender; + setStatus(value: VideoConference['status']): IVideoConferenceExtender; - setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender; + setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender; - setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender; + setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender; - addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender; + addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender; - setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender; + setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender; - getVideoConference(): VideoConference; + getVideoConference(): VideoConference; } diff --git a/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts b/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts index aa2d53d705906..d0de8788d83e0 100644 --- a/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts +++ b/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts @@ -5,11 +5,11 @@ import type { VideoConference } from '../videoConferences/IVideoConference'; * video conferences in a read-only-fashion. */ export interface IVideoConferenceRead { - /** - * Gets a video conference by an id. - * - * @param id the id of the video conference - * @returns the video conference - */ - getById(id: string): Promise; + /** + * Gets a video conference by an id. + * + * @param id the id of the video conference + * @returns the video conference + */ + getById(id: string): Promise; } diff --git a/packages/apps-engine/src/definition/api/ApiEndpoint.ts b/packages/apps-engine/src/definition/api/ApiEndpoint.ts index 8ab7610c9b4fa..08d06f8f9f05a 100644 --- a/packages/apps-engine/src/definition/api/ApiEndpoint.ts +++ b/packages/apps-engine/src/definition/api/ApiEndpoint.ts @@ -5,36 +5,36 @@ import type { IApiResponse, IApiResponseJSON } from './IResponse'; /** Represents an api endpoint that is being provided. */ export abstract class ApiEndpoint implements IApiEndpoint { - /** - * The last part of the api URL. Example: https://{your-server-address}/api/apps/public/{your-app-id}/{path} - * or https://{your-server-address}/api/apps/private/{your-app-id}/{private-hash}/{path} - */ - public path: string; + /** + * The last part of the api URL. Example: https://{your-server-address}/api/apps/public/{your-app-id}/{path} + * or https://{your-server-address}/api/apps/private/{your-app-id}/{private-hash}/{path} + */ + public path: string; - constructor(public app: IApp) {} + constructor(public app: IApp) {} - /** - * Return response with status 200 (OK) and a optional content - * @param content - */ - protected success(content?: any): IApiResponse { - return { - status: HttpStatusCode.OK, - content, - }; - } + /** + * Return response with status 200 (OK) and a optional content + * @param content + */ + protected success(content?: any): IApiResponse { + return { + status: HttpStatusCode.OK, + content, + }; + } - /** - * Return a json response adding Content Type header as - * application/json if not already provided - * @param reponse - */ - protected json(response: IApiResponseJSON): IApiResponse { - if (!response.headers || !response.headers['content-type']) { - response.headers = response.headers || {}; - response.headers['content-type'] = 'application/json'; - } + /** + * Return a json response adding Content Type header as + * application/json if not already provided + * @param reponse + */ + protected json(response: IApiResponseJSON): IApiResponse { + if (!response?.headers['content-type']) { + response.headers = response.headers || {}; + response.headers['content-type'] = 'application/json'; + } - return response; - } + return response; + } } diff --git a/packages/apps-engine/src/definition/api/IApi.ts b/packages/apps-engine/src/definition/api/IApi.ts index 9ad2f42ed5a88..a7e9d28739084 100644 --- a/packages/apps-engine/src/definition/api/IApi.ts +++ b/packages/apps-engine/src/definition/api/IApi.ts @@ -4,55 +4,55 @@ import type { IApiEndpoint } from './IApiEndpoint'; * Represents an api that is being provided. */ export interface IApi { - /** - * Provides the visibility method of the URL, see the ApiVisibility descriptions for more information - */ - visibility: ApiVisibility; - /** - * Provides the visibility method of the URL, see the ApiSecurity descriptions for more information - */ - security: ApiSecurity; - /** - * Provide enpoints for this api registry - */ - endpoints: Array; + /** + * Provides the visibility method of the URL, see the ApiVisibility descriptions for more information + */ + visibility: ApiVisibility; + /** + * Provides the visibility method of the URL, see the ApiSecurity descriptions for more information + */ + security: ApiSecurity; + /** + * Provide enpoints for this api registry + */ + endpoints: Array; } export enum ApiVisibility { - /** - * A public Api has a fixed format for a url. Using it enables an - * easy to remember structure, however, it also means the url is - * intelligently guessed. As a result, we recommend having some - * sort of security setup if you must have a public api.Whether - * you use the provided security, ApiSecurity, or implement your own. - * Url format: - * `https://{your-server-address}/api/apps/public/{your-app-id}/{path}` - */ - PUBLIC, - /** - * Private Api's contain a random value in the url format, - * making them harder go guess by default. The random value - * will be generated whenever the App is installed on a server. - * This means that the URL will not be the same on any server, - * but will remain the same throughout the lifecycle of an App - * including updates. As a result, if a user uninstalls the App - * and reinstalls the App, then the random value will change. - * Url format: - * `https://{your-server-address}/api/apps/private/{your-app-id}/{random-hash}/{path}` - */ - PRIVATE, + /** + * A public Api has a fixed format for a url. Using it enables an + * easy to remember structure, however, it also means the url is + * intelligently guessed. As a result, we recommend having some + * sort of security setup if you must have a public api.Whether + * you use the provided security, ApiSecurity, or implement your own. + * Url format: + * `https://{your-server-address}/api/apps/public/{your-app-id}/{path}` + */ + PUBLIC, + /** + * Private Api's contain a random value in the url format, + * making them harder go guess by default. The random value + * will be generated whenever the App is installed on a server. + * This means that the URL will not be the same on any server, + * but will remain the same throughout the lifecycle of an App + * including updates. As a result, if a user uninstalls the App + * and reinstalls the App, then the random value will change. + * Url format: + * `https://{your-server-address}/api/apps/private/{your-app-id}/{random-hash}/{path}` + */ + PRIVATE, } export enum ApiSecurity { - /** - * No security check will be executed agains the calls made to this URL - */ - UNSECURE, - /** - * Only calls containing a valid token will be able to execute the api - * Mutiple tokens can be generated to access the api, by default one - * will be generated automatically. - * @param `X-Auth-Token` - */ - // CHECKSUM_SECRET, + /** + * No security check will be executed agains the calls made to this URL + */ + UNSECURE, + /** + * Only calls containing a valid token will be able to execute the api + * Mutiple tokens can be generated to access the api, by default one + * will be generated automatically. + * @param `X-Auth-Token` + */ + // CHECKSUM_SECRET, } diff --git a/packages/apps-engine/src/definition/api/IApiEndpoint.ts b/packages/apps-engine/src/definition/api/IApiEndpoint.ts index b369fc175dc2f..5ec783073f2c6 100644 --- a/packages/apps-engine/src/definition/api/IApiEndpoint.ts +++ b/packages/apps-engine/src/definition/api/IApiEndpoint.ts @@ -8,40 +8,89 @@ import type { IApiResponse } from './IResponse'; * Represents an api endpoint that is being provided. */ export interface IApiEndpoint { - /** - * The last part of the api URL. Example: https://{your-server-address}/api/apps/public/{your-app-id}/{path} - * or https://{your-server-address}/api/apps/private/{your-app-id}/{private-hash}/{path} - */ - path: string; - examples?: { [key: string]: IApiExample }; - /** - * Whether this endpoint requires an authenticated user to access it. - * - * The authentication will be done by the host server using its own - * authentication system. - * - * If no authentication is provided, the request will be automatically - * rejected with a 401 status code. - */ - authRequired?: boolean; + /** + * The last part of the api URL. Example: https://{your-server-address}/api/apps/public/{your-app-id}/{path} + * or https://{your-server-address}/api/apps/private/{your-app-id}/{private-hash}/{path} + */ + path: string; + examples?: { [key: string]: IApiExample }; + /** + * Whether this endpoint requires an authenticated user to access it. + * + * The authentication will be done by the host server using its own + * authentication system. + * + * If no authentication is provided, the request will be automatically + * rejected with a 401 status code. + */ + authRequired?: boolean; - /** - * The methods that are available for this endpoint. - * This property is provided by the Runtime and should not be set manually. - * - * Its values are used on the Apps-Engine to validate the request method. - */ - _availableMethods?: string[]; + /** + * The methods that are available for this endpoint. + * This property is provided by the Runtime and should not be set manually. + * + * Its values are used on the Apps-Engine to validate the request method. + */ + _availableMethods?: string[]; - /** - * Called whenever the publically accessible url for this App is called, - * if you handle the methods differently then split it out so your code doesn't get too big. - */ - get?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; - post?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; - put?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; - delete?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; - head?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; - options?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; - patch?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + /** + * Called whenever the publically accessible url for this App is called, + * if you handle the methods differently then split it out so your code doesn't get too big. + */ + get?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; + post?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; + put?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; + delete?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; + head?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; + options?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; + patch?( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise; } diff --git a/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts b/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts index de9144784b34e..69291170c23e5 100644 --- a/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts +++ b/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts @@ -1,6 +1,6 @@ export interface IApiEndpointInfo { - basePath: string; - fullPath: string; - appId: string; - hash?: string; + basePath: string; + fullPath: string; + appId: string; + hash?: string; } diff --git a/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts b/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts index 0ede26045f79d..bdb052192e50f 100644 --- a/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts +++ b/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts @@ -1,10 +1,10 @@ import type { IApiExample } from './IApiExample'; export interface IApiEndpointMetadata { - path: string; - computedPath: string; - methods: Array; - examples?: { - [key: string]: IApiExample; - }; + path: string; + computedPath: string; + methods: Array; + examples?: { + [key: string]: IApiExample; + }; } diff --git a/packages/apps-engine/src/definition/api/IApiExample.ts b/packages/apps-engine/src/definition/api/IApiExample.ts index f870d59e643de..8e3644e67bc94 100644 --- a/packages/apps-engine/src/definition/api/IApiExample.ts +++ b/packages/apps-engine/src/definition/api/IApiExample.ts @@ -2,18 +2,18 @@ * Represents the parameters of an api example. */ export interface IApiExample { - params?: { [key: string]: string }; - query?: { [key: string]: string }; - headers?: { [key: string]: string }; - content?: any; + params?: { [key: string]: string }; + query?: { [key: string]: string }; + headers?: { [key: string]: string }; + content?: any; } /** * Decorator to describe api examples */ export function example(options: IApiExample) { - return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { - target.examples = target.examples || {}; - target.examples[propertyKey] = options; - }; + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + target.examples = target.examples || {}; + target.examples[propertyKey] = options; + }; } diff --git a/packages/apps-engine/src/definition/api/IRequest.ts b/packages/apps-engine/src/definition/api/IRequest.ts index 027de11b20264..935d7a1412f89 100644 --- a/packages/apps-engine/src/definition/api/IRequest.ts +++ b/packages/apps-engine/src/definition/api/IRequest.ts @@ -2,15 +2,15 @@ import type { RequestMethod } from '../accessors'; import type { IUser } from '../users'; export interface IApiRequest { - method: RequestMethod; - headers: { [key: string]: string }; - query: { [key: string]: string }; - params: { [key: string]: string }; - content: any; - privateHash?: string; - /** - * The user that is making the request, as - * authenticated by Rocket.Chat's strategy. - */ - user?: IUser; + method: RequestMethod; + headers: { [key: string]: string }; + query: { [key: string]: string }; + params: { [key: string]: string }; + content: any; + privateHash?: string; + /** + * The user that is making the request, as + * authenticated by Rocket.Chat's strategy. + */ + user?: IUser; } diff --git a/packages/apps-engine/src/definition/api/IResponse.ts b/packages/apps-engine/src/definition/api/IResponse.ts index 8f394b8a93b0c..3a6e1a2e77361 100644 --- a/packages/apps-engine/src/definition/api/IResponse.ts +++ b/packages/apps-engine/src/definition/api/IResponse.ts @@ -1,13 +1,13 @@ import type { HttpStatusCode } from '../accessors'; export interface IApiResponse { - status: HttpStatusCode; - headers?: { [key: string]: string }; - content?: any; + status: HttpStatusCode; + headers?: { [key: string]: string }; + content?: any; } export interface IApiResponseJSON { - status: HttpStatusCode; - headers?: { [key: string]: string }; - content?: { [key: string]: any }; + status: HttpStatusCode; + headers?: { [key: string]: string }; + content?: { [key: string]: any }; } diff --git a/packages/apps-engine/src/definition/assets/IAsset.ts b/packages/apps-engine/src/definition/assets/IAsset.ts index 30c54ae6565d6..be463dacfe791 100644 --- a/packages/apps-engine/src/definition/assets/IAsset.ts +++ b/packages/apps-engine/src/definition/assets/IAsset.ts @@ -1,6 +1,6 @@ export interface IAsset { - name: string; - path: string; - type: string; - public: boolean; + name: string; + path: string; + type: string; + public: boolean; } diff --git a/packages/apps-engine/src/definition/assets/IAssetProvider.ts b/packages/apps-engine/src/definition/assets/IAssetProvider.ts index 4e1da50222faa..6efdbe718518f 100644 --- a/packages/apps-engine/src/definition/assets/IAssetProvider.ts +++ b/packages/apps-engine/src/definition/assets/IAssetProvider.ts @@ -1,5 +1,5 @@ import type { IAsset } from './IAsset'; export interface IAssetProvider { - getAssets(): Array; + getAssets(): Array; } diff --git a/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts b/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts index 40a46bf7e37fd..673d531fabbbf 100644 --- a/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts +++ b/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts @@ -1,4 +1,4 @@ export interface IWorkspaceToken { - token: string; - expiresAt: Date; + token: string; + expiresAt: Date; } diff --git a/packages/apps-engine/src/definition/email/IEmail.ts b/packages/apps-engine/src/definition/email/IEmail.ts index 27acdc0859715..c06c894984c40 100644 --- a/packages/apps-engine/src/definition/email/IEmail.ts +++ b/packages/apps-engine/src/definition/email/IEmail.ts @@ -1,12 +1,12 @@ export interface IEmail { - to: string | string[]; - /** - * @deprecated this will be inferred from the settings - */ - from?: string; - replyTo?: string; - subject: string; - html?: string; - text?: string; - headers?: string; + to: string | string[]; + /** + * @deprecated this will be inferred from the settings + */ + from?: string; + replyTo?: string; + subject: string; + html?: string; + text?: string; + headers?: string; } diff --git a/packages/apps-engine/src/definition/email/IEmailDescriptor.ts b/packages/apps-engine/src/definition/email/IEmailDescriptor.ts index 168bae039168f..df8b11f4dc5a6 100644 --- a/packages/apps-engine/src/definition/email/IEmailDescriptor.ts +++ b/packages/apps-engine/src/definition/email/IEmailDescriptor.ts @@ -1,11 +1,11 @@ export interface IEmailDescriptor { - from?: string | undefined; - to?: string | Array | undefined; - cc?: string | Array | undefined; - bcc?: string | Array | undefined; - replyTo?: string | Array | undefined; - subject?: string | undefined; - text?: string | undefined; - html?: string | undefined; - headers?: Record | undefined; + from?: string | undefined; + to?: string | Array | undefined; + cc?: string | Array | undefined; + bcc?: string | Array | undefined; + replyTo?: string | Array | undefined; + subject?: string | undefined; + text?: string | undefined; + html?: string | undefined; + headers?: Record | undefined; } diff --git a/packages/apps-engine/src/definition/email/IPreEmailSent.ts b/packages/apps-engine/src/definition/email/IPreEmailSent.ts index 2d5e40c92851f..3253eecb45ac2 100644 --- a/packages/apps-engine/src/definition/email/IPreEmailSent.ts +++ b/packages/apps-engine/src/definition/email/IPreEmailSent.ts @@ -15,11 +15,11 @@ import { AppMethod } from '../metadata'; * reason for rejection. */ export interface IPreEmailSent { - [AppMethod.EXECUTE_PRE_EMAIL_SENT]( - context: IPreEmailSentContext, - read: IRead, - http: IHttp, - persis: IPersistence, - modify: IModify, - ): Promise; + [AppMethod.EXECUTE_PRE_EMAIL_SENT]( + context: IPreEmailSentContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts b/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts index 7427424f88eb0..990312d679cd2 100644 --- a/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts +++ b/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts @@ -1,6 +1,6 @@ import type { IEmailDescriptor } from './IEmailDescriptor'; export interface IPreEmailSentContext { - context: unknown; - email: IEmailDescriptor; + context: unknown; + email: IEmailDescriptor; } diff --git a/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts b/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts index a3e802aa69d86..5eaed633afcbe 100644 --- a/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts +++ b/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts @@ -12,21 +12,21 @@ * join a room */ export class AppsEngineException extends Error { - public name = 'AppsEngineException'; + public name = 'AppsEngineException'; - public static JSONRPC_ERROR_CODE = -32070; + public static JSONRPC_ERROR_CODE = -32070; - public message: string; + public message: string; - constructor(message?: string) { - super(); - this.message = message; - } + constructor(message?: string) { + super(); + this.message = message; + } - public getErrorInfo() { - return { - name: this.name, - message: this.message, - }; - } + public getErrorInfo() { + return { + name: this.name, + message: this.message, + }; + } } diff --git a/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts b/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts index 7c750e1c7e22f..43d8757500077 100644 --- a/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts +++ b/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts @@ -4,48 +4,48 @@ import type { IExternalComponentState } from './IExternalComponentState'; * Represents an external component that is being provided. */ export interface IExternalComponent { - /** - * Provides the appId of the app which the external component belongs to. - */ - appId: string; - /** - * Provides the name of the external component. This key must be unique. - */ - name: string; - /** - * Provides the description of the external component. - */ - description: string; - /** - * Provides the icon's url or base64 string. - */ - icon: string; - /** - * Provides the location which external component needs - * to register, see the ExternalComponentLocation descriptions - * for the more information. - */ - location: ExternalComponentLocation; - /** - * Provides the url that external component will load. - */ - url: string; - /** - * Provides options for the external component. - */ - options?: IExternalComponentOptions; - /** - * Represents the current state of the external component. - * The value is *null* until the ExternalComponentOpened - * event is triggered. It doesn't make sense to get its value in - * PreExternalComponentOpenedPrevent, PreExternalComponentOpenedModify - * and PreExternalComponentOpenedExtend handlers. - */ - state?: IExternalComponentState; + /** + * Provides the appId of the app which the external component belongs to. + */ + appId: string; + /** + * Provides the name of the external component. This key must be unique. + */ + name: string; + /** + * Provides the description of the external component. + */ + description: string; + /** + * Provides the icon's url or base64 string. + */ + icon: string; + /** + * Provides the location which external component needs + * to register, see the ExternalComponentLocation descriptions + * for the more information. + */ + location: ExternalComponentLocation; + /** + * Provides the url that external component will load. + */ + url: string; + /** + * Provides options for the external component. + */ + options?: IExternalComponentOptions; + /** + * Represents the current state of the external component. + * The value is *null* until the ExternalComponentOpened + * event is triggered. It doesn't make sense to get its value in + * PreExternalComponentOpenedPrevent, PreExternalComponentOpenedModify + * and PreExternalComponentOpenedExtend handlers. + */ + state?: IExternalComponentState; } export enum ExternalComponentLocation { - CONTEXTUAL_BAR = 'CONTEXTUAL_BAR', + CONTEXTUAL_BAR = 'CONTEXTUAL_BAR', - MODAL = 'MODAL', + MODAL = 'MODAL', } diff --git a/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts b/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts index 2581c047ab439..c679a7b5f3ff9 100644 --- a/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts +++ b/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts @@ -1,10 +1,10 @@ export interface IExternalComponentOptions { - /** - * The width of the external component - */ - width?: number; - /** - * The height of the external component - */ - height?: number; + /** + * The width of the external component + */ + width?: number; + /** + * The height of the external component + */ + height?: number; } diff --git a/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts b/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts index 4c401f3e28d1d..ba33072a28281 100644 --- a/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts +++ b/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts @@ -5,12 +5,12 @@ import type { IExternalComponentRoomInfo, IExternalComponentUserInfo } from '../ * current user's information and the current room's information. */ export interface IExternalComponentState { - /** - * The user who opened this external component - */ - currentUser: IExternalComponentUserInfo; - /** - * The room where the external component belongs to - */ - currentRoom: IExternalComponentRoomInfo; + /** + * The user who opened this external component + */ + currentUser: IExternalComponentUserInfo; + /** + * The room where the external component belongs to + */ + currentRoom: IExternalComponentRoomInfo; } diff --git a/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts index 24d224ba29138..c1324eb837784 100644 --- a/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts +++ b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts @@ -5,12 +5,17 @@ import type { IExternalComponent } from './IExternalComponent'; * Handler called after an external component is closed. */ export interface IPostExternalComponentClosed { - /** - * Method called after an external component is closed. - * - * @param externalComponent The external component which was closed - * @param read An accessor to the environment - * @param http An accessor to the outside world - */ - executePostExternalComponentClosed(externalComponent: IExternalComponent, read: IRead, http: IHttp, persistence: IPersistence): Promise; + /** + * Method called after an external component is closed. + * + * @param externalComponent The external component which was closed + * @param read An accessor to the environment + * @param http An accessor to the outside world + */ + executePostExternalComponentClosed( + externalComponent: IExternalComponent, + read: IRead, + http: IHttp, + persistence: IPersistence, + ): Promise; } diff --git a/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts index 8a09ebe711d27..040f2c404e1b8 100644 --- a/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts +++ b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts @@ -5,12 +5,17 @@ import type { IExternalComponent } from './IExternalComponent'; * Handler called after an external component is opened. */ export interface IPostExternalComponentOpened { - /** - * Method called after an external component is opened. - * - * @param externalComponent The external component which was opened - * @param read An accessor to the environment - * @param http An accessor to the outside world - */ - executePostExternalComponentOpened(externalComponent: IExternalComponent, read: IRead, http: IHttp, persistence: IPersistence): Promise; + /** + * Method called after an external component is opened. + * + * @param externalComponent The external component which was opened + * @param read An accessor to the environment + * @param http An accessor to the outside world + */ + executePostExternalComponentOpened( + externalComponent: IExternalComponent, + read: IRead, + http: IHttp, + persistence: IPersistence, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IDepartment.ts b/packages/apps-engine/src/definition/livechat/IDepartment.ts index 1a59c98356129..f8b92f3d8b077 100644 --- a/packages/apps-engine/src/definition/livechat/IDepartment.ts +++ b/packages/apps-engine/src/definition/livechat/IDepartment.ts @@ -1,17 +1,17 @@ export interface IDepartment { - id: string; - name?: string; - email?: string; - description?: string; - offlineMessageChannelName?: string; - requestTagBeforeClosingChat?: false; - chatClosingTags?: Array; - abandonedRoomsCloseCustomMessage?: string; - waitingQueueMessage?: string; - departmentsAllowedToForward?: string; - enabled: boolean; - updatedAt: Date; - numberOfAgents: number; - showOnOfflineForm: boolean; - showOnRegistration: boolean; + id: string; + name?: string; + email?: string; + description?: string; + offlineMessageChannelName?: string; + requestTagBeforeClosingChat?: false; + chatClosingTags?: Array; + abandonedRoomsCloseCustomMessage?: string; + waitingQueueMessage?: string; + departmentsAllowedToForward?: string; + enabled: boolean; + updatedAt: Date; + numberOfAgents: number; + showOnOfflineForm: boolean; + showOnRegistration: boolean; } diff --git a/packages/apps-engine/src/definition/livechat/ILivechatContact.ts b/packages/apps-engine/src/definition/livechat/ILivechatContact.ts index 20577ac97fea3..24f4955a2faf8 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatContact.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatContact.ts @@ -3,48 +3,48 @@ import type { IVisitorEmail } from './IVisitorEmail'; import type { IVisitorPhone } from './IVisitorPhone'; export interface ILivechatContactVisitorAssociation { - visitorId: string; - source: { - type: OmnichannelSourceType; - id?: IOmnichannelSource['id']; - }; + visitorId: string; + source: { + type: OmnichannelSourceType; + id?: IOmnichannelSource['id']; + }; } export interface ILivechatContactChannel { - name: string; - verified: boolean; - visitor: ILivechatContactVisitorAssociation; - blocked: boolean; - field?: string; - value?: string; - verifiedAt?: Date; - details: IOmnichannelSource; - lastChat?: { - _id: string; - ts: Date; - }; + name: string; + verified: boolean; + visitor: ILivechatContactVisitorAssociation; + blocked: boolean; + field?: string; + value?: string; + verifiedAt?: Date; + details: IOmnichannelSource; + lastChat?: { + _id: string; + ts: Date; + }; } export interface ILivechatContactConflictingField { - field: 'name' | 'manager' | `customFields.${string}`; - value: string; + field: 'name' | 'manager' | `customFields.${string}`; + value: string; } export interface ILivechatContact { - _id: string; - _updatedAt: Date; - name: string; - phones?: IVisitorPhone[]; - emails?: IVisitorEmail[]; - contactManager?: string; - unknown?: boolean; - conflictingFields?: ILivechatContactConflictingField[]; - customFields?: Record; - channels: ILivechatContactChannel[]; - createdAt: Date; - lastChat?: { - _id: string; - ts: Date; - }; - importIds?: string[]; + _id: string; + _updatedAt: Date; + name: string; + phones?: IVisitorPhone[]; + emails?: IVisitorEmail[]; + contactManager?: string; + unknown?: boolean; + conflictingFields?: ILivechatContactConflictingField[]; + customFields?: Record; + channels: ILivechatContactChannel[]; + createdAt: Date; + lastChat?: { + _id: string; + ts: Date; + }; + importIds?: string[]; } diff --git a/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts b/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts index c7c554b8376b5..68e3a7596f87f 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts @@ -3,10 +3,10 @@ import type { IDepartment } from './IDepartment'; import type { ILivechatRoom } from './ILivechatRoom'; export interface ILivechatEventContext { - agent: IUser; - room: ILivechatRoom; + agent: IUser; + room: ILivechatRoom; } export interface ILivechatDepartmentEventContext { - department: IDepartment; + department: IDepartment; } diff --git a/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts b/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts index af5a4423eb966..4c8218c95eb6f 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts @@ -2,6 +2,6 @@ import type { IVisitor } from './IVisitor'; import type { IMessage } from '../messages/IMessage'; export interface ILivechatMessage extends IMessage { - visitor?: IVisitor; - token?: string; + visitor?: IVisitor; + token?: string; } diff --git a/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts b/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts index d4b2be7d0cfb7..8fc640fa7ebba 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts @@ -6,75 +6,75 @@ import type { ILivechatContact } from './ILivechatContact'; import type { IVisitor } from './IVisitor'; export enum OmnichannelSourceType { - WIDGET = 'widget', - EMAIL = 'email', - SMS = 'sms', - APP = 'app', - API = 'api', - OTHER = 'other', + WIDGET = 'widget', + EMAIL = 'email', + SMS = 'sms', + APP = 'app', + API = 'api', + OTHER = 'other', } export interface IOmnichannelSource { - type: OmnichannelSourceType; - // An optional identification of external sources, such as an App - id?: string; - // A human readable alias that goes with the ID, for post analytical purposes - alias?: string; - // A label to be shown in the room info - label?: string; - // The sidebar icon - sidebarIcon?: string; - // The default sidebar icon - defaultIcon?: string; - // The destination of the message (e.g widget host, email address, whatsapp number, etc) - destination?: string; + type: OmnichannelSourceType; + // An optional identification of external sources, such as an App + id?: string; + // A human readable alias that goes with the ID, for post analytical purposes + alias?: string; + // A label to be shown in the room info + label?: string; + // The sidebar icon + sidebarIcon?: string; + // The default sidebar icon + defaultIcon?: string; + // The destination of the message (e.g widget host, email address, whatsapp number, etc) + destination?: string; } interface IOmnichannelSourceApp { - type: 'app'; - // An optional identification of external sources, such as an App - id?: string; - // A human readable alias that goes with the ID, for post analytical purposes - alias?: string; - // A label to be shown in the room info - label?: string; - // The sidebar icon - sidebarIcon?: string; - // The default sidebar icon - defaultIcon?: string; - // The destination of the message (e.g widget host, email address, whatsapp number, etc) - destination?: string; + type: 'app'; + // An optional identification of external sources, such as an App + id?: string; + // A human readable alias that goes with the ID, for post analytical purposes + alias?: string; + // A label to be shown in the room info + label?: string; + // The sidebar icon + sidebarIcon?: string; + // The default sidebar icon + defaultIcon?: string; + // The destination of the message (e.g widget host, email address, whatsapp number, etc) + destination?: string; } export type OmnichannelSource = - | { - type: Exclude; - } - | IOmnichannelSourceApp; + | { + type: Exclude; + } + | IOmnichannelSourceApp; export interface IVisitorChannelInfo { - lastMessageTs?: Date; - phone?: string; + lastMessageTs?: Date; + phone?: string; } export interface ILivechatRoom extends IRoom { - visitor: IVisitor; - visitorChannelInfo?: IVisitorChannelInfo; - department?: IDepartment; - closer: 'user' | 'visitor' | 'bot'; - closedBy?: IUser; - servedBy?: IUser; - responseBy?: IUser; - isWaitingResponse: boolean; - isOpen: boolean; - closedAt?: Date; - source?: OmnichannelSource; - contact?: ILivechatContact; + visitor: IVisitor; + visitorChannelInfo?: IVisitorChannelInfo; + department?: IDepartment; + closer: 'user' | 'visitor' | 'bot'; + closedBy?: IUser; + servedBy?: IUser; + responseBy?: IUser; + isWaitingResponse: boolean; + isOpen: boolean; + closedAt?: Date; + source?: OmnichannelSource; + contact?: ILivechatContact; } export const isLivechatRoom = (room: IRoom): room is ILivechatRoom => { - return room.type === RoomType.LIVE_CHAT; + return room.type === RoomType.LIVE_CHAT; }; export const isLivechatFromApp = (room: ILivechatRoom): room is ILivechatRoom & { source: IOmnichannelSourceApp } => { - return room.source && room.source.type === 'app'; + return room.source && room.source.type === 'app'; }; diff --git a/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts b/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts index dba672ad391b2..3d3dbd2c14005 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts @@ -7,13 +7,13 @@ import type { ILivechatRoom } from './ILivechatRoom'; * @deprecated please prefer the IPostLivechatRoomClosed event */ export interface ILivechatRoomClosedHandler { - /** - * Method called *after* a livechat room is closed. - * - * @param livechatRoom The livechat room which is closed. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persistence An accessor to the App's persistence - */ - [AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER](data: ILivechatRoom, read: IRead, http: IHttp, persistence: IPersistence): Promise; + /** + * Method called *after* a livechat room is closed. + * + * @param livechatRoom The livechat room which is closed. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persistence An accessor to the App's persistence + */ + [AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER](data: ILivechatRoom, read: IRead, http: IHttp, persistence: IPersistence): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts b/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts index 988d0a2ec5fd0..a2321f7a52711 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts @@ -2,7 +2,7 @@ import type { IUser } from '../users'; import type { ILivechatRoom } from './ILivechatRoom'; export interface ILivechatTransferData { - currentRoom: ILivechatRoom; - targetAgent?: IUser; - targetDepartment?: string; + currentRoom: ILivechatRoom; + targetAgent?: IUser; + targetDepartment?: string; } diff --git a/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts b/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts index 74db472751d40..68dedb80c1d7c 100644 --- a/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts +++ b/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts @@ -3,13 +3,13 @@ import type { IUser } from '../users'; import type { IDepartment } from './IDepartment'; export enum LivechatTransferEventType { - AGENT = 'agent', - DEPARTMENT = 'department', + AGENT = 'agent', + DEPARTMENT = 'department', } export interface ILivechatTransferEventContext { - type: LivechatTransferEventType; - room: IRoom; - from: IUser | IDepartment; - to: IUser | IDepartment; + type: LivechatTransferEventType; + room: IRoom; + from: IUser | IDepartment; + to: IUser | IDepartment; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts index 5c322534c9ff1..e4426ee989247 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts @@ -6,20 +6,20 @@ import type { ILivechatEventContext } from './ILivechatEventContext'; * Handler called after the assignment of a livechat agent. */ export interface IPostLivechatAgentAssigned { - /** - * Handler called *after* the assignment of a livechat agent. - * - * @param data the livechat context data which contains agent's info and room's info. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_AGENT_ASSIGNED]( - context: ILivechatEventContext, - read: IRead, - http: IHttp, - persis: IPersistence, - modify?: IModify, - ): Promise; + /** + * Handler called *after* the assignment of a livechat agent. + * + * @param data the livechat context data which contains agent's info and room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_AGENT_ASSIGNED]( + context: ILivechatEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts index 2884cfa94b83e..6af57ab2abbd4 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts @@ -6,20 +6,20 @@ import type { ILivechatEventContext } from './ILivechatEventContext'; * Handler called after the unassignment of a livechat agent. */ export interface IPostLivechatAgentUnassigned { - /** - * Handler called *after* the unassignment of a livechat agent. - * - * @param data the livechat context data which contains agent's info and room's info. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_AGENT_UNASSIGNED]( - context: ILivechatEventContext, - read: IRead, - http: IHttp, - persis: IPersistence, - modify?: IModify, - ): Promise; + /** + * Handler called *after* the unassignment of a livechat agent. + * + * @param data the livechat context data which contains agent's info and room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_AGENT_UNASSIGNED]( + context: ILivechatEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentDisabled.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentDisabled.ts index a08b1d61e446f..5fb5ff698d672 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentDisabled.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentDisabled.ts @@ -6,20 +6,20 @@ import type { ILivechatDepartmentEventContext } from './ILivechatEventContext'; * Handler called after the disablement of a livechat department. */ export interface IPostLivechatDepartmentDisabled { - /** - * Handler called *after* the disablement of a livechat department. - * - * @param data the livechat context data which contains the department disabled - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_DEPARTMENT_DISABLED]( - context: ILivechatDepartmentEventContext, - read: IRead, - http: IHttp, - persis: IPersistence, - modify?: IModify, - ): Promise; + /** + * Handler called *after* the disablement of a livechat department. + * + * @param data the livechat context data which contains the department disabled + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_DEPARTMENT_DISABLED]( + context: ILivechatDepartmentEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentRemoved.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentRemoved.ts index 51a08d81eb88e..113da3d1087ac 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentRemoved.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatDepartmentRemoved.ts @@ -6,20 +6,20 @@ import type { ILivechatDepartmentEventContext } from './ILivechatEventContext'; * Handler called after the removal of a livechat department. */ export interface IPostLivechatDepartmentRemoved { - /** - * Handler called *after* the removal of a livechat department. - * - * @param data the livechat context data which contains the department removed - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_DEPARTMENT_REMOVED]( - context: ILivechatDepartmentEventContext, - read: IRead, - http: IHttp, - persis: IPersistence, - modify?: IModify, - ): Promise; + /** + * Handler called *after* the removal of a livechat department. + * + * @param data the livechat context data which contains the department removed + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_DEPARTMENT_REMOVED]( + context: ILivechatDepartmentEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts index 2c5edc0b9692b..1201af3bb7aab 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts @@ -6,14 +6,20 @@ import type { IVisitor } from './IVisitor'; * Handler called after the guest's info get saved. */ export interface IPostLivechatGuestSaved { - /** - * Handler called *after* the guest's info get saved. - * - * @param data the livechat context data which contains guest's info and room's info. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_GUEST_SAVED](context: IVisitor, read: IRead, http: IHttp, persis: IPersistence, modify: IModify): Promise; + /** + * Handler called *after* the guest's info get saved. + * + * @param data the livechat context data which contains guest's info and room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_GUEST_SAVED]( + context: IVisitor, + read: IRead, + http: IHttp, + persis: IPersistence, + modify: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts index 072e02e8c721b..9fb775ad0ada5 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts @@ -6,14 +6,20 @@ import type { ILivechatRoom } from './ILivechatRoom'; * Handler called after a livechat room is closed. */ export interface IPostLivechatRoomClosed { - /** - * Method called *after* a livechat room is closed. - * - * @param livechatRoom The livechat room which is closed. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_CLOSED](room: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence, modify?: IModify): Promise; + /** + * Method called *after* a livechat room is closed. + * + * @param livechatRoom The livechat room which is closed. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_CLOSED]( + room: ILivechatRoom, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts index 13b6d1cb2e4b4..0b31593784d57 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts @@ -6,14 +6,20 @@ import type { ILivechatRoom } from './ILivechatRoom'; * Handler called after the room's info get saved. */ export interface IPostLivechatRoomSaved { - /** - * Handler called *after* the room's info get saved. - * - * @param data the livechat context data which contains room's info. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_SAVED](context: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence, modify: IModify): Promise; + /** + * Handler called *after* the room's info get saved. + * + * @param data the livechat context data which contains room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_SAVED]( + context: ILivechatRoom, + read: IRead, + http: IHttp, + persis: IPersistence, + modify: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts index 237dcd9566e96..0f8b4bb463578 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts @@ -6,14 +6,20 @@ import type { ILivechatRoom } from './ILivechatRoom'; * Handler called after a livechat room is started. */ export interface IPostLivechatRoomStarted { - /** - * Method called *after* a livechat room is started. - * - * @param livechatRoom The livechat room which is started. - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_STARTED](room: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence, modify?: IModify): Promise; + /** + * Method called *after* a livechat room is started. + * + * @param livechatRoom The livechat room which is started. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_STARTED]( + room: ILivechatRoom, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts index aa86f8d358d36..4f70f942abe9a 100644 --- a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts @@ -3,11 +3,11 @@ import { AppMethod } from '../metadata'; import type { ILivechatTransferEventContext } from './ILivechatTransferEventContext'; export interface IPostLivechatRoomTransferred { - [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_TRANSFERRED]( - context: ILivechatTransferEventContext, - read: IRead, - http: IHttp, - persis: IPersistence, - modify: IModify, - ): Promise; + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_TRANSFERRED]( + context: ILivechatTransferEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify: IModify, + ): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IPreLivechatRoomCreatePrevent.ts b/packages/apps-engine/src/definition/livechat/IPreLivechatRoomCreatePrevent.ts index 3e7ca67307381..700f905f82f7b 100644 --- a/packages/apps-engine/src/definition/livechat/IPreLivechatRoomCreatePrevent.ts +++ b/packages/apps-engine/src/definition/livechat/IPreLivechatRoomCreatePrevent.ts @@ -8,14 +8,14 @@ import type { ILivechatRoom } from './ILivechatRoom'; * To prevent the room from being created, the app should throw an `AppsEngineException` */ export interface IPreLivechatRoomCreatePrevent { - /** - * Method called *before* a livechat room is created. - * - * @param livechatRoom The livechat room which is about to be created - * @param read An accessor to the environment - * @param http An accessor to the outside world - * @param persis An accessor to the App's persistence - * @param modify An accessor to the modifier - */ - [AppMethod.EXECUTE_PRE_LIVECHAT_ROOM_CREATE_PREVENT](room: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence): Promise; + /** + * Method called *before* a livechat room is created. + * + * @param livechatRoom The livechat room which is about to be created + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_PRE_LIVECHAT_ROOM_CREATE_PREVENT](room: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence): Promise; } diff --git a/packages/apps-engine/src/definition/livechat/IVisitor.ts b/packages/apps-engine/src/definition/livechat/IVisitor.ts index db5876dd912d3..64445df8ae5da 100644 --- a/packages/apps-engine/src/definition/livechat/IVisitor.ts +++ b/packages/apps-engine/src/definition/livechat/IVisitor.ts @@ -2,15 +2,15 @@ import type { IVisitorEmail } from './IVisitorEmail'; import type { IVisitorPhone } from './IVisitorPhone'; export interface IVisitor { - id?: string; - token: string; - username: string; - updatedAt?: Date; - name: string; - department?: string; - phone?: Array; - visitorEmails?: Array; - status?: string; - customFields?: { [key: string]: any }; - livechatData?: { [key: string]: any }; + id?: string; + token: string; + username: string; + updatedAt?: Date; + name: string; + department?: string; + phone?: Array; + visitorEmails?: Array; + status?: string; + customFields?: { [key: string]: any }; + livechatData?: { [key: string]: any }; } diff --git a/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts b/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts index a1e35380666e4..8a97c82bf4de1 100644 --- a/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts +++ b/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts @@ -1,3 +1,3 @@ export interface IVisitorEmail { - address: string; + address: string; } diff --git a/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts b/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts index fe112777e7d7c..9b839a49504f3 100644 --- a/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts +++ b/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts @@ -1,3 +1,3 @@ export interface IVisitorPhone { - phoneNumber: string; + phoneNumber: string; } diff --git a/packages/apps-engine/src/definition/livechat/index.ts b/packages/apps-engine/src/definition/livechat/index.ts index 4533df149fd20..a34151da53317 100644 --- a/packages/apps-engine/src/definition/livechat/index.ts +++ b/packages/apps-engine/src/definition/livechat/index.ts @@ -21,26 +21,26 @@ import { IVisitorEmail } from './IVisitorEmail'; import { IVisitorPhone } from './IVisitorPhone'; export { - ILivechatEventContext, - ILivechatMessage, - ILivechatRoom, - IPostLivechatAgentAssigned, - IPreLivechatRoomCreatePrevent, - ILivechatContact, - IPostLivechatAgentUnassigned, - IPostLivechatGuestSaved, - IPostLivechatRoomStarted, - IPostLivechatRoomClosed, - IPostLivechatRoomSaved, - IPostLivechatRoomTransferred, - ILivechatRoomClosedHandler, - ILivechatTransferData, - ILivechatTransferEventContext, - IDepartment, - IVisitor, - IVisitorEmail, - IVisitorPhone, - LivechatTransferEventType, - IPostLivechatDepartmentRemoved, - IPostLivechatDepartmentDisabled, + ILivechatEventContext, + ILivechatMessage, + ILivechatRoom, + IPostLivechatAgentAssigned, + IPreLivechatRoomCreatePrevent, + ILivechatContact, + IPostLivechatAgentUnassigned, + IPostLivechatGuestSaved, + IPostLivechatRoomStarted, + IPostLivechatRoomClosed, + IPostLivechatRoomSaved, + IPostLivechatRoomTransferred, + ILivechatRoomClosedHandler, + ILivechatTransferData, + ILivechatTransferEventContext, + IDepartment, + IVisitor, + IVisitorEmail, + IVisitorPhone, + LivechatTransferEventType, + IPostLivechatDepartmentRemoved, + IPostLivechatDepartmentDisabled, }; diff --git a/packages/apps-engine/src/definition/messages/IMessage.ts b/packages/apps-engine/src/definition/messages/IMessage.ts index 50d36f9d5db2f..abf6f57be2473 100644 --- a/packages/apps-engine/src/definition/messages/IMessage.ts +++ b/packages/apps-engine/src/definition/messages/IMessage.ts @@ -9,28 +9,28 @@ import type { IMessageReactions } from './IMessageReaction'; import type { MessageType } from './MessageType'; export interface IMessage { - id?: string; - threadId?: string; - room: IRoom; - sender: IUser; - text?: string; - createdAt?: Date; - updatedAt?: Date; - editor?: IUser; - editedAt?: Date; - emoji?: string; - avatarUrl?: string; - alias?: string; - file?: IMessageFile; - attachments?: Array; - reactions?: IMessageReactions; - groupable?: boolean; - parseUrls?: boolean; - customFields?: { [key: string]: any }; - blocks?: Array; - starred?: Array<{ _id: string }>; - pinned?: boolean; - pinnedAt?: Date; - pinnedBy?: IUserLookup; - type?: MessageType; + id?: string; + threadId?: string; + room: IRoom; + sender: IUser; + text?: string; + createdAt?: Date; + updatedAt?: Date; + editor?: IUser; + editedAt?: Date; + emoji?: string; + avatarUrl?: string; + alias?: string; + file?: IMessageFile; + attachments?: Array; + reactions?: IMessageReactions; + groupable?: boolean; + parseUrls?: boolean; + customFields?: { [key: string]: any }; + blocks?: Array; + starred?: Array<{ _id: string }>; + pinned?: boolean; + pinnedAt?: Date; + pinnedBy?: IUserLookup; + type?: MessageType; } diff --git a/packages/apps-engine/src/definition/messages/IMessageAction.ts b/packages/apps-engine/src/definition/messages/IMessageAction.ts index 3f32e4aa781d7..5e44f425e6cc6 100644 --- a/packages/apps-engine/src/definition/messages/IMessageAction.ts +++ b/packages/apps-engine/src/definition/messages/IMessageAction.ts @@ -5,13 +5,13 @@ import type { MessageProcessingType } from './MessageProcessingType'; * Interface which represents an action which can be added to a message. */ export interface IMessageAction { - type: MessageActionType; - text?: string; - url?: string; - image_url?: string; - is_webview?: boolean; - webview_height_ratio?: string; - msg?: string; - msg_in_chat_window?: boolean; - msg_processing_type?: MessageProcessingType; + type: MessageActionType; + text?: string; + url?: string; + image_url?: string; + is_webview?: boolean; + webview_height_ratio?: string; + msg?: string; + msg_in_chat_window?: boolean; + msg_processing_type?: MessageProcessingType; } diff --git a/packages/apps-engine/src/definition/messages/IMessageAttachment.ts b/packages/apps-engine/src/definition/messages/IMessageAttachment.ts index 96dd8aa1fe34e..7f0875fe07cea 100644 --- a/packages/apps-engine/src/definition/messages/IMessageAttachment.ts +++ b/packages/apps-engine/src/definition/messages/IMessageAttachment.ts @@ -8,36 +8,36 @@ import type { MessageActionButtonsAlignment } from './MessageActionButtonsAlignm * Interface which represents an attachment which can be added to a message. */ export interface IMessageAttachment { - /** Causes the image, audio, and video sections to be hidding when this is true. */ - collapsed?: boolean; - /** The color you want the order on the left side to be, supports any valid background-css value. */ - color?: string; // TODO: Maybe we change this to a Color class which has helper methods? - /** The text to display for this attachment. */ - text?: string; - /** Displays the time next to the text portion. */ - timestamp?: Date; - /** Only applicable if the timestamp is provided, as it makes the time clickable to this link. */ - timestampLink?: string; - /** An image that displays to the left of the text, looks better when this is relatively small. */ - thumbnailUrl?: string; - /** Author portion of the attachment. */ - author?: IMessageAttachmentAuthor; - /** Title portion of the attachment. */ - title?: IMessageAttachmentTitle; - /** The image to display, will be "big" and easy to see. */ - imageUrl?: string; - /** Audio file to play, only supports what html's