Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3 #120

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

V3 #120

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 33 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,21 @@ Adventure quest game by [@Teoreez](https://github.com/Teoreez)

#### Getting Started

```javascript
const { Alice, Reply, Markup } = require('yandex-dialogs-sdk')
```js
const { Alice, render } = require('yandex-dialogs-sdk')

const alice = new Alice();
const { reply, pause, buttons } = render

const M = Markup;
alice.command('', async ctx => Reply.text('Look, what i can!'));
alice.command('Give a piece of advice', async ctx =>
Reply.text('Make const not var'),
);
alice.command('', async ctx => {
return reply`
${['Здравствуйте', 'Добрый день']}! ${pause(500)} Как дел+а?
${buttons(['Отлично', 'Супер'])}
`
});
alice.command('Give a piece of advice', async ctx => {
return reply`Make const not var`
});
alice.command(
['What is trending now?', 'Watch films', 'Whats in the theatre?'],
ctx => {
Expand All @@ -53,15 +59,21 @@ alice.command(
};
},
);
alice.command(/(https?:\/\/[^\s]+)/g, ctx => Reply.text('Matched a link!'));
alice.any(async ctx => Reply.text(`I don't understand`));
alice.command(/(https?:\/\/[^\s]+)/g, ctx => reply`Matched a link!`));
alice.any(async ctx => {
return reply`I don't understand`
});
const server = alice.listen(3001, '/');
```

#### Hot middlewares from maintainer
```js
const { render } = require('yandex-dialogs-sdk')
const { reply, pause, buttons } = render
```
This library uses [https://github.com/vitalets/alice-renderer](https://github.com/vitalets/alice-renderer) for rendering.

Full documentation is [here](https://github.com/vitalets/alice-renderer)

- **[yandex-dialogs-sdk-lowdb](https://github.com/fletcherist/yandex-dialogs-sdk-lowdb)** - store your users sessions in file
- **[yandex-dialogs-sdk-chatbase](https://github.com/popstas/yandex-dialogs-sdk-chatbase)** - send events to Google Chatbase by **[@popstas](https://github.com/popstas)**

#### Handle non-trivial scenarios

Expand All @@ -72,11 +84,11 @@ const alice = new Alice();
const SCENE_AT_BAR = 'SCENE_AT_BAR';
const atBar = new Scene(SCENE_AT_BAR);

atBar.command('show menu', ctx =>
Reply.text('only vodka here', {
atBar.command('show menu', ctx => {
return Reply.text('only vodka here', {
buttons: ['buy vodka', 'go away'],
}),
);
}),
});
atBar.command('buy vodka', ctx => Reply.text(`you're dead`));
atBar.command('go away', ctx => {
ctx.leave();
Expand Down Expand Up @@ -194,45 +206,11 @@ const createMessagesCounterMiddleware = () => {
alice.use(createMessagesCounterMiddleware())
```

###### Reply
```javascript
const { Reply } = require('yandex-dialogs-sdk')
IMAGE_ID = '213044/d13b0d86a41daf9de232'
EXTRA_PARAMS = { // Extra params are optional
tts: 'Hi the+re',
buttons: ['one', Markup.button('two')],
end_session: true
}
```
- `Reply.text`
```javascript
// Second argument is optional
alice.any(ctx => Reply.text('text'), EXTRA_PARAMS)
```
- `Reply.bigImageCard` - One big image
```javascript
Reply.bigImageCard('text', {
image_id: IMAGE_ID,
title: string, // optional
description: string, // optional
button: M.button('click'), // optional
}, EXTRA_PARAMS)
```
- `Reply.itemsListCard` - Gallery
```javascript
Reply.itemsListCard('text', [IMAGE_ID, IMAGE_ID], EXTRA_PARAMS);
Reply.itemsListCard('test', {
header: 'header',
footer: {
text: 'test',
button: Markup.button('button'),
},
items: [
IMAGE_ID,
{ image_id: IMAGE_ID, title: 'title', description: 'description' },
],
});
```
#### Hot middlewares

- **[yandex-dialogs-sdk-lowdb](https://github.com/fletcherist/yandex-dialogs-sdk-lowdb)** - store your users sessions in file
- **[yandex-dialogs-sdk-chatbase](https://github.com/popstas/yandex-dialogs-sdk-chatbase)** - send events to Google Chatbase by **[@popstas](https://github.com/popstas)**


###### Events
```javascript
Expand All @@ -244,21 +222,6 @@ alice.on('response', ctx => {
```


###### Markup
```javascript
const { Markup } = require('yandex-dialogs-sdk')
```
- `Markup.button`
```javascript
const M = Markup
M.button('string')
M.button({
title: string;
url: string;
payload: object;
hide: boolean;
})
```

## CONTRIBUTING
`git clone`
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"@types/node-fetch": "^2.1.2",
"fast-levenshtein": "^2.0.6",
"node-fetch": "^2.1.2",
"debug": "^4.1.0"
"debug": "^4.1.0",
"alice-renderer": "1.0.0"
},
"devDependencies": {
"@types/debug": "0.0.31",
Expand All @@ -72,9 +73,8 @@
"npm-run-all": "^4.1.3",
"shx": "^0.3.2",
"sinon": "^7.1.0",
"ts-jest": "^23.0.0",
"tslint": "^5.10.0",
"typescript": "^3.0.1",
"ts-jest": "25.4.0",
"typescript": "3.8.3",
"vrsource-tslint-rules": "^5.8.2"
}
}
78 changes: 78 additions & 0 deletions src/alice-renderer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
declare module 'alice-renderer' {
Copy link

@shining-mind shining-mind May 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declared Response interface is not-compatible with ApiResponseBody as a result tests won't work with the new reply.

I've tried to fix this issue in forked repo by declaring API as ambient module and importing API types here, but I can't find a good solution how to ship this types with NPM package. It seems that *.d.ts files added to dist folder won't be resolved by the typescript compiler if package is used as dependency.

export interface Button {
title: string;
url?: string;
payload?: string;
hide?: boolean;
}

export interface Response {
text: string;
tts?: string;
card?: {
type: 'BigImage';
image_id?: string;
title?: string;
descriptions?: string;
};
buttons?: Button[];
end_session: boolean;
}

export function reply(stringParts: string[]): Response;
export function buttons(
items: Array<string | Button>,
defaults?: Button,
): Button[];
export function audio(name: string): void;
export function effect(name: string): void;
export function pause(ms?: number): void;
export function br(count?: number): void;
export function text(value: string | string[]): void;
export function tts(value: string | string[]): void;
export function textTts(
textValue: string | string[],
ttsValue: string | string[],
): void;
export function plural(
number: number,
one: string,
two: string,
five: string,
): void;
export function enumerate(list: any[]): void;

export function userify(userId: string, target: typeof reply): typeof reply;
export function userify(
userId: string,
target: { [key: string]: typeof reply },
): { [key: string]: typeof reply };

export function select(array: string[]): string;

export function once(
options: {
calls?: number;
seconds?: number;
leading: boolean;
},
response: any,
): void;

export function configure(options: { disableRandom?: boolean }): void;

export function image(
imageId: string,
options?: {
title?: string;
description?: string;
appendDescription?: string;
button?: Button;
},
): {
type: 'BigImage';
image_id: string;
title?: string;
description?: string;
};
}
59 changes: 21 additions & 38 deletions src/alice.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,38 @@
import { EventEmitter } from 'events';

import { IImagesApiConfig, IImagesApi, ImagesApi } from './imagesApi';
import { WebhookServer, IWebhookServer } from './server/webhookServer';
import { ImagesApiConfig, ImagesApi } from './imagesApi';
import { WebhookServer } from './server/webhookServer';
import { Middleware } from './middleware/middleware';
import { IApiRequest } from './api/request';
import { IContext } from './context';
import { IApiResponse } from './api/response';
import { ApiRequest } from './api/request';
import { Context } from './context';
import { ApiResponse } from './api/response';
import { ALICE_PROTOCOL_VERSION } from './constants';
import { CommandCallback, CommandDeclaration } from './command/command';
import { InMemorySessionStorage } from './session/inMemorySessionStorage';
import { sessionMiddleware } from './session/sessionMiddleware';
import debug from './debug';

import { MainStage } from './stage/mainScene';
import { ISessionStorage } from './session/session';
import { IScene } from './stage/scene';
import { Scene } from './stage/scene';

export interface IAliceConfig extends IImagesApiConfig {
sessionStorage?: ISessionStorage;
}

export interface IAlice {
readonly imagesApi: IImagesApi;
handleRequest(data: IApiRequest): Promise<IApiResponse>;
use(middleware: Middleware): void;
listen(port: number, webhookUrl: string, options: object): IWebhookServer;
}
export type AliceConfig = ImagesApiConfig

export class Alice implements IAlice {
private readonly _config: IAliceConfig;
export class Alice {
private readonly _config: AliceConfig;
private readonly _middlewares: Middleware[];
private readonly _imagesApi: IImagesApi;
private readonly _imagesApi: ImagesApi;
private readonly _mainStage: MainStage;
private readonly _sessionStorage: ISessionStorage;
private _eventEmitter: EventEmitter;

constructor(config: IAliceConfig = {}) {
constructor(config: AliceConfig = {}) {
this._eventEmitter = new EventEmitter();
this._config = config;
this.handleRequest = this.handleRequest.bind(this);

this._middlewares = [];
this._imagesApi = new ImagesApi(this._config);
this._mainStage = new MainStage();

this._sessionStorage =
config.sessionStorage || new InMemorySessionStorage();
this.use(sessionMiddleware(this._sessionStorage));
}

private _buildContext(request: IApiRequest): IContext {
private _buildContext(request: ApiRequest): Context {
return {
data: request,
message: request.request.command,
Expand All @@ -62,7 +45,7 @@ export class Alice implements IAlice {
};
}

private async _runMiddlewares(context: IContext): Promise<IContext> {
private async _runMiddlewares(context: Context): Promise<Context> {
const middlewares = Array.from(this._middlewares);
// mainStage middleware should always be the latest one
middlewares.push(this._mainStage.middleware);
Expand All @@ -71,7 +54,7 @@ export class Alice implements IAlice {
}

let index = 0;
const next = async (middlewareContext: IContext): Promise<IContext> => {
const next = async (middlewareContext: Context): Promise<Context> => {
const middleware = middlewares[index];
index++;
return middleware(
Expand All @@ -82,11 +65,11 @@ export class Alice implements IAlice {
return next(context);
}

get imagesApi(): IImagesApi {
get imagesApi(): ImagesApi {
return this._imagesApi;
}

public async handleRequest(data: IApiRequest): Promise<IApiResponse> {
public async handleRequest(data: ApiRequest): Promise<ApiResponse> {
if (data.version !== ALICE_PROTOCOL_VERSION) {
throw new Error('Unknown protocol version');
}
Expand Down Expand Up @@ -140,23 +123,23 @@ export class Alice implements IAlice {
}

public command(
declaration: CommandDeclaration<IContext>,
callback: CommandCallback<IContext>,
declaration: CommandDeclaration,
callback: CommandCallback,
): void {
this._mainStage.scene.command(declaration, callback);
}

public any(callback: CommandCallback<IContext>): void {
public any(callback: CommandCallback): void {
this._mainStage.scene.any(callback);
}

public registerScene(scene: IScene): void {
public registerScene(scene: Scene): void {
this._mainStage.stage.addScene(scene);
}

public on(
type: 'response' | 'request',
callback: (context: IContext) => any,
callback: (context: Context) => any,
): void {
this._eventEmitter.addListener(type, callback);
}
Expand Down
8 changes: 4 additions & 4 deletions src/api/image.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
export interface IApiImageItem {
export interface ApiImageItem {
id: string;
origUrl?: string;
}

export interface IApiImageUploadResponse {
image: IApiImageItem;
export interface ApiImageUploadResponse {
image: ApiImageItem;
}

export interface IApiImageListResponse {
images: IApiImageItem[];
images: ApiImageItem[];
}

export interface IApiImageQuotaResponse {
Expand Down
Loading