diff --git a/.bazelrc b/.bazelrc index 4175338085..a697abf6a2 100644 --- a/.bazelrc +++ b/.bazelrc @@ -3,7 +3,13 @@ build --strategy=TypeScriptCompile=worker # Use java 11 -build --java_toolchain=@bazel_tools//tools/jdk:toolchain_java11 --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java11 --workspace_status_command=tools/build/bazel_status.sh +build --java_toolchain=@bazel_tools//tools/jdk:toolchain_java11 --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java11 +# Remove once annotation processing fix is released (https://github.com/bazelbuild/bazel/issues/12837) +build --nojava_header_compilation + +# Stamp version and commit +build --stamp --workspace_status_command=tools/build/bazel_status.sh + # Output test errors by default test --test_output=errors diff --git a/.bazelversion b/.bazelversion index 1545d96657..fcdb2e109f 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -3.5.0 +4.0.0 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f186c7500c..7356087a53 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -54,7 +54,7 @@ jobs: env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' - name: Upload airy binary to S3 - if: startsWith(github.ref, 'refs/heads/release') || startsWith(github.ref, 'refs/heads/main') || startsWith(github.ref, 'refs/heads/develop') + if: startsWith(github.ref, 'refs/heads/release') || startsWith(github.ref, 'refs/heads/main') run: | aws s3 cp bazel-bin/infrastructure/cli/airy_linux_bin s3://airy-core-binaries/`cat ./VERSION`/linux/amd64/airy aws s3 cp bazel-bin/infrastructure/cli/airy_darwin_bin s3://airy-core-binaries/`cat ./VERSION`/darwin/amd64/airy @@ -62,3 +62,10 @@ jobs: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: Upload airy binary to S3 [develop] + if: startsWith(github.ref, 'refs/heads/develop') + run: | + aws s3 cp bazel-bin/infrastructure/cli/airy_linux_bin s3://airy-core-binaries/develop/linux/amd64/airy + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 91a60c8ca6..1c9fbbb797 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ # Editors and IDE's -!.ijwb/.idea/fileTemplates/ - .idea/ .code/ .vscode/ diff --git a/.ijwb/.idea/fileTemplates/Stream App.java b/.ijwb/.idea/fileTemplates/Stream App.java deleted file mode 100644 index 489b70dcd7..0000000000 --- a/.ijwb/.idea/fileTemplates/Stream App.java +++ /dev/null @@ -1,41 +0,0 @@ -#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end - -import co.airy.kafka.streams.KafkaStreamsWrapper; -import co.airy.log.AiryLoggerFactory; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.slf4j.Logger; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.context.event.ApplicationStartedEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; - -@Component -public class ${NAME} implements ApplicationListener, DisposableBean { - private final Logger log = AiryLoggerFactory.getLogger(Resolver.class); - private static final String appId = "#[[$AppId$]]#"; - private final KafkaStreamsWrapper streams; - - public ${NAME}(KafkaStreamsWrapper streams) { - this.streams = streams; - } - - @Override - public void onApplicationEvent(ApplicationStartedEvent event) { - final StreamsBuilder builder = new StreamsBuilder(); - #[[$END$]]# - streams.start(builder.build(), appId); - } - - @Override - public void destroy() { - if (streams != null) { - streams.close(); - } - } - - // Visible for testing - KafkaStreams.State getStreamState() { - return streams.state(); - } -} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..22f3139f67 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +docs/docs/cli/*.md diff --git a/BUILD b/BUILD index 10e30e5293..74ee504d57 100644 --- a/BUILD +++ b/BUILD @@ -6,6 +6,11 @@ load("@io_bazel_rules_go//go:def.bzl", "TOOLS_NOGO", "nogo") package(default_visibility = ["//visibility:public"]) +alias( + name = "tsconfig.json", + actual = "//:bazel.tsconfig.json", +) + multirun( name = "fix", commands = [ @@ -163,8 +168,8 @@ exports_files( [ "package.json", ".prettierrc.json", + ".prettierignore", "yarn.lock", - "tsconfig.json", ], ) diff --git a/README.md b/README.md index 4841d2f2af..4c46e417f3 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ The bootstrap installation requires [Vagrant](https://www.vagrantup.com/downloads) and [VirtualBox](https://www.virtualbox.org/wiki/Downloads). If they are not found, the script will attempt to install them for you. Check out our [test -deployment guide](/docs/docs/guides/airy-core-in-test-env.md) for detailed information. +deployment guide](/docs/docs/getting-started/deployment/test-environment.md) for detailed information. ## Components @@ -95,9 +95,9 @@ The Airy Core Platform contains the following components: Kafka](https://kafka.apache.org) to process incoming webhook data from different sources. We make sense of the data and reshape it into source independent contacts, conversations, and messages (see our - [glossary](/docs/docs/glossary.md) for formal definitions). + [glossary](/docs/getting-started/glossary.md) for formal definitions). -- An [API](/docs/docs/api/http.md) to manage the data sets the platform +- An [API](/docs/docs/api/http/introduction.md) to manage the data sets the platform handles. - A webhook integration server that allows its users to programmatically diff --git a/VERSION b/VERSION index a918a2aa18..faef31a435 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.0 +0.7.0 diff --git a/WORKSPACE b/WORKSPACE index fa8ef5d216..51ee8fa4ba 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -10,7 +10,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") git_repository( name = "com_github_airyhq_bazel_tools", - commit = "fd79bd3344b9c95a09eaa94597a49069f943e089", + commit = "cdb56bffd21ea94fe909394a2c7321135dfd506f", remote = "https://github.com/airyhq/bazel-tools.git", shallow_since = "1607079534 +0100", ) @@ -34,7 +34,6 @@ maven_install( "com.google.auth:google-auth-library-oauth2-http:0.20.0", "com.jayway.jsonpath:json-path:2.4.0", "com.twilio.sdk:twilio:7.51.0", - "cz.habarta.typescript-generator:typescript-generator-core:2.26.723", "io.confluent:kafka-avro-serializer:5.5.1", "io.confluent:kafka-schema-registry-client:5.5.1", "io.confluent:kafka-schema-registry:5.5.1", diff --git a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java index 6977821c0c..1bd872f298 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java @@ -4,7 +4,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; import java.util.Map; @RestController diff --git a/backend/api/admin/src/main/java/co/airy/core/api/config/ServiceDiscovery.java b/backend/api/admin/src/main/java/co/airy/core/api/config/ServiceDiscovery.java index 404921a692..90e5ef6f0f 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/config/ServiceDiscovery.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/config/ServiceDiscovery.java @@ -1,10 +1,8 @@ package co.airy.core.api.config; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; diff --git a/backend/api/auth/src/main/java/co/airy/core/api/auth/controllers/UsersController.java b/backend/api/auth/src/main/java/co/airy/core/api/auth/controllers/UsersController.java index 153faf9aea..9c4634f78f 100644 --- a/backend/api/auth/src/main/java/co/airy/core/api/auth/controllers/UsersController.java +++ b/backend/api/auth/src/main/java/co/airy/core/api/auth/controllers/UsersController.java @@ -15,10 +15,10 @@ import co.airy.core.api.auth.dto.User; import co.airy.core.api.auth.services.Mail; import co.airy.core.api.auth.services.Password; -import co.airy.spring.web.payload.EmptyResponsePayload; -import co.airy.spring.web.payload.RequestErrorResponsePayload; import co.airy.spring.auth.IgnoreAuthPattern; import co.airy.spring.jwt.Jwt; +import co.airy.spring.web.payload.EmptyResponsePayload; +import co.airy.spring.web.payload.RequestErrorResponsePayload; import org.jdbi.v3.core.statement.UnableToExecuteStatementException; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpStatus; diff --git a/backend/api/communication/BUILD b/backend/api/communication/BUILD index 3391e22829..3092b59af6 100644 --- a/backend/api/communication/BUILD +++ b/backend/api/communication/BUILD @@ -11,7 +11,6 @@ app_deps = [ "//backend/model/channel", "//backend/model/metadata", "//backend:read-receipt", - "//lib/java/mapping", "//lib/java/date", "//lib/java/pagination", "//lib/java/spring/auth:spring-auth", diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/ConversationsController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/ConversationsController.java index a5c63448f5..b97d846583 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/ConversationsController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/ConversationsController.java @@ -1,13 +1,11 @@ package co.airy.core.api.communication; import co.airy.avro.communication.Metadata; -import co.airy.core.api.communication.lucene.ExtendedQueryParser; -import co.airy.model.metadata.MetadataKeys; -import co.airy.model.metadata.Subject; import co.airy.avro.communication.ReadReceipt; import co.airy.core.api.communication.dto.Conversation; import co.airy.core.api.communication.dto.ConversationIndex; import co.airy.core.api.communication.dto.LuceneQueryResult; +import co.airy.core.api.communication.lucene.ExtendedQueryParser; import co.airy.core.api.communication.lucene.ReadOnlyLuceneStore; import co.airy.core.api.communication.payload.ConversationByIdRequestPayload; import co.airy.core.api.communication.payload.ConversationListRequestPayload; @@ -15,6 +13,8 @@ import co.airy.core.api.communication.payload.ConversationResponsePayload; import co.airy.core.api.communication.payload.ConversationTagRequestPayload; import co.airy.core.api.communication.payload.ResponseMetadata; +import co.airy.model.metadata.MetadataKeys; +import co.airy.model.metadata.Subject; import co.airy.pagination.Page; import co.airy.pagination.Paginator; import co.airy.spring.web.payload.EmptyResponsePayload; @@ -23,7 +23,6 @@ import org.apache.kafka.streams.state.ReadOnlyKeyValueStore; import org.apache.lucene.analysis.core.WhitespaceAnalyzer; import org.apache.lucene.queryparser.classic.ParseException; -import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.Query; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -112,7 +111,7 @@ private ResponseEntity queryConversations(ConversationListRequestPayload requ private ResponseEntity listConversations(ConversationListRequestPayload requestPayload) { final List conversations = fetchAllConversations(); int totalSize = conversations.size(); - conversations.sort(comparing(conversation -> ((Conversation) conversation).getLastMessage().getSentAt()).reversed()); + conversations.sort(comparing(conversation -> ((Conversation) conversation).getLastMessageContainer().getMessage().getSentAt()).reversed()); final Paginator paginator = new Paginator<>(conversations, Conversation::getId) .from(requestPayload.getCursor()).perPage(requestPayload.getPageSize()); diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/Mapper.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/Mapper.java index ec914f15bd..106822b9c5 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/Mapper.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/Mapper.java @@ -1,34 +1,26 @@ package co.airy.core.api.communication; import co.airy.avro.communication.Message; -import co.airy.model.metadata.MetadataKeys; -import co.airy.model.metadata.MetadataRepository; -import co.airy.model.channel.ChannelPayload; import co.airy.core.api.communication.dto.Conversation; import co.airy.core.api.communication.dto.DisplayName; +import co.airy.core.api.communication.dto.MessageContainer; import co.airy.core.api.communication.payload.ContactResponsePayload; import co.airy.core.api.communication.payload.ConversationResponsePayload; import co.airy.core.api.communication.payload.MessageResponsePayload; -import co.airy.mapping.ContentMapper; +import co.airy.model.channel.ChannelPayload; +import co.airy.model.metadata.MetadataKeys; import org.springframework.stereotype.Component; import java.util.Map; -import static co.airy.model.metadata.MetadataRepository.getConversationInfo; import static co.airy.date.format.DateFormat.isoFromMillis; -import static java.util.stream.Collectors.toList; +import static co.airy.model.metadata.MetadataRepository.getConversationInfo; +import static co.airy.model.message.MessageRepository.resolveContent; @Component public class Mapper { - private final ContentMapper contentMapper; - - Mapper(ContentMapper contentMapper) { - this.contentMapper = contentMapper; - } public ConversationResponsePayload fromConversation(Conversation conversation) { - final Map metadata = conversation.getMetadata(); - return ConversationResponsePayload.builder() .channel(ChannelPayload.builder() .id(conversation.getChannelId()) @@ -37,16 +29,10 @@ public ConversationResponsePayload fromConversation(Conversation conversation) { .build()) .id(conversation.getId()) .unreadMessageCount(conversation.getUnreadMessageCount()) - .tags( - MetadataRepository.filterPrefix(metadata, MetadataKeys.TAGS) - .keySet() - .stream() - .map(s -> s.split("\\.")[1]) - .collect(toList()) - ) + .tags(conversation.getTagIds()) .createdAt(isoFromMillis(conversation.getCreatedAt())) .contact(getContact(conversation)) - .lastMessage(fromMessage(conversation.getLastMessage())) + .lastMessage(fromMessageContainer(conversation.getLastMessageContainer())) .build(); } @@ -61,9 +47,10 @@ private ContactResponsePayload getContact(Conversation conversation) { .build(); } - public MessageResponsePayload fromMessage(Message message) { + public MessageResponsePayload fromMessageContainer(MessageContainer messageContainer) { + final Message message = messageContainer.getMessage(); return MessageResponsePayload.builder() - .content(contentMapper.renderWithDefaultAndLog(message)) + .content(resolveContent(message, messageContainer.getMetadataMap())) .senderType(message.getSenderType().toString().toLowerCase()) .deliveryState(message.getDeliveryState().toString().toLowerCase()) .id(message.getId()) diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/MessagesController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/MessagesController.java index 452bbaca25..c8740bf41d 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/MessagesController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/MessagesController.java @@ -1,6 +1,6 @@ package co.airy.core.api.communication; -import co.airy.avro.communication.Message; +import co.airy.core.api.communication.dto.MessageContainer; import co.airy.core.api.communication.payload.MessageListRequestPayload; import co.airy.core.api.communication.payload.MessageListResponsePayload; import co.airy.pagination.Page; @@ -41,18 +41,19 @@ ResponseEntity messageList(@RequestBody @Valid Messa } private MessageListResponsePayload fetchMessages(String conversationId, int pageSize, String cursor) { - final List messages = stores.getMessages(conversationId); + final List messages = stores.getMessages(conversationId); if (messages == null) { return null; } - Paginator paginator = new Paginator<>(messages, Message::getId).perPage(pageSize).from(cursor); + Paginator paginator = new Paginator<>(messages, (message) -> message.getMessage().getId()) + .perPage(pageSize).from(cursor); - Page page = paginator.page(); + Page page = paginator.page(); return MessageListResponsePayload.builder() - .data(page.getData().stream().map(mapper::fromMessage).collect(toList())) + .data(page.getData().stream().map(mapper::fromMessageContainer).collect(toList())) .responseMetadata(MessageListResponsePayload.ResponseMetadata.builder() .nextCursor(page.getNextCursor()) .previousCursor(cursor) diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/MetadataController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/MetadataController.java index 8ac527219b..ffdff2549c 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/MetadataController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/MetadataController.java @@ -1,9 +1,9 @@ package co.airy.core.api.communication; import co.airy.avro.communication.Metadata; -import co.airy.model.metadata.Subject; import co.airy.core.api.communication.payload.RemoveMetadataRequestPayload; import co.airy.core.api.communication.payload.SetMetadataRequestPayload; +import co.airy.model.metadata.Subject; import co.airy.spring.web.payload.EmptyResponsePayload; import co.airy.spring.web.payload.RequestErrorResponsePayload; import org.springframework.http.HttpStatus; diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java index 572d415816..fa8601faef 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java @@ -6,6 +6,7 @@ import co.airy.avro.communication.Message; import co.airy.avro.communication.SenderType; import co.airy.core.api.communication.dto.Conversation; +import co.airy.core.api.communication.dto.MessageContainer; import co.airy.core.api.communication.payload.SendMessageRequestPayload; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.spring.web.payload.EmptyResponsePayload; @@ -72,6 +73,6 @@ public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPaylo producer.send(new ProducerRecord<>(applicationCommunicationMessages.name(), message.getId(), message)).get(); - return ResponseEntity.ok(mapper.fromMessage(message)); + return ResponseEntity.ok(mapper.fromMessageContainer(new MessageContainer(message, Map.of()))); } } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/Stores.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/Stores.java index 15c56269ca..8392f8b3bd 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/Stores.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/Stores.java @@ -7,6 +7,7 @@ import co.airy.avro.communication.SenderType; import co.airy.core.api.communication.dto.Conversation; import co.airy.core.api.communication.dto.CountAction; +import co.airy.core.api.communication.dto.MessageContainer; import co.airy.core.api.communication.dto.MessagesTreeSet; import co.airy.core.api.communication.dto.UnreadCountState; import co.airy.core.api.communication.lucene.IndexingProcessor; @@ -43,11 +44,13 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ExecutionException; import static co.airy.model.metadata.MetadataRepository.getId; import static co.airy.model.metadata.MetadataRepository.getSubject; import static co.airy.model.metadata.MetadataRepository.isConversationMetadata; +import static co.airy.model.metadata.MetadataRepository.isMessageMetadata; import static java.util.stream.Collectors.toCollection; @Component @@ -82,16 +85,16 @@ private void startStream() { builder.addStateStore(new LuceneDiskStore.Builder(conversationsLuceneStore, luceneProvider)); - final KStream messageStream = builder.stream(new ApplicationCommunicationMessages().name()) - .selectKey((messageId, message) -> message.getConversationId()) - .peek((conversationId, message) -> webSocketController.onNewMessage(message)); + final KStream messageStream = builder.stream(new ApplicationCommunicationMessages().name()); final KTable channelTable = builder.stream(new ApplicationCommunicationChannels().name()) .peek((channelId, channel) -> webSocketController.onChannelUpdate(channel)) .toTable(); + // conversation/message metadata keyed by conversation/message id final KTable> metadataTable = builder.table(applicationCommunicationMetadata) - .filter((metadataId, metadata) -> isConversationMetadata(metadata)) + .filter((metadataId, metadata) -> isConversationMetadata(metadata) + || isMessageMetadata(metadata)) .groupBy((metadataId, metadata) -> KeyValue.pair(getSubject(metadata).getIdentifier(), metadata)) .aggregate(HashMap::new, (conversationId, metadata, aggregate) -> { aggregate.put(metadata.getKey(), metadata.getValue()); @@ -106,6 +109,8 @@ private void startStream() { // unread counts final KTable unreadCountTable = messageStream + .selectKey((messageId, message) -> message.getConversationId()) + .peek((conversationId, message) -> webSocketController.onNewMessage(message)) .mapValues(message -> CountAction.increment(message.getSentAt())) .merge(resetStream) .groupByKey() @@ -124,33 +129,41 @@ private void startStream() { unreadCountTable.toStream().peek(webSocketController::onUnreadCount); - final KGroupedStream messageGroupedStream = messageStream.groupByKey(); + final KGroupedStream messageGroupedStream = messageStream.toTable() + .leftJoin(metadataTable, (message, metadataMap) -> MessageContainer.builder() + .message(message) + .metadataMap(Optional.ofNullable(metadataMap).orElse(new HashMap<>())) + .build()) + .toStream() + .filter((messageId, messageContainer) -> messageContainer != null) + .groupBy((messageId, messageContainer) -> messageContainer.getMessage().getConversationId()); + // messages store messageGroupedStream.aggregate(MessagesTreeSet::new, ((key, value, aggregate) -> { - aggregate.add(value); + aggregate.update(value); return aggregate; }), Materialized.as(messagesStore)); // conversations store messageGroupedStream .aggregate(Conversation::new, - (conversationId, message, aggregate) -> { - if (aggregate.getLastMessage() == null) { + (conversationId, container, aggregate) -> { + if (aggregate.getLastMessageContainer() == null) { aggregate = Conversation.builder() - .lastMessage(message) - .createdAt(message.getSentAt()) // Set this only once for the sent time of the first message + .lastMessageContainer(container) + .createdAt(container.getMessage().getSentAt()) // Set this only once for the sent time of the first message .build(); } // equals because messages can be updated - if (message.getSentAt() >= aggregate.getLastMessage().getSentAt()) { - aggregate.setLastMessage(message); + if (container.getMessage().getSentAt() >= aggregate.getLastMessageContainer().getMessage().getSentAt()) { + aggregate.setLastMessageContainer(container); } - if (SenderType.SOURCE_CONTACT.equals(message.getSenderType())) { - aggregate.setSourceConversationId(message.getSenderId()); + if (SenderType.SOURCE_CONTACT.equals(container.getMessage().getSenderType())) { + aggregate.setSourceConversationId(container.getMessage().getSenderId()); } return aggregate; @@ -165,12 +178,10 @@ private void startStream() { } return conversation; }) - .leftJoin(unreadCountTable, (conversation, unreadCountState) -> { - if (unreadCountState != null) { - return conversation.toBuilder().unreadMessageCount(unreadCountState.getUnreadCount()).build(); - } - return conversation; - }, Materialized.as(conversationsStore)) + .leftJoin(unreadCountTable, (conversation, unreadCountState) -> conversation.toBuilder() + .unreadMessageCount(Optional.ofNullable(unreadCountState) + .map(UnreadCountState::getUnreadCount).orElse(0) + ).build(), Materialized.as(conversationsStore)) .toStream() .process(IndexingProcessor.getSupplier(conversationsLuceneStore), conversationsLuceneStore); @@ -201,9 +212,8 @@ public void deleteMetadata(Subject subject, String key) throws ExecutionExceptio producer.send(new ProducerRecord<>(applicationCommunicationMetadata, getId(subject, key).toString(), null)).get(); } - public List getMessages(String conversationId) { + public List getMessages(String conversationId) { final ReadOnlyKeyValueStore messagesStore = getMessagesStore(); - final MessagesTreeSet messagesTreeSet = messagesStore.get(conversationId); return messagesTreeSet == null ? null : new ArrayList<>(messagesTreeSet); diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/WebSocketController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/WebSocketController.java index 5df863ce0c..cdd75fbc91 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/WebSocketController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/WebSocketController.java @@ -3,17 +3,19 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.Message; import co.airy.model.channel.ChannelPayload; +import co.airy.core.api.communication.dto.MessageContainer; import co.airy.core.api.communication.dto.UnreadCountState; import co.airy.core.api.communication.payload.MessageUpsertPayload; import co.airy.core.api.communication.payload.UnreadCountPayload; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; +import java.util.Map; import java.time.Instant; import static co.airy.avro.communication.ChannelConnectionState.CONNECTED; -import static co.airy.model.channel.ChannelPayload.fromChannel; import static co.airy.date.format.DateFormat.isoFromMillis; +import static co.airy.model.channel.ChannelPayload.fromChannel; @Service public class WebSocketController { @@ -34,7 +36,7 @@ public void onNewMessage(Message message) { final MessageUpsertPayload messageUpsertPayload = MessageUpsertPayload.builder() .channelId(message.getChannelId()) .conversationId(message.getConversationId()) - .message(mapper.fromMessage(message)) + .message(mapper.fromMessageContainer(new MessageContainer(message, Map.of()))) .build(); messagingTemplate.convertAndSend(QUEUE_MESSAGE, messageUpsertPayload); } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/Conversation.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/Conversation.java index 4316714eda..d9ec5ec611 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/Conversation.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/Conversation.java @@ -1,8 +1,8 @@ package co.airy.core.api.communication.dto; import co.airy.avro.communication.Channel; -import co.airy.avro.communication.Message; import co.airy.model.metadata.MetadataKeys; +import co.airy.model.metadata.MetadataRepository; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder; @@ -11,8 +11,10 @@ import java.io.Serializable; import java.util.HashMap; +import java.util.List; import java.util.Map; +import static java.util.stream.Collectors.toList; import static org.springframework.util.StringUtils.capitalize; @Data @@ -21,7 +23,7 @@ @AllArgsConstructor public class Conversation implements Serializable { private Long createdAt; - private Message lastMessage; + private MessageContainer lastMessageContainer; private String sourceConversationId; private Channel channel; @@ -45,7 +47,7 @@ public DisplayName getDisplayNameOrDefault() { } /** - * - Remove the source provider (see docs/docs/glossary.md#source-provider) + * - Remove the source provider (see docs/getting-started/glossary.md#source-provider) * - Capitalize first letter * E.g. twilio.sms -> Sms, facebook -> Facebook */ @@ -55,13 +57,22 @@ private String prettifySource(String source) { return capitalize(source); } + @JsonIgnore + public List getTagIds() { + return MetadataRepository.filterPrefix(metadata, MetadataKeys.TAGS) + .keySet() + .stream() + .map(s -> s.split("\\.")[1]) + .collect(toList()); + } + @JsonIgnore public String getId() { - return this.lastMessage.getConversationId(); + return this.lastMessageContainer.getMessage().getConversationId(); } @JsonIgnore public String getChannelId() { - return this.lastMessage.getChannelId(); + return this.lastMessageContainer.getMessage().getChannelId(); } } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/ConversationIndex.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/ConversationIndex.java index 48f8133520..876da12dc8 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/ConversationIndex.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/ConversationIndex.java @@ -6,9 +6,7 @@ import lombok.NoArgsConstructor; import java.io.Serializable; -import java.util.HashMap; import java.util.List; -import java.util.Map; @Data @Builder @@ -21,9 +19,7 @@ public class ConversationIndex implements Serializable { private String source; private Long createdAt; private Integer unreadMessageCount; - - @Builder.Default - private Map metadata = new HashMap<>(); + private List tagIds; public static ConversationIndex fromConversation(Conversation conversation) { return ConversationIndex.builder() @@ -31,8 +27,8 @@ public static ConversationIndex fromConversation(Conversation conversation) { .channelId(conversation.getChannelId()) .source(conversation.getChannel().getSource()) .displayName(conversation.getDisplayNameOrDefault().toString()) - .metadata(new HashMap<>(conversation.getMetadata())) .createdAt(conversation.getCreatedAt()) + .tagIds(conversation.getTagIds()) .unreadMessageCount(conversation.getUnreadMessageCount()) .build(); } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessageContainer.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessageContainer.java new file mode 100644 index 0000000000..afaa63ebf7 --- /dev/null +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessageContainer.java @@ -0,0 +1,19 @@ +package co.airy.core.api.communication.dto; + +import co.airy.avro.communication.Message; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MessageContainer implements Serializable { + private Message message; + private Map metadataMap; +} diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessagesTreeSet.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessagesTreeSet.java index 582d0f5340..1d205b3da0 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessagesTreeSet.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/MessagesTreeSet.java @@ -1,14 +1,19 @@ package co.airy.core.api.communication.dto; -import co.airy.avro.communication.Message; import com.fasterxml.jackson.annotation.JsonCreator; import java.util.Comparator; import java.util.TreeSet; -public class MessagesTreeSet extends TreeSet { +public class MessagesTreeSet extends TreeSet { @JsonCreator public MessagesTreeSet() { - super(Comparator.comparing(Message::getSentAt).reversed()); + super(Comparator.comparing((MessageContainer container) -> container.getMessage().getSentAt()).reversed()); + } + + // TreeSet does not support updating objects + public void update(MessageContainer container) { + remove(container); + add(container); } } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/lucene/DocumentMapper.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/lucene/DocumentMapper.java index ac2d50e0d0..c8215015d9 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/lucene/DocumentMapper.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/lucene/DocumentMapper.java @@ -10,9 +10,9 @@ import org.apache.lucene.document.TextField; import org.apache.lucene.index.IndexableField; -import java.util.Map; +import java.util.List; -import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toList; public class DocumentMapper { public Document fromConversationIndex(ConversationIndex conversation) { @@ -29,8 +29,8 @@ public Document fromConversationIndex(ConversationIndex conversation) { document.add(new IntPoint("unread_message_count", conversation.getUnreadMessageCount())); document.add(new StoredField("unread_message_count", conversation.getUnreadMessageCount())); - for (Map.Entry entry : conversation.getMetadata().entrySet()) { - document.add(new TextField("metadata." + entry.getKey(), entry.getValue(), Field.Store.YES)); + for (String tagId : conversation.getTagIds()) { + document.add(new TextField("tag_ids", tagId, Field.Store.YES)); } return document; @@ -40,18 +40,16 @@ public ConversationIndex fromDocument(Document document) { final Long createdAt = document.getField("created_at").numericValue().longValue(); final Integer unreadCount = document.getField("unread_message_count").numericValue().intValue(); - final Map metadata = document.getFields().stream() - .filter((field) -> field.name().startsWith("metadata")) - .collect(toMap( - (field) -> field.name().replace("metadata.", ""), - IndexableField::stringValue - )); + final List tagIds = document.getFields().stream() + .filter((field) -> field.name().equals("tag_ids")) + .map(IndexableField::stringValue) + .collect(toList()); return ConversationIndex.builder() .id(document.get("id")) .unreadMessageCount(unreadCount) .createdAt(createdAt) - .metadata(metadata) + .tagIds(tagIds) .displayName(document.get("display_name")) .build(); } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/MessageResponsePayload.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/MessageResponsePayload.java index 806db54106..71d3eee6c1 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/MessageResponsePayload.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/MessageResponsePayload.java @@ -1,20 +1,17 @@ package co.airy.core.api.communication.payload; -import co.airy.mapping.model.Content; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - @Data @Builder @NoArgsConstructor @AllArgsConstructor public class MessageResponsePayload { private String id; - private List content; + private String content; private String senderType; private String sentAt; private String deliveryState; diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/SendMessageRequestPayload.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/SendMessageRequestPayload.java index b843e80bd6..6ed2e29156 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/SendMessageRequestPayload.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/payload/SendMessageRequestPayload.java @@ -1,6 +1,6 @@ package co.airy.core.api.communication.payload; -import co.airy.mapping.model.Content; +import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -17,5 +17,5 @@ public class SendMessageRequestPayload { private UUID conversationId; @Valid @NotNull - private Content message; + private JsonNode message; } diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsInfoTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsInfoTest.java index 9945a8050a..43c56fa0cb 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsInfoTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsInfoTest.java @@ -22,8 +22,8 @@ import java.util.UUID; -import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; +import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.test.Timing.retryOnException; import static org.hamcrest.core.Is.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsListTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsListTest.java index f315b51f3d..13329239e7 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsListTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsListTest.java @@ -72,17 +72,21 @@ class ConversationsListTest { .build(); private static final String conversationIdToFind = UUID.randomUUID().toString(); + private static final String tagId = UUID.randomUUID().toString(); + private static final String anotherTagId = UUID.randomUUID().toString(); + private static final String userId = "user-id"; private static final List conversations = List.of( TestConversation.from(UUID.randomUUID().toString(), channelToFind, Map.of(MetadataKeys.Source.Contact.FIRST_NAME, firstNameToFind), 1), - TestConversation.from(UUID.randomUUID().toString(), channelToFind, 1), - TestConversation.from(conversationIdToFind, defaultChannel, 1), + TestConversation.from(UUID.randomUUID().toString(), channelToFind, + Map.of(MetadataKeys.TAGS + "." + tagId, "", MetadataKeys.TAGS + "." + anotherTagId, ""), + 1), + TestConversation.from(conversationIdToFind, defaultChannel, Map.of(MetadataKeys.TAGS + "." + tagId, ""), 1), TestConversation.from(UUID.randomUUID().toString(), defaultChannel, 2), TestConversation.from(UUID.randomUUID().toString(), defaultChannel, 5) ); - @BeforeAll static void beforeAll() throws Exception { kafkaTestHelper = new KafkaTestHelper(sharedKafkaTestResource, getTopics()); @@ -100,7 +104,6 @@ static void afterAll() throws Exception { kafkaTestHelper.afterAll(); } - @BeforeEach void beforeEach() throws Exception { webTestHelper.waitUntilHealthy(); @@ -137,16 +140,21 @@ void canFilterByDisplayName() throws Exception { checkConversationsFound(payload, 1); } + @Test + void canFilterByTagIds() throws Exception { + checkConversationsFound("{\"filters\": \"tag_ids:(" + tagId + ")\"}", 2); + + checkConversationsFound("{\"filters\": \"tag_ids:(" + tagId + " AND " + anotherTagId + ")\"}", 1); + } + @Test void canFilterByUnreadMessageCountRange() throws Exception { - String payload = "{\"filters\": \"unread_message_count:[2 TO *]\"}"; - checkConversationsFound(payload, 2); + checkConversationsFound("{\"filters\": \"unread_message_count:[2 TO *]\"}", 2); } @Test void canFilterByUnreadMessageCount() throws Exception { - String payload = "{\"filters\": \"unread_message_count:2\"}"; - checkConversationsFound(payload, 1); + checkConversationsFound("{\"filters\": \"unread_message_count:2\"}", 1); } @Test @@ -162,16 +170,7 @@ void canFilterByCombinedQueries() throws Exception { @Test void canFilterForUnknownNames() throws Exception { - String payload = "{\"filters\": \"display_name:Ada\"}"; - checkNoConversationReturned(payload); - } - - private void checkNoConversationReturned(String payload) throws Exception { - retryOnException( - () -> webTestHelper.post("/conversations.list", payload, userId) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data", hasSize(0))), - "Expected no conversations returned"); + checkConversationsFound("{\"filters\": \"display_name:Ada\"}", 0); } private void checkConversationsFound(String payload, int count) throws InterruptedException { diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsTagTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsTagTest.java index 368939368a..64cedd6317 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsTagTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/ConversationsTagTest.java @@ -3,7 +3,6 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.ChannelConnectionState; import co.airy.core.api.communication.util.TestConversation; -import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; import co.airy.spring.core.AirySpringBootApplication; @@ -23,8 +22,8 @@ import java.util.UUID; -import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; +import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.test.Timing.retryOnException; import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.hamcrest.core.Is.is; diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/MessagesTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/MessagesTest.java index 0fb81ccfd0..6e0758d169 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/MessagesTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/MessagesTest.java @@ -2,7 +2,9 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.ChannelConnectionState; +import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; +import co.airy.avro.communication.SenderType; import co.airy.core.api.communication.util.TestConversation; import co.airy.date.format.DateFormat; import co.airy.kafka.test.KafkaTestHelper; @@ -11,6 +13,7 @@ import co.airy.spring.test.WebTestHelper; import org.apache.avro.specific.SpecificRecordBase; import org.apache.kafka.clients.producer.ProducerRecord; +import org.hamcrest.core.StringContains; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -23,16 +26,24 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.time.Duration; +import java.time.Instant; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeUnit; -import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; +import static co.airy.core.api.communication.util.Topics.applicationCommunicationMessages; +import static co.airy.core.api.communication.util.Topics.applicationCommunicationMetadata; +import static co.airy.core.api.communication.util.Topics.getTopics; +import static co.airy.model.metadata.MetadataRepository.newMessageMetadata; import static co.airy.test.Timing.retryOnException; import static java.util.Comparator.reverseOrder; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.core.StringContains.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -43,17 +54,25 @@ public class MessagesTest { @RegisterExtension public static final SharedKafkaTestResource sharedKafkaTestResource = new SharedKafkaTestResource(); - private static KafkaTestHelper kafkaTestHelper; @Autowired private WebTestHelper webTestHelper; + private static final String channelId = "channel-id"; + private static final Channel channel = Channel.newBuilder() + .setConnectionState(ChannelConnectionState.CONNECTED) + .setId(channelId) + .setName("channel-name") + .setSource("facebook") + .setSourceChannelId("ps-id") + .build(); + @BeforeAll static void beforeAll() throws Exception { kafkaTestHelper = new KafkaTestHelper(sharedKafkaTestResource, getTopics()); - kafkaTestHelper.beforeAll(); + kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationChannels.name(), channelId, channel)); } @AfterAll @@ -69,27 +88,14 @@ void beforeEach() throws Exception { @Test void canFetchMessages() throws Exception { final String conversationId = UUID.randomUUID().toString(); - final String channelId = "channelId"; - final String userId = "user-id"; - - final Channel channel = Channel.newBuilder() - .setConnectionState(ChannelConnectionState.CONNECTED) - .setId(channelId) - .setName("channel-name") - .setSource("facebook") - .setSourceChannelId("ps-id") - .build(); - kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationChannels.name(), channelId, channel)); int messageCount = 10; final List> records = TestConversation.generateRecords(conversationId, channel, messageCount); - kafkaTestHelper.produceRecords(records); final String payload = "{\"conversation_id\":\"" + conversationId + "\"}"; - retryOnException( - () -> webTestHelper.post("/messages.list", payload, userId) + () -> webTestHelper.post("/messages.list", payload, "user-id") .andExpect(status().isOk()) .andExpect(jsonPath("$.data", hasSize(messageCount))) .andExpect(jsonPath("$.data[*].sent_at").value(contains( @@ -100,4 +106,38 @@ void canFetchMessages() throws Exception { "/messages.list endpoint error"); } + @Test + void canReplaceMessageContentUrl() throws Exception { + final String conversationId = UUID.randomUUID().toString(); + + final String sourceUrl = "http://source.example.org/file.jpg?cache=1&tracking=all#section"; + final String persistentUrl = "http://airy.customer.org/data.jpg"; + + final String messageId = UUID.randomUUID().toString(); + kafkaTestHelper.produceRecords(List.of( + new ProducerRecord<>(applicationCommunicationMessages.name(), messageId, Message.newBuilder() + .setId(messageId) + .setSentAt(Instant.now().toEpochMilli()) + .setSenderId("source-conversation-id") + .setDeliveryState(DeliveryState.DELIVERED) + .setSource("facebook") + .setSenderType(SenderType.SOURCE_CONTACT) + .setConversationId(conversationId) + .setHeaders(Map.of()) + .setChannelId(channel.getId()) + .setContent(String.format("{\"url\":\"%s\"}", sourceUrl)) + .build()), + new ProducerRecord<>(applicationCommunicationMetadata.name(), "metadata-id", + newMessageMetadata(messageId, "data_" + sourceUrl, persistentUrl)) + )); + + final String payload = "{\"conversation_id\":\"" + conversationId + "\"}"; + retryOnException( + () -> webTestHelper.post("/messages.list", payload, "user-id") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data", hasSize(1))) + .andExpect(jsonPath("$.data[0].content", containsString(persistentUrl))), + "/messages.list content url was not replaced by metadata"); + } + } diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/MetadataControllerTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/MetadataControllerTest.java index 74af0d44de..cbc2b609c4 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/MetadataControllerTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/MetadataControllerTest.java @@ -22,8 +22,8 @@ import java.util.UUID; -import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; +import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.test.Timing.retryOnException; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/SendMessageControllerTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/SendMessageControllerTest.java index 3bb6539c35..ccbaea3578 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/SendMessageControllerTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/SendMessageControllerTest.java @@ -7,10 +7,6 @@ import co.airy.core.api.communication.util.TestConversation; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; -import co.airy.mapping.ContentMapper; -import co.airy.mapping.model.Audio; -import co.airy.mapping.model.Content; -import co.airy.mapping.model.Text; import co.airy.spring.core.AirySpringBootApplication; import co.airy.spring.test.WebTestHelper; import com.fasterxml.jackson.databind.JsonNode; @@ -36,12 +32,9 @@ import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; import static co.airy.core.api.communication.util.Topics.applicationCommunicationMessages; import static co.airy.core.api.communication.util.Topics.getTopics; -import static co.airy.test.Timing.retryOnException; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; -import static org.hamcrest.core.Is.isA; import static org.junit.jupiter.api.Assertions.fail; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -68,9 +61,6 @@ public class SendMessageControllerTest { @Autowired private WebTestHelper webTestHelper; - @Autowired - private ContentMapper contentMapper; - @BeforeAll static void beforeAll() throws Exception { kafkaTestHelper = new KafkaTestHelper(sharedKafkaTestResource, getTopics()); @@ -91,45 +81,23 @@ void beforeEach() throws Exception { webTestHelper.waitUntilHealthy(); } - - @Test - void failsForUnknownContentSchema() throws Exception { - String payload = String.format("{\"conversation_id\":\"%s\"," + - "\"message\":{\"text\":\"answeris42\",\"type\":\"unknown\"}}", - conversationId); - final String userId = "user-id"; - - webTestHelper.post("/messages.send", payload, userId) - .andExpect(status().isBadRequest()); - } - - @Test - void canSendTemplateMessages() throws Exception { - String payload = String.format("{\"conversation_id\":\"%s\"," + - "\"message\":{\"payload\":{\"a nested\":\"structure\"},\"type\":\"source.template\"}}", - conversationId); - final String userId = "user-id"; - - webTestHelper.post("/messages.send", payload, userId) - .andExpect(status().isOk()); - } - @Test void canSendTextMessages() throws Exception { - String payload = String.format("{\"conversation_id\":\"%s\"," + - "\"message\":{\"text\":\"answeris42\",\"type\":\"text\"}}", - conversationId); + final String messagePayload = "{\"text\":\"answeris42\"}"; + final String requestPayload = String.format("{\"conversation_id\":\"%s\"," + + "\"message\":%s}", + conversationId, messagePayload); final String userId = "user-id"; - final String response = webTestHelper.post("/messages.send", payload, userId) + final String response = webTestHelper.post("/messages.send", requestPayload, userId) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); final JsonNode responseNode = new ObjectMapper().readTree(response); final String messageId = responseNode.get("id").textValue(); - List> records = kafkaTestHelper.consumeRecords(3, applicationCommunicationMessages.name()); - assertThat(records, hasSize(3)); + List> records = kafkaTestHelper.consumeRecords(2, applicationCommunicationMessages.name()); + assertThat(records, hasSize(2)); final Optional maybeMessage = records.stream() .map(ConsumerRecord::value) @@ -141,9 +109,6 @@ void canSendTextMessages() throws Exception { } final Message message = maybeMessage.get(); - final List contents = contentMapper.render(message); - assertThat(contents, hasSize(1)); - assertThat(contents, everyItem(isA(Text.class))); - assertThat(message.getSenderId(), is(userId)); + assertThat(message.getContent(), equalTo(messagePayload)); } } diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/UnreadCountTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/UnreadCountTest.java index 598ce5cbce..bf505c08d6 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/UnreadCountTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/UnreadCountTest.java @@ -3,10 +3,6 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.ChannelConnectionState; import co.airy.core.api.communication.util.TestConversation; -import co.airy.kafka.schema.application.ApplicationCommunicationChannels; -import co.airy.kafka.schema.application.ApplicationCommunicationMessages; -import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; -import co.airy.kafka.schema.application.ApplicationCommunicationReadReceipts; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; import co.airy.spring.core.AirySpringBootApplication; @@ -26,8 +22,8 @@ import java.util.UUID; -import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; +import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.test.Timing.retryOnException; import static org.hamcrest.core.IsEqual.equalTo; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/WebSocketControllerTest.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/WebSocketControllerTest.java index f037203f75..c68ef5b521 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/WebSocketControllerTest.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/WebSocketControllerTest.java @@ -42,8 +42,8 @@ import static co.airy.core.api.communication.WebSocketController.QUEUE_CHANNEL_CONNECTED; import static co.airy.core.api.communication.WebSocketController.QUEUE_MESSAGE; import static co.airy.core.api.communication.WebSocketController.QUEUE_UNREAD_COUNT; -import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.core.api.communication.util.Topics.applicationCommunicationChannels; +import static co.airy.core.api.communication.util.Topics.getTopics; import static co.airy.test.Timing.retryOnException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/backend/api/communication/src/test/java/co/airy/core/api/communication/util/TestConversation.java b/backend/api/communication/src/test/java/co/airy/core/api/communication/util/TestConversation.java index 7932d61c51..7f7715e1a8 100644 --- a/backend/api/communication/src/test/java/co/airy/core/api/communication/util/TestConversation.java +++ b/backend/api/communication/src/test/java/co/airy/core/api/communication/util/TestConversation.java @@ -3,6 +3,7 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; +import co.airy.avro.communication.Metadata; import co.airy.avro.communication.SenderType; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; @@ -19,6 +20,7 @@ import java.util.Random; import java.util.UUID; +import static co.airy.model.metadata.MetadataRepository.getId; import static co.airy.model.metadata.MetadataRepository.newConversationMetadata; @Data @@ -30,7 +32,6 @@ public class TestConversation { private Channel channel; private String conversationId; private Map metadata; - private int messageCount; private long lastMessageSentAt; private List> records; @@ -38,8 +39,7 @@ public static TestConversation from(String conversationId, Channel channel, int TestConversation testConversation = new TestConversation(); testConversation.setConversationId(conversationId); testConversation.setChannel(channel); - testConversation.setMessageCount(messageCount); - testConversation.setRecords(testConversation.generateRecords()); + testConversation.setRecords(testConversation.generateRecords(messageCount)); return testConversation; } @@ -48,33 +48,32 @@ public static TestConversation from(String conversationId, Channel channel, Map< TestConversation testConversation = new TestConversation(); testConversation.setConversationId(conversationId); testConversation.setChannel(channel); - testConversation.setMessageCount(messageCount); testConversation.setMetadata(metadata); - testConversation.setRecords(testConversation.generateRecords()); + testConversation.setRecords(testConversation.generateRecords(messageCount)); return testConversation; } public static List> generateRecords(String conversationId, Channel channel, int messageCount) { - return TestConversation.from(conversationId, channel, messageCount).generateRecords(); + return TestConversation.from(conversationId, channel, messageCount).generateRecords(messageCount); } - private List> generateRecords() { - final List> messages = getMessages(); + private List> generateRecords(int messageCount) { + final List> messages = getMessages(messageCount); this.lastMessageSentAt = ((Message) messages.get(messages.size() - 1).value()).getSentAt(); List> records = new ArrayList<>(messages); if (metadata != null) { - metadata.forEach((metadataKey, metadataValue) -> - records.add(new ProducerRecord<>(applicationCommunicationMetadata, conversationId, - newConversationMetadata(conversationId, metadataKey, metadataValue) - ))); + metadata.forEach((metadataKey, metadataValue) -> { + final Metadata metadata = newConversationMetadata(conversationId, metadataKey, metadataValue); + records.add(new ProducerRecord<>(applicationCommunicationMetadata, getId(metadata).toString(), metadata)); + }); } return records; } - private List> getMessages() { + private List> getMessages(int messageCount) { List> records = new ArrayList<>(); Random random = new Random(); Instant startDate = Instant.now().minus(Duration.ofDays(random.nextInt(365))); diff --git a/backend/media/src/main/java/co/airy/core/media/config/AwsConfig.java b/backend/media/src/main/java/co/airy/core/media/config/AwsConfig.java index f718d2be19..6dc2388204 100644 --- a/backend/media/src/main/java/co/airy/core/media/config/AwsConfig.java +++ b/backend/media/src/main/java/co/airy/core/media/config/AwsConfig.java @@ -3,7 +3,6 @@ import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import org.springframework.beans.factory.annotation.Value; diff --git a/backend/media/src/test/java/co/airy/core/media/MessagesTest.java b/backend/media/src/test/java/co/airy/core/media/MessagesTest.java index dbe108ec69..86666391d2 100644 --- a/backend/media/src/test/java/co/airy/core/media/MessagesTest.java +++ b/backend/media/src/test/java/co/airy/core/media/MessagesTest.java @@ -45,7 +45,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; diff --git a/backend/media/src/test/java/co/airy/core/media/MetadataTest.java b/backend/media/src/test/java/co/airy/core/media/MetadataTest.java index 0c0bf154e3..30370741cb 100644 --- a/backend/media/src/test/java/co/airy/core/media/MetadataTest.java +++ b/backend/media/src/test/java/co/airy/core/media/MetadataTest.java @@ -21,7 +21,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; @@ -40,8 +39,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; diff --git a/backend/model/message/src/main/java/co/airy/model/message/MessageRepository.java b/backend/model/message/src/main/java/co/airy/model/message/MessageRepository.java index 6166a7ad4f..8ecbbe7b23 100644 --- a/backend/model/message/src/main/java/co/airy/model/message/MessageRepository.java +++ b/backend/model/message/src/main/java/co/airy/model/message/MessageRepository.java @@ -3,6 +3,7 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; +import java.util.Map; import java.time.Instant; public class MessageRepository { @@ -15,4 +16,18 @@ public static Message updateDeliveryState(Message message, DeliveryState state) public static boolean isNewMessage(Message message) { return message.getUpdatedAt() == null; } + + public static String resolveContent(Message message, Map metadata) { + final String content = message.getContent(); + + return metadata.entrySet() + .stream() + .filter((entry) -> entry.getKey().startsWith("data_")) + .reduce(content, (updatedContent, entry) -> { + final String key = entry.getKey(); + final String urlToReplace = key.replace("data_", ""); + + return updatedContent.replace(urlToReplace, entry.getValue()); + }, (oldValue, newValue) -> newValue); + } } diff --git a/backend/sources/chat-plugin/BUILD b/backend/sources/chat-plugin/BUILD index 6372305e28..b820727a48 100644 --- a/backend/sources/chat-plugin/BUILD +++ b/backend/sources/chat-plugin/BUILD @@ -12,7 +12,6 @@ app_deps = [ "//backend/model/message", "//lib/java/uuid", "//lib/java/date", - "//lib/java/mapping", "//lib/java/spring/web:spring-web", "//lib/java/spring/kafka/core:spring-kafka-core", "//lib/java/spring/kafka/streams:spring-kafka-streams", diff --git a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/Mapper.java b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/Mapper.java index 23ceeab253..f44579a84c 100644 --- a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/Mapper.java +++ b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/Mapper.java @@ -2,23 +2,17 @@ import co.airy.avro.communication.Message; import co.airy.core.chat_plugin.payload.MessageResponsePayload; -import co.airy.mapping.ContentMapper; import org.springframework.stereotype.Component; import static co.airy.date.format.DateFormat.isoFromMillis; @Component public class Mapper { - private final ContentMapper contentMapper; - - Mapper(ContentMapper contentMapper) { - this.contentMapper = contentMapper; - } - public MessageResponsePayload fromMessage(Message message) { return MessageResponsePayload.builder() - .content(contentMapper.renderWithDefaultAndLog(message)) + .content(message.getContent()) .senderType(message.getSenderType().toString().toLowerCase()) + .deliveryState(message.getDeliveryState().toString().toLowerCase()) .state(message.getDeliveryState().toString().toLowerCase()) .id(message.getId()) .sentAt(isoFromMillis(message.getSentAt())) diff --git a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/MessageResponsePayload.java b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/MessageResponsePayload.java index 150e27f2e4..943f6eba47 100644 --- a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/MessageResponsePayload.java +++ b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/MessageResponsePayload.java @@ -1,13 +1,11 @@ package co.airy.core.chat_plugin.payload; -import co.airy.mapping.model.Content; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; -import java.util.List; @Data @Builder @@ -15,7 +13,7 @@ @AllArgsConstructor public class MessageResponsePayload implements Serializable { private String id; - private List content; + private String content; private String state; private String senderType; private String sentAt; diff --git a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/SendMessageRequestPayload.java b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/SendMessageRequestPayload.java index 6904a5f65a..c368f77c90 100644 --- a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/SendMessageRequestPayload.java +++ b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/payload/SendMessageRequestPayload.java @@ -1,16 +1,20 @@ package co.airy.core.chat_plugin.payload; -import co.airy.mapping.model.Text; -import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data @NoArgsConstructor public class SendMessageRequestPayload { @NotNull - private Text message; + private TextMessage message; + + @Data + @NoArgsConstructor + public static class TextMessage { + @NotNull + private String text; + } } diff --git a/backend/sources/chat-plugin/src/test/java/co/airy/core/chat_plugin/ChatControllerTest.java b/backend/sources/chat-plugin/src/test/java/co/airy/core/chat_plugin/ChatControllerTest.java index 267ec3c780..fb2da45429 100644 --- a/backend/sources/chat-plugin/src/test/java/co/airy/core/chat_plugin/ChatControllerTest.java +++ b/backend/sources/chat-plugin/src/test/java/co/airy/core/chat_plugin/ChatControllerTest.java @@ -7,7 +7,6 @@ import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; -import co.airy.mapping.model.Text; import co.airy.spring.core.AirySpringBootApplication; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -44,7 +43,6 @@ import static co.airy.core.chat_plugin.WebSocketController.QUEUE_MESSAGE; import static co.airy.test.Timing.retryOnException; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; @@ -126,14 +124,13 @@ void authenticateSendAndReceive() throws Exception { .headers(buildHeaders(token)) .content(sendMessagePayload)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.content[0].text", containsString(messageText))), + .andExpect(jsonPath("$.content", containsString(messageText))), "Message was not sent"); final MessageUpsertPayload messageUpsertPayload = messageFuture.get(); assertNotNull(messageUpsertPayload); - final Text text = (Text) messageUpsertPayload.getMessage().getContent().get(0); - assertThat(text.getText(), containsString(messageText)); + assertThat(messageUpsertPayload.getMessage().getContent(), containsString(messageText)); } @Test @@ -150,12 +147,13 @@ void canResumeConversation() throws Exception { final String authToken = jsonNode.get("token").textValue(); final String messageText = "Talk to you later!"; - final String sendMessagePayload = "{\"message\": { \"text\": \"" + messageText + "\", \"type\":\"text\" }}"; + final String sendMessagePayload = "{\"message\":{\"text\":\"" + messageText + "\"}}"; mvc.perform(post("/chatplugin.send") .headers(buildHeaders(authToken)) .content(sendMessagePayload)) .andExpect(status().isOk()) - .andExpect(jsonPath("$.content[0].text", containsString(messageText))); + .andExpect(jsonPath("$.delivery_state", is("delivered"))) + .andExpect(jsonPath("$.content", containsString(messageText))); response = mvc.perform(post("/chatplugin.resumeToken") .headers(buildHeaders(authToken)) @@ -175,7 +173,7 @@ void canResumeConversation() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.token", is(not(nullValue())))) .andExpect(jsonPath("$.messages", hasSize(1))) - .andExpect(jsonPath("$.messages[0].content[0].text", equalTo(messageText))); + .andExpect(jsonPath("$.messages[0].content", containsString(messageText))); }, "Did not resume conversation"); } diff --git a/backend/sources/facebook/connector/BUILD b/backend/sources/facebook/connector/BUILD index a03e6ad0d3..04704f3e58 100644 --- a/backend/sources/facebook/connector/BUILD +++ b/backend/sources/facebook/connector/BUILD @@ -10,7 +10,6 @@ app_deps = [ "//backend/model/metadata", "//lib/java/uuid", "//lib/java/log", - "//lib/java/mapping", "//lib/java/spring/web:spring-web", "//lib/java/spring/auth:spring-auth", "//lib/java/spring/kafka/core:spring-kafka-core", diff --git a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Connector.java b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Connector.java index 8d5c2c561a..c456286661 100644 --- a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Connector.java +++ b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Connector.java @@ -3,15 +3,15 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; -import co.airy.model.metadata.MetadataKeys; -import co.airy.core.sources.facebook.dto.SendMessageRequest; -import co.airy.core.sources.facebook.dto.Conversation; -import co.airy.core.sources.facebook.api.model.SendMessagePayload; -import co.airy.core.sources.facebook.api.model.UserProfile; import co.airy.core.sources.facebook.api.Api; import co.airy.core.sources.facebook.api.ApiException; import co.airy.core.sources.facebook.api.Mapper; +import co.airy.core.sources.facebook.api.model.SendMessagePayload; +import co.airy.core.sources.facebook.api.model.UserProfile; +import co.airy.core.sources.facebook.dto.Conversation; +import co.airy.core.sources.facebook.dto.SendMessageRequest; import co.airy.log.AiryLoggerFactory; +import co.airy.model.metadata.MetadataKeys; import co.airy.spring.auth.IgnoreAuthPattern; import co.airy.spring.web.filters.RequestLoggingIgnorePatterns; import org.apache.kafka.streams.KeyValue; diff --git a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Stores.java b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Stores.java index ea6cb8e91e..309032af93 100644 --- a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Stores.java +++ b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/Stores.java @@ -6,8 +6,8 @@ import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; import co.airy.avro.communication.SenderType; -import co.airy.core.sources.facebook.dto.SendMessageRequest; import co.airy.core.sources.facebook.dto.Conversation; +import co.airy.core.sources.facebook.dto.SendMessageRequest; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; diff --git a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/Mapper.java b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/Mapper.java index 5a41f71176..1eab0349bc 100644 --- a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/Mapper.java +++ b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/Mapper.java @@ -3,50 +3,23 @@ import co.airy.avro.communication.Message; import co.airy.core.sources.facebook.api.model.SendMessagePayload; import co.airy.core.sources.facebook.dto.SendMessageRequest; -import co.airy.mapping.ContentMapper; -import co.airy.mapping.model.Content; -import co.airy.mapping.model.SourceTemplate; -import co.airy.mapping.model.Text; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Service; -import java.util.List; - @Service public class Mapper { - private final ContentMapper mapper; - - Mapper(ContentMapper mapper) { - this.mapper = mapper; - } + private final ObjectMapper objectMapper = new ObjectMapper(); public SendMessagePayload fromSendMessageRequest(SendMessageRequest sendMessageRequest) throws Exception { final Message message = sendMessageRequest.getMessage(); - - final SendMessagePayload.MessagePayload messagePayload = new SendMessagePayload.MessagePayload(); - - final Content content = mapper.render(message) - .stream() - .findFirst() - .orElseThrow(() -> new Exception("Message is empty")); - - if (content instanceof Text) { - messagePayload.setText(((Text) content).getText()); - } else if (content instanceof SourceTemplate) { - messagePayload.setAttachment(SendMessagePayload.AttachmentPayload.builder() - .type("template") - .payload(((SourceTemplate) content).getPayload()) - .build()); - } - + final JsonNode messagePayload = objectMapper.readTree(message.getContent()); SendMessagePayload.SendMessagePayloadBuilder builder = SendMessagePayload.builder() .recipient(SendMessagePayload.MessageRecipient.builder() .id(sendMessageRequest.getConversation().getSourceConversationId()) .build()) .message(messagePayload); - return builder.build(); } } diff --git a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/Pages.java b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/Pages.java index 743883e729..fca91bdac4 100644 --- a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/Pages.java +++ b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/Pages.java @@ -1,6 +1,5 @@ package co.airy.core.sources.facebook.api.model; -import co.airy.core.sources.facebook.api.model.PageWithConnectInfo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/SendMessagePayload.java b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/SendMessagePayload.java index f8a73e8f84..c875d716ce 100644 --- a/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/SendMessagePayload.java +++ b/backend/sources/facebook/connector/src/main/java/co/airy/core/sources/facebook/api/model/SendMessagePayload.java @@ -1,15 +1,12 @@ package co.airy.core.sources.facebook.api.model; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.io.Serializable; - @Data @Builder @NoArgsConstructor @@ -18,7 +15,7 @@ public class SendMessagePayload { private String messagingType; private MessageRecipient recipient; - private MessagePayload message; + private JsonNode message; private String tag; @Data @@ -28,21 +25,4 @@ public class SendMessagePayload { public static class MessageRecipient { private String id; } - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class MessagePayload implements Serializable { - private String text; - private AttachmentPayload attachment; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class AttachmentPayload implements Serializable { - private String type; - private JsonNode payload; - } } diff --git a/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/FetchMetadataTest.java b/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/FetchMetadataTest.java index 48462b76cc..f1efd323c5 100644 --- a/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/FetchMetadataTest.java +++ b/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/FetchMetadataTest.java @@ -5,7 +5,6 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; -import co.airy.model.metadata.MetadataKeys; import co.airy.avro.communication.SenderType; import co.airy.core.sources.facebook.api.Api; import co.airy.core.sources.facebook.api.model.UserProfile; @@ -15,6 +14,7 @@ import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; +import co.airy.model.metadata.MetadataKeys; import co.airy.spring.core.AirySpringBootApplication; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; diff --git a/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/SendMessageTest.java b/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/SendMessageTest.java index 6d01a9f31f..ea55061ef2 100644 --- a/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/SendMessageTest.java +++ b/backend/sources/facebook/connector/src/test/java/co/airy/core/sources/facebook/SendMessageTest.java @@ -5,19 +5,17 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; import co.airy.avro.communication.SenderType; -import co.airy.core.sources.facebook.api.model.SendMessagePayload; import co.airy.core.sources.facebook.api.Api; +import co.airy.core.sources.facebook.api.model.SendMessagePayload; import co.airy.kafka.schema.Topic; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; -import co.airy.mapping.model.SourceTemplate; import co.airy.spring.core.AirySpringBootApplication; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -130,7 +128,7 @@ void canSendMessageViaTheFacebookApi() throws Exception { TimeUnit.SECONDS.sleep(5); final ObjectMapper objectMapper = new ObjectMapper(); - final JsonNode attachmentPayload = objectMapper.readTree("{\"a\":\"template payload\"}"); + final JsonNode messagePayload = objectMapper.readTree("{\"text\":\"Hello Facebook\"}"); kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationMessages.name(), messageId, Message.newBuilder() @@ -142,14 +140,14 @@ void canSendMessageViaTheFacebookApi() throws Exception { .setConversationId(conversationId) .setChannelId(channelId) .setSource("facebook") - .setContent(objectMapper.writeValueAsString(new SourceTemplate(attachmentPayload))) + .setContent(objectMapper.writeValueAsString(messagePayload)) .build()) ); retryOnException(() -> { final SendMessagePayload sendMessagePayload = payloadCaptor.getValue(); assertThat(sendMessagePayload.getRecipient().getId(), equalTo(sourceConversationId)); - assertThat(sendMessagePayload.getMessage().getAttachment().getPayload(), equalTo(attachmentPayload)); + assertThat(sendMessagePayload.getMessage(), equalTo(messagePayload)); assertThat(tokenCaptor.getValue(), equalTo(token)); }, "Facebook API was not called"); diff --git a/backend/sources/facebook/events-router/src/test/java/co/airy/core/sources/facebook/EventsRouterTest.java b/backend/sources/facebook/events-router/src/test/java/co/airy/core/sources/facebook/EventsRouterTest.java index 0a6e24d1f7..86e8deb0c9 100644 --- a/backend/sources/facebook/events-router/src/test/java/co/airy/core/sources/facebook/EventsRouterTest.java +++ b/backend/sources/facebook/events-router/src/test/java/co/airy/core/sources/facebook/EventsRouterTest.java @@ -35,8 +35,8 @@ import java.util.concurrent.TimeUnit; import static co.airy.test.Timing.retryOnException; -import static org.hamcrest.CoreMatchers.is; import static org.apache.kafka.streams.KafkaStreams.State.RUNNING; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/backend/sources/google/connector/BUILD b/backend/sources/google/connector/BUILD index 228830b2e0..dd317369ba 100644 --- a/backend/sources/google/connector/BUILD +++ b/backend/sources/google/connector/BUILD @@ -10,7 +10,6 @@ app_deps = [ "//lib/java/spring/kafka/core:spring-kafka-core", "//lib/java/spring/kafka/streams:spring-kafka-streams", "//lib/java/uuid", - "//lib/java/mapping", "//lib/java/kafka/schema:source-google-events", "//lib/java/spring/web:spring-web", "//lib/java/spring/auth:spring-auth", diff --git a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/Connector.java b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/Connector.java index 2c597adb38..0a72fd346f 100644 --- a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/Connector.java +++ b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/Connector.java @@ -2,13 +2,13 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; -import co.airy.core.sources.google.model.SendMessagePayload; import co.airy.core.sources.google.model.SendMessageRequest; import co.airy.core.sources.google.services.Api; import co.airy.core.sources.google.services.Mapper; import co.airy.log.AiryLoggerFactory; import co.airy.spring.auth.IgnoreAuthPattern; import co.airy.spring.web.filters.RequestLoggingIgnorePatterns; +import com.fasterxml.jackson.databind.JsonNode; import org.slf4j.Logger; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @@ -33,7 +33,7 @@ public Message sendMessage(SendMessageRequest sendMessageRequest) { final Message message = sendMessageRequest.getMessage(); try { - final SendMessagePayload sendMessagePayload = mapper.fromSendMessageRequest(sendMessageRequest); + final JsonNode sendMessagePayload = mapper.fromSendMessageRequest(sendMessageRequest); api.sendMessage(sendMessageRequest.getSourceConversationId(), sendMessagePayload); diff --git a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/model/SendMessagePayload.java b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/model/SendMessagePayload.java deleted file mode 100644 index 8ce3ce6858..0000000000 --- a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/model/SendMessagePayload.java +++ /dev/null @@ -1,26 +0,0 @@ -package co.airy.core.sources.google.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class SendMessagePayload { - @JsonProperty("messageId") - private String messageId; - private String text; - private Representative representative; - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class Representative { - @JsonProperty("representativeType") - private String representativeType; - } -} diff --git a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Api.java b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Api.java index 7a2365397a..86a462184d 100644 --- a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Api.java +++ b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Api.java @@ -2,7 +2,7 @@ import co.airy.core.sources.google.ApiException; import co.airy.core.sources.google.model.GoogleServiceAccount; -import co.airy.core.sources.google.model.SendMessagePayload; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; @@ -42,7 +42,7 @@ public Api(RestTemplateBuilder restTemplateBuilder, ObjectMapper objectMapper, G this.serviceAccount = serviceAccount; } - public void sendMessage(final String conversationId, SendMessagePayload sendMessagePayload) throws Exception { + public void sendMessage(final String conversationId, JsonNode sendMessagePayload) throws Exception { String reqUrl = String.format(requestTemplate, conversationId); final byte[] serializedServiceAccount = objectMapper.writeValueAsString(serviceAccount).getBytes(); diff --git a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Mapper.java b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Mapper.java index 6b206f9bc7..fda97ce2e7 100644 --- a/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Mapper.java +++ b/backend/sources/google/connector/src/main/java/co/airy/core/sources/google/services/Mapper.java @@ -1,31 +1,20 @@ package co.airy.core.sources.google.services; import co.airy.avro.communication.Message; -import co.airy.core.sources.google.model.SendMessagePayload; import co.airy.core.sources.google.model.SendMessageRequest; -import co.airy.mapping.ContentMapper; -import co.airy.mapping.model.Text; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.stereotype.Service; @Service public class Mapper { - private final ContentMapper mapper; - Mapper(ContentMapper mapper) { - this.mapper = mapper; - } + private final ObjectMapper mapper = new ObjectMapper(); - public SendMessagePayload fromSendMessageRequest(SendMessageRequest sendMessageRequest) throws Exception { + public JsonNode fromSendMessageRequest(SendMessageRequest sendMessageRequest) throws Exception { final Message message = sendMessageRequest.getMessage(); - final Text text = (Text) mapper.render(message) - .stream() - .filter(c -> c instanceof Text) - .findFirst() - .orElseThrow(() -> new Exception("google only supports text messages")); - - return SendMessagePayload.builder() - .messageId(message.getId()) - .representative(new SendMessagePayload.Representative("HUMAN")) - .text(text.getText()) - .build(); + final JsonNode messageNode = mapper.readTree(message.getContent()); + ((ObjectNode) messageNode).put("messageId", message.getId()); + return messageNode; } } diff --git a/backend/sources/google/connector/src/test/java/co/airy/core/sources/google/SendMessageTest.java b/backend/sources/google/connector/src/test/java/co/airy/core/sources/google/SendMessageTest.java index 935066ea22..96d2f559d0 100644 --- a/backend/sources/google/connector/src/test/java/co/airy/core/sources/google/SendMessageTest.java +++ b/backend/sources/google/connector/src/test/java/co/airy/core/sources/google/SendMessageTest.java @@ -3,15 +3,14 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; import co.airy.avro.communication.SenderType; -import co.airy.core.sources.google.model.SendMessagePayload; import co.airy.core.sources.google.services.Api; import co.airy.kafka.schema.Topic; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; -import co.airy.mapping.model.Text; import co.airy.spring.core.AirySpringBootApplication; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; @@ -88,9 +87,9 @@ void canSendMessageViaGoogleApi() throws Exception { final String messageId = UUID.randomUUID().toString(); final String sourceConversationId = "source-conversation-id"; final String channelId = UUID.randomUUID().toString(); - final String text = "Hello World"; + final String textPayload = "{\"text\":\"Hi world\",\"fallback\":\"bye world\"}"; - ArgumentCaptor payloadCaptor = ArgumentCaptor.forClass(SendMessagePayload.class); + ArgumentCaptor payloadCaptor = ArgumentCaptor.forClass(JsonNode.class); ArgumentCaptor googleIdCaptor = ArgumentCaptor.forClass(String.class); doNothing().when(api).sendMessage(googleIdCaptor.capture(), payloadCaptor.capture()); @@ -106,13 +105,12 @@ void canSendMessageViaGoogleApi() throws Exception { .setDeliveryState(DeliveryState.DELIVERED) .setConversationId(conversationId) .setChannelId(channelId) - .setContent("{\"text\":\"" + text + "\"}") + .setContent("{\"text\":\"" + textPayload + "\"}") .build()) ); TimeUnit.SECONDS.sleep(5); - final ObjectMapper objectMapper = new ObjectMapper(); kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationMessages.name(), messageId, Message.newBuilder() .setId(messageId) @@ -123,15 +121,15 @@ void canSendMessageViaGoogleApi() throws Exception { .setConversationId(conversationId) .setChannelId(channelId) .setSource("google") - .setContent(objectMapper.writeValueAsString(new Text(text))) + .setContent(textPayload) .build()) ); retryOnException(() -> { - final SendMessagePayload sendMessagePayload = payloadCaptor.getValue(); + final JsonNode sendMessagePayload = payloadCaptor.getValue(); - assertThat(sendMessagePayload.getText(), equalTo(text)); - assertThat(sendMessagePayload.getMessageId(), equalTo(messageId)); + assertThat(sendMessagePayload.get("text").textValue(), equalTo("Hi world")); + assertThat(sendMessagePayload.get("messageId").textValue(), equalTo(messageId)); assertThat(googleIdCaptor.getValue(), equalTo(sourceConversationId)); }, "google API was not called"); } diff --git a/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/EventsRouter.java b/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/EventsRouter.java index 6f8c969aa9..3f983f210a 100644 --- a/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/EventsRouter.java +++ b/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/EventsRouter.java @@ -30,8 +30,8 @@ import java.util.ArrayList; import java.util.List; -import static co.airy.model.metadata.MetadataRepository.getId; import static co.airy.core.sources.google.InfoExtractor.getMetadataFromContext; +import static co.airy.model.metadata.MetadataRepository.getId; @Component public class EventsRouter implements DisposableBean, ApplicationListener { diff --git a/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/InfoExtractor.java b/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/InfoExtractor.java index 33d111d144..4c96b038a5 100644 --- a/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/InfoExtractor.java +++ b/backend/sources/google/events-router/src/main/java/co/airy/core/sources/google/InfoExtractor.java @@ -1,14 +1,13 @@ package co.airy.core.sources.google; import co.airy.avro.communication.Metadata; -import co.airy.model.metadata.MetadataKeys; import co.airy.log.AiryLoggerFactory; +import co.airy.model.metadata.MetadataKeys; import com.fasterxml.jackson.databind.JsonNode; import org.slf4j.Logger; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/backend/sources/google/events-router/src/test/java/co/airy/core/sources/google/EventsRouterTest.java b/backend/sources/google/events-router/src/test/java/co/airy/core/sources/google/EventsRouterTest.java index bb62059cc6..d614e7c486 100644 --- a/backend/sources/google/events-router/src/test/java/co/airy/core/sources/google/EventsRouterTest.java +++ b/backend/sources/google/events-router/src/test/java/co/airy/core/sources/google/EventsRouterTest.java @@ -4,7 +4,6 @@ import co.airy.avro.communication.ChannelConnectionState; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; -import co.airy.model.metadata.MetadataKeys; import co.airy.kafka.schema.Topic; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; @@ -12,6 +11,7 @@ import co.airy.kafka.schema.source.SourceGoogleEvents; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; +import co.airy.model.metadata.MetadataKeys; import co.airy.spring.core.AirySpringBootApplication; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; diff --git a/backend/sources/twilio/connector/BUILD b/backend/sources/twilio/connector/BUILD index 1ab494184b..0298cc6b63 100644 --- a/backend/sources/twilio/connector/BUILD +++ b/backend/sources/twilio/connector/BUILD @@ -8,7 +8,6 @@ app_deps = [ "//backend/model/channel", "//backend/model/message", "//lib/java/log", - "//lib/java/mapping", "//lib/java/uuid", "@maven//:com_twilio_sdk_twilio", "//lib/java/spring/kafka/core:spring-kafka-core", diff --git a/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/ChannelsController.java b/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/ChannelsController.java index 7b7d9e04f0..51bfcb216e 100644 --- a/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/ChannelsController.java +++ b/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/ChannelsController.java @@ -10,8 +10,6 @@ import lombok.NoArgsConstructor; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerRecord; -import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; diff --git a/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/Connector.java b/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/Connector.java index 563f5589de..eba9e7d70a 100644 --- a/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/Connector.java +++ b/backend/sources/twilio/connector/src/main/java/co/airy/core/sources/twilio/Connector.java @@ -5,10 +5,10 @@ import co.airy.core.sources.twilio.dto.SendMessageRequest; import co.airy.core.sources.twilio.services.Api; import co.airy.log.AiryLoggerFactory; -import co.airy.mapping.ContentMapper; -import co.airy.mapping.model.Text; import co.airy.spring.auth.IgnoreAuthPattern; import co.airy.spring.web.filters.RequestLoggingIgnorePatterns; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.twilio.exception.ApiException; import org.slf4j.Logger; import org.springframework.context.annotation.Bean; @@ -23,11 +23,10 @@ public class Connector { private static final Logger log = AiryLoggerFactory.getLogger(Connector.class); private final Api api; - private final ContentMapper mapper; + private final ObjectMapper mapper = new ObjectMapper(); - Connector(Api api, ContentMapper mapper) { + Connector(Api api) { this.api = api; - this.mapper = mapper; } public Message sendMessage(SendMessageRequest sendMessageRequest) { @@ -35,14 +34,8 @@ public Message sendMessage(SendMessageRequest sendMessageRequest) { final String from = sendMessageRequest.getChannel().getSourceChannelId(); final String to = sendMessageRequest.getSourceConversationId(); try { - // TODO Figure out how we can let clients know which outbound message types are supported - final Text text = (Text) mapper.render(message) - .stream() - .filter(c -> c instanceof Text) - .findFirst() - .orElseThrow(() -> new Exception("twilio only supports text messages")); - - api.sendMessage(from, to, text.getText()); + final JsonNode messageNode = mapper.readTree(message.getContent()); + api.sendMessage(from, to, messageNode.get("text").textValue()); updateDeliveryState(message, DeliveryState.DELIVERED); return message; diff --git a/backend/sources/twilio/connector/src/test/java/co/airy/core/sources/twilio/SendMessageTest.java b/backend/sources/twilio/connector/src/test/java/co/airy/core/sources/twilio/SendMessageTest.java index 68a07a6217..5e1c2919e2 100644 --- a/backend/sources/twilio/connector/src/test/java/co/airy/core/sources/twilio/SendMessageTest.java +++ b/backend/sources/twilio/connector/src/test/java/co/airy/core/sources/twilio/SendMessageTest.java @@ -11,9 +11,7 @@ import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; -import co.airy.mapping.model.Text; import co.airy.spring.core.AirySpringBootApplication; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -124,7 +122,6 @@ void canSendMessageViaTheTwilioApi() throws Exception { TimeUnit.SECONDS.sleep(5); - final ObjectMapper objectMapper = new ObjectMapper(); kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationMessages.name(), messageId, Message.newBuilder() .setId(messageId) @@ -135,7 +132,7 @@ void canSendMessageViaTheTwilioApi() throws Exception { .setConversationId(conversationId) .setChannelId(channelId) .setSource("twilio.sms") - .setContent(objectMapper.writeValueAsString(new Text(text))) + .setContent("{\"text\":\"" + text + "\"}") .build()) ); diff --git a/backend/webhook/publisher/BUILD b/backend/webhook/publisher/BUILD index fc0d56080a..641e101902 100644 --- a/backend/webhook/publisher/BUILD +++ b/backend/webhook/publisher/BUILD @@ -7,7 +7,6 @@ app_deps = [ "//backend/model/message", "//backend:webhook", "//lib/java/uuid", - "//lib/java/mapping", "//lib/java/date", "//lib/java/spring/kafka/core:spring-kafka-core", "//lib/java/spring/kafka/streams:spring-kafka-streams", diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Mapper.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Mapper.java index 8ccffff625..3b641bddd2 100644 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Mapper.java +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Mapper.java @@ -3,9 +3,6 @@ import co.airy.avro.communication.Message; import co.airy.core.webhook.publisher.model.Postback; import co.airy.core.webhook.publisher.model.WebhookBody; -import co.airy.mapping.ContentMapper; -import co.airy.mapping.model.Content; -import co.airy.mapping.model.Text; import org.springframework.stereotype.Component; import java.util.List; @@ -15,28 +12,11 @@ @Component public class Mapper { - private final ContentMapper contentMapper; - - Mapper(ContentMapper contentMapper) { - this.contentMapper = contentMapper; - } - public WebhookBody fromMessage(Message message) throws Exception { - final List content = contentMapper.renderWithDefaultAndLog(message); - - final Text textContent = (Text) content.stream() - .filter(c -> (c instanceof Text)) - .findFirst() - .orElse(null); - - if (textContent == null) { - throw new NotATextMessage(); - } - return WebhookBody.builder() .conversationId(message.getConversationId()) .id(message.getId()) - .text(textContent.getText()) + .content(message.getContent()) .source(message.getSource()) .postback(buildPostback(message)) .sentAt(isoFromMillis(message.getSentAt())) diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/model/WebhookBody.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/model/WebhookBody.java index 85e123d4e7..558c237c05 100644 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/model/WebhookBody.java +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/model/WebhookBody.java @@ -14,7 +14,7 @@ public class WebhookBody implements Serializable { private String conversationId; private String id; - private String text; + private String content; private Sender sender; private String sentAt; private String source; diff --git a/bazel.tsconfig.json b/bazel.tsconfig.json new file mode 100644 index 0000000000..933d800425 --- /dev/null +++ b/bazel.tsconfig.json @@ -0,0 +1,51 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "strict": false, + "baseUrl": "./", + "noImplicitAny": false, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true, + "sourceMap": true, + "jsx": "react", + "paths": { + "components": [ + "./frontend/components/src" + ], + "components/*": [ + "./frontend/components/src/*" + ], + "httpclient": [ + "./lib/typescript/httpclient" + ], + "httpclient/*": [ + "./lib/typescript/httpclient/*" + ], + "types": [ + "./lib/typescript/types" + ], + "types/*": [ + "./lib/typescript/types/*" + ], + "websocketclient": [ + "./lib/typescript/websocketclient" + ], + "websocketclient/*": [ + "./lib/typescript/websocketclient/*" + ], + "*": [ + "./*" + ] + } + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 26e434eb6e..7e471e2d9f 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -11,4 +11,5 @@ prettier( "**/*.css", ]), config = "//:.prettierrc.json", + ignore = "//:.prettierignore", ) diff --git a/docs/cli-doc/BUILD b/docs/cli-doc/BUILD new file mode 100644 index 0000000000..7275d0aa11 --- /dev/null +++ b/docs/cli-doc/BUILD @@ -0,0 +1,23 @@ +# gazelle:prefix docs +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "generate_cli_docs_lib", + srcs = ["generate_cli_docs.go"], + importpath = "docs", + visibility = ["//visibility:private"], + x_defs = { + "ProjectDir": "{PROJECT_DIR}", + }, + deps = [ + "//infrastructure/cli/cmd", + "@com_github_spf13_cobra//doc", + ], +) + +go_binary( + name = "generate_cli_docs", + out = "generate_cli_docs", + embed = [":generate_cli_docs_lib"], + visibility = ["//visibility:public"], +) diff --git a/docs/cli-doc/generate_cli_docs.go b/docs/cli-doc/generate_cli_docs.go new file mode 100644 index 0000000000..0fcd88eea2 --- /dev/null +++ b/docs/cli-doc/generate_cli_docs.go @@ -0,0 +1,41 @@ +package main + +import ( + "cli/cmd" + "path/filepath" + "strings" + + "github.com/spf13/cobra/doc" + + "fmt" +) + +var ProjectDir string + +const fmTemplate = `--- +title: %s +sidebar_label: %s +--- + +` + +func defaultLinkHandler(name, ref string) string { + return fmt.Sprintf("`%s <%s.rst>`_", name, ref) +} + +func main() { + + filePrepender := func(filename string) string { + title := strings.Title(strings.Replace(strings.ReplaceAll(filepath.Base(filename), "_", " "), ".md", "", 1)) + return fmt.Sprintf(fmTemplate, title, title) + } + identity := func(s string) string { return s } + + cmd.RootCmd.DisableAutoGenTag = true + + err := doc.GenMarkdownTreeCustom(cmd.RootCmd, ProjectDir+"/docs/docs/cli", filePrepender, identity) + if err != nil { + fmt.Println(err) + } + +} diff --git a/docs/cli-doc/go.mod b/docs/cli-doc/go.mod new file mode 100644 index 0000000000..d2c43cb897 --- /dev/null +++ b/docs/cli-doc/go.mod @@ -0,0 +1,9 @@ +module main + +go 1.12 + +require ( + github.com/spf13/cobra v1.1.1 +) + +replace "github.com/airyhq/airy/infrastructure/cli" => ../../infrastructure/cli diff --git a/docs/cli-doc/go.sum b/docs/cli-doc/go.sum new file mode 100644 index 0000000000..f01bf3255e --- /dev/null +++ b/docs/cli-doc/go.sum @@ -0,0 +1,289 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/docs/docs/api/authentication.md b/docs/docs/api/authentication.md new file mode 100644 index 0000000000..92cc9d12d6 --- /dev/null +++ b/docs/docs/api/authentication.md @@ -0,0 +1,36 @@ +--- +title: Authentication +sidebar_label: Authentication +--- + +In order to communicate with the Airy Core API, you need a valid +[JWT](https://jwt.io/) token. Get a valid token by sending a request to the +login endpoint [login](#login). It returns a short-lived JWT token you can use +for HTTP requests. + +## Login + +As the purpose of this endpoint is to obtain valid JWT tokens, it +does not require a valid token to be present in the headers. + +`POST /users.login` + +**Sample request** + +```json5 +{ + "email": "grace@example.com", + "password": "avalidpassword" +} +``` + +**Sample response** + +```json +{ + "id": "424242-4242-42-4242-4242", + "first_name": "Grace", + "last_name": "Hopper", + "token": "JWT_TOKEN" +} +``` diff --git a/docs/docs/api/endpoints/channels.md b/docs/docs/api/endpoints/channels.md new file mode 100644 index 0000000000..1142a2ee12 --- /dev/null +++ b/docs/docs/api/endpoints/channels.md @@ -0,0 +1,33 @@ +--- +title: Channels +sidebar_label: Channels +--- + +Refer to our [channel](getting-started/glossary.md#channel) definition +for more information. + +## List + +`POST /channels.list` + +**Sample response** + +```json5 +{ + "data": [ + { + "id": "channel-uuid-1", + "name": "my page 1", + "source": "facebook", + "source_channel_id": "fb-page-id-1", + "image_url": "http://example.org/avatar.jpeg" // optional + }, + { + "id": "channel-uuid-2", + "name": "my page 2", + "source": "facebook", + "source_channel_id": "fb-page-id-2" + } + ] +} +``` diff --git a/docs/docs/api/endpoints/conversations.md b/docs/docs/api/endpoints/conversations.md new file mode 100644 index 0000000000..43bd0ff26c --- /dev/null +++ b/docs/docs/api/endpoints/conversations.md @@ -0,0 +1,189 @@ +--- +title: Conversations +sidebar_label: Conversations +--- + +Refer to our [conversation](getting-started/glossary.md#conversation) +definition for more information. + +## List + +`POST /conversations.list` + +This is a [paginated](/api/endpoints/introduction.md#pagination) endpoint. + +**Filtering** + +This endpoint allows you to query conversations using the human readable [Lucene +Query Syntax](https://lucene.apache.org/core/2_9_4/queryparsersyntax.html). You +can query on all fields defined in [this +class](https://github.com/airyhq/airy/blob/main/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/ConversationIndex.java). + +**Sample request** + +Find users whose name ends with "Lovelace": + +```json5 +{ + "filters": "display_name:*Lovelace", // optional + "cursor": "next-page-uuid", + "page_size": 2 +} +``` + +**Sample request** + +```json5 +{ + "cursor": "next-page-uuid", + "page_size": 2 +} +``` + +**Sample response** + +```json5 +{ + "data": [ + { + "id": "a688d36c-a85e-44af-bc02-4248c2c97622", + "channel": { + "name": "Facebook page name", + "source": "facebook", + "id": "318efa04-7cc1-4200-988e-50699d0dd6e3" + }, + "created_at": "2019-01-07T09:01:44.000Z", + "contact": { + // Additional data on the contact + "avatar_url": "https://assets.airy.co/AirySupportIcon.jpg", + "display_name": "Airy Support" + }, + "tags": ["f339c325-8614-43cb-a70a-e83d81bf56fc"], + "last_message": { + id: "{UUID}", + "content": '{"text":"Hello World"}', + // source message payload + // typed source message model + state: "{String}", + // delivery state of message, one of PENDING, FAILED, DELIVERED + sender_type: "{string/enum}", + // See glossary + sent_at: "{string}" + //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients + }, + "unread_message_count": 1 + } + ], + "response_metadata": { + "previous_cursor": "", + "next_cursor": "", + "filtered_total": 1, + "total": 1, + "badge_unread_count": 1 + } +} +``` + +## info + +`POST /conversations.info` + +**Sample request** + +```json +{ + "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622" +} +``` + +**Sample response** + +```json5 +{ + "id": "a688d36c-a85e-44af-bc02-4248c2c97622", + "channel": { + "name": "facebook", + "id": "318efa04-7cc1-4200-988e-50699d0dd6e3" + }, + "created_at": "2019-01-07T09:01:44.000Z", + "contact": { + "avatar_url": "https://assets.airy.co/AirySupportIcon.jpg", // optional + "display_name": "Airy Support" // optional + }, + "tags": ["f339c325-8614-43cb-a70a-e83d81bf56fc"], + "last_message": { + "id": "{UUID}", + "content": '{"text":"Hello World"}', + // source message payload + // typed source message model + "delivery_state": "{String}", + // delivery state of message, one of PENDING, FAILED, DELIVERED + "sender_type": "{string/enum}", + // See glossary + "sent_at": "{string}" + //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients + }, + "unread_message_count": 1 +} +``` + +#### Mark conversation as read + +`POST /conversations.read` + +Resets the unread count of a conversation and returns status code `202 (Accepted)`. + +**Sample request** + +```json +{ + "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622" +} +``` + +**Sample response** + +```json5 +{} +``` + +## Tag a conversation + +Tags an existing conversation with [an existing +tag](/api/endpoints/tags.md#create). Returns status code `200` if successful. + +`POST /conversations.tag` + +**Sample request** + +```json5 +{ + "conversation_id": "CONVERSATION_ID", + "tag_id": "TAG_ID" +} +``` + +**Sample response** + +```json5 +{} +``` + +## Untag a conversation + +`POST /conversations.untag` + +**Sample request** + +```json5 +{ + "conversation_id": "CONVERSATION_ID", + "tag_id": "TAG_ID" +} +``` + +**Sample response** + +```json5 +{} +``` diff --git a/docs/docs/api/endpoints/introduction.md b/docs/docs/api/endpoints/introduction.md new file mode 100644 index 0000000000..0e218b0f37 --- /dev/null +++ b/docs/docs/api/endpoints/introduction.md @@ -0,0 +1,74 @@ +--- +title: Introduction +sidebar_label: Introduction +--- + +The grouping of HTTP endpoints reflects the high-level entities of the [Airy +Core Data Model](getting-started/glossary.md). + +## Conventions + +All HTTP endpoints adhere to the following conventions: + +- Endpoints only accept `POST` JSON requests. +- Communication always requires a valid [JWT + token](/api/authentication.md), except for `/users.login` and + `/users.signup` endpoints. +- We use dots for namespacing URLs (eg `/things.add`). + +## Pagination + +By default, paginated endpoints return a maximum of 20 elements on the first page. + +The size of the returned page can be controlled by the `page_size` field of the +body. You can move back and forth between pages using the `cursor` field of the +body. + +Paginated endpoints _always_ respond with the following JSON format: + +```json +{ + "data": [ + { + "id": "a688d36c-a85e-44af-bc02-4248c2c97622", + "field1": "answer is 42", + "field2": "this is fine" + } + ], + "response_metadata": { + "previous_cursor": "", + "next_cursor": "", + "filtered_total": 1, + "total": 1 + } +} +``` + +The response comes in two parts: + +- `data` + + An array of objects. Object specification depends on the endpoint. + +- `response_metadata` + An object with the following fields: + + - `previous_cursor` + + The ID of first elements in the previous page of data. Empty if the returned + page is the first one. + + - `next_cursor` + + The ID of first elements in the next page of data. Empty if the returned + page is the last one. + + - `filtered_total` + + The total number of elements across pages in the context of the current + filter selection. Only applicable to paginated endpoints that can filter + data. + + - `total` + + The total number of elements across all pages. diff --git a/docs/docs/api/endpoints/messages.md b/docs/docs/api/endpoints/messages.md new file mode 100644 index 0000000000..f422b600bc --- /dev/null +++ b/docs/docs/api/endpoints/messages.md @@ -0,0 +1,83 @@ +--- +title: Messages +sidebar_label: Messages +--- + +Refer to our [messages](getting-started/glossary.md#message) definition +for more information. + +## List + +`POST /messages.list` + +This is a [paginated](#pagination) endpoint. Messages are sorted from oldest to +latest. + +**Sample request** + +```json5 +{ + "conversation_id": "4242-4242-4242-424242", + "cursor": "next-page-uuid", // optional + "page_size": 2 // optional +} +``` + +**Sample response** + +```json5 +{ + "data": [ + { + "id": "{UUID}", + "content": '{"text":"Hello World"}', + // source message payload + // typed source message model + "state": "{String}", + // delivery state of message, one of PENDING, FAILED, DELIVERED + "sender_type": "{string/enum}", + // See glossary + "sent_at": "{string}" + //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients + } + ], + "response_metadata": { + "previous_cursor": "", + "next_cursor": "", + "filtered_total": 1, + "total": 1 + } +} +``` + +## Send + +`POST /messages.send` + +Sends a message to a conversation and returns a payload. Whatever is put on the +`message` field will be forwarded "as-is" to the source's message endpoint. + +**Sending a text message** + +```json5 +{ + "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", + "message": { + "text": "Hello World" + } +} +``` + +**Sample response** + +```json5 +{ + "id": "{UUID}", + "content": '{"text":"Hello"}', + "state": "pending|failed|delivered", + "sender_type": "{string/enum}", + // See glossary + "sent_at": "{string}" + //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients +} +``` diff --git a/docs/docs/api/endpoints/metadata.md b/docs/docs/api/endpoints/metadata.md new file mode 100644 index 0000000000..f7de541669 --- /dev/null +++ b/docs/docs/api/endpoints/metadata.md @@ -0,0 +1,36 @@ +--- +title: Metadata +sidebar_label: Metadata +--- + +Refer to our [metadata](getting-started/glossary.md#metadata) definition for +more information. + +## Set + +`POST /metadata.set` + +```json +{ + "conversation_id": "conversation-id", + "key": "ad.id", + "value": "Grace" +} +``` + +The endpoint returns status code `200` if the operation was successful, and +`400` if not. + +## Remove + +`POST /metadata.remove` + +```json +{ + "conversation_id": "conversation-id", + "key": "ad.id" +} +``` + +This endpoint returns status code `200` if the operation was successful, and +`500` if not. diff --git a/docs/docs/api/endpoints/tags.md b/docs/docs/api/endpoints/tags.md new file mode 100644 index 0000000000..c60711d956 --- /dev/null +++ b/docs/docs/api/endpoints/tags.md @@ -0,0 +1,90 @@ +--- +title: Tags +sidebar_label: Tags +--- + +Please refer to our [tag](getting-started/glossary.md#tag) definition for more +information. + +## Create + +`POST /tags.create` + +**Sample request** + +```json5 +{ + "name": "Urgent", + "color": "tag-red" // one of tag-red | tag-blue | tag-green | tag-purple +} +``` + +If the tag is successfully created, the request returns status code `201` (created) with the tag ID in the response body. + +**Sample response** + +```json5 +{ + "id": "TAG-UUID" +} +``` + +## Update + +`POST /tags.update` + +**Sample request** + +```json +{ + "id": "TAG-ID", + "name": "Urgent", + "color": "tag-blue" // one of tag-red | tag-blue | tag-green | tag-purple +} +``` + +If action is successful, the request returns status code `200`. + +**Sample response** + +```json5 +{} +``` + +## Delete + +`POST /tags.delete` + +**Sample request** + +```json +{ + "id": "ID-OF-THE-TAG" +} +``` + +If action is successful, returns HTTP status `200`. + +**Sample response** + +```json5 +{} +``` + +## List + +`POST /tags.list` + +**Sample response** + +```json5 +{ + "tags": [ + { + "id": "TAG-ID", + "name": "name of the tag", + "color": "RED" + } + ] +} +``` diff --git a/docs/docs/api/endpoints/users.md b/docs/docs/api/endpoints/users.md new file mode 100644 index 0000000000..f522c67fcc --- /dev/null +++ b/docs/docs/api/endpoints/users.md @@ -0,0 +1,37 @@ +--- +title: Users +sidebar_label: Users +--- + +Refer to our [user](getting-started/glossary.md#user) definition for more +information. + +## Signup + +`POST /users.signup` + +**Sample request** + +```json +{ + "first_name": "Grace", + "last_name": "Hopper", + "password": "the_answer_is_42", + "email": "grace@example.com" +} +``` + +The password **must** be at least 6 characters long. + +**Sample response** + +```json +{ + "id": "424242-4242-42-4242-4242", + "first_name": "Grace", + "last_name": "Hopper", + "token": "JWT_TOKEN" +} +``` + +This endpoint returns the same response as `POST /login`. diff --git a/docs/docs/api/http.md b/docs/docs/api/http.md deleted file mode 100644 index a451960c20..0000000000 --- a/docs/docs/api/http.md +++ /dev/null @@ -1,616 +0,0 @@ ---- -title: HTTP -sidebar_label: HTTP ---- - -This documents offers a high-level overview of the different parts that -compose the Airy API. - -## Introduction - -The HTTP endpoints adhere to the following conventions: - -- Endpoints only accept `POST` JSON requests. -- Communication always requires a valid [JWT token](#authentication), except for - `/users.login` and `/users.signup` endpoints. -- We use dots for namespacing URLs (eg `/things.add`). - -## Authentication - -In order to communicate with the API endpoints, you need a valid -[JWT](https://jwt.io/) token. Get a valid token by sending a request to the -login endpoint [login](#login). It returns a short-lived JWT token you can use -for HTTP requests. - -### Login - -As the purpose of this endpoint is to obtain valid JWT tokens, it -does not require a valid token to be present in the headers. - -`POST /users.login` - -**Sample request** - -```json5 -{ - "email": "grace@example.com", - "password": "avalidpassword" -} -``` - -**Sample response** - -```json -{ - "id": "424242-4242-42-4242-4242", - "first_name": "Grace", - "last_name": "Hopper", - "token": "JWT_TOKEN" -} -``` - -## Endpoints - -The grouping of endpoints reflects the high-level entities of the [Airy Core -Data Model](glossary.md). - -### Users - -Please refer to our [user](glossary.md#users) definition for more -information. - -#### Signup - -`POST /users.signup` - -**Sample request** - -```json -{ - "first_name": "Grace", - "last_name": "Hopper", - "password": "the_answer_is_42", - "email": "grace@example.com" -} -``` - -The password **must** be at least 6 characters long. - -**Sample response** - -```json -{ - "id": "424242-4242-42-4242-4242", - "first_name": "Grace", - "last_name": "Hopper", - "token": "JWT_TOKEN" -} -``` - -This endpoint returns the same response as `POST /login`. - -### Conversations - -Please refer to our [conversation](glossary.md#conversation) definition -for more information. - -#### List conversations - -`POST /conversations.list` - -This is a [paginated](#pagination) endpoint. - -**Filtering** - -This endpoint allows you to query conversations using the human readable [Lucene -Query Syntax](https://lucene.apache.org/core/2_9_4/queryparsersyntax.html). You -can query on all fields defined in [this -class](https://github.com/airyhq/airy/blob/main/backend/api/communication/src/main/java/co/airy/core/api/communication/dto/ConversationIndex.java). - -**Sample request** - -Find users whose name ends with "Lovelace": - -```json5 -{ - "filters": "display_name:*Lovelace", // optional - "cursor": "next-page-uuid", - "page_size": 2 -} -``` - -**Sample request** - -```json5 -{ - "cursor": "next-page-uuid", - "page_size": 2 -} -``` - -**Sample response** - -```json5 -{ - "data": [ - { - "id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "channel": { - "name": "Facebook page name", - "source": "facebook", - "id": "318efa04-7cc1-4200-988e-50699d0dd6e3" - }, - "created_at": "2019-01-07T09:01:44.000Z", - "contact": { - // Additional data on the contact - "avatar_url": "https://assets.airy.co/AirySupportIcon.jpg", - "display_name": "Airy Support" - }, - "tags": ["f339c325-8614-43cb-a70a-e83d81bf56fc"], - "last_message": { - id: "{UUID}", - content: [ - { - text: "{String}", - type: "text" - // Determines the schema of the content - }, - ] - // typed source message model - state: "{String}", - // delivery state of message, one of PENDING, FAILED, DELIVERED - sender_type: "{string/enum}", - // See glossary - sent_at: "{string}" - //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients - }, - "unread_message_count": 1 - } - ], - "response_metadata": { - "previous_cursor": "", - "next_cursor": "", - "filtered_total": 1, - "total": 1, - "badge_unread_count": 1 - } -} -``` - -#### Conversation info - -`POST /conversations.info` - -**Sample request** - -```json -{ - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622" -} -``` - -**Sample response** - -```json5 -{ - "id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "channel": { - "name": "facebook", - "id": "318efa04-7cc1-4200-988e-50699d0dd6e3" - }, - "created_at": "2019-01-07T09:01:44.000Z", - "contact": { - "avatar_url": "https://assets.airy.co/AirySupportIcon.jpg", // optional - "display_name": "Airy Support" // optional - }, - "tags": ["f339c325-8614-43cb-a70a-e83d81bf56fc"], - "last_message": { - "id": "{UUID}", - "content": [ - { - "text": "{String}", - "type": "text" - // Determines the schema of the content - } - ], - // typed source message model - "delivery_state": "{String}", - // delivery state of message, one of PENDING, FAILED, DELIVERED - "sender_type": "{string/enum}", - // See glossary - "sent_at": "{string}" - //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients - }, - "unread_message_count": 1 -} -``` - -#### Mark conversation as read - -`POST /conversations.read` - -Resets the unread count of a conversation and returns status code `202 (Accepted)`. - -**Sample request** - -```json -{ - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622" -} -``` - -**Sample response** - -```json5 -{} -``` - -#### Tag a conversation - -Tags an existing conversation with [an existing tag](#creating-a-tag). Returns -status code `200` if successful. - -`POST /conversations.tag` - -**Sample request** - -```json5 -{ - "conversation_id": "CONVERSATION_ID", - "tag_id": "TAG_ID" -} -``` - -**Sample response** - -```json5 -{} -``` - -#### Untag a conversation - -`POST /conversations.untag` - -**Sample request** - -```json5 -{ - "conversation_id": "CONVERSATION_ID", - "tag_id": "TAG_ID" -} -``` - -**Sample response** - -```json5 -{} -``` - -### Messages - -Please refer to our [messages](glossary.md#message) definition for more -information. - -#### List messages - -`POST /messages.list` - -This is a [paginated](#pagination) endpoint. Messages are sorted from oldest to latest. - -**Sample request** - -```json5 -{ - "conversation_id": "4242-4242-4242-424242", - "cursor": "next-page-uuid", // optional - "page_size": 2 // optional -} -``` - -**Sample response** - -```json5 -{ - "data": [ - { - "id": "{UUID}", - "content": [ - { - "text": "{String}", - "type": "text" - // Determines the schema of the content - } - ], - // typed source message model - "state": "{String}", - // delivery state of message, one of PENDING, FAILED, DELIVERED - "sender_type": "{string/enum}", - // See glossary - "sent_at": "{string}" - //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients - } - ], - "response_metadata": { - "previous_cursor": "", - "next_cursor": "", - "filtered_total": 1, - "total": 1 - } -} -``` - -#### Send a message - -`POST /messages.send` - -Sends a message to a conversation and returns a payload. - -**Sending a text message** - -```json5 -{ - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "message": { - "text": "Hello World", - "type": "text" - } -} -``` - -**Sending an attachment message** - -```json5 -{ - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "message": { - "url": "http://example.org/myfile", - "type": "image|video|audio|file" - } -} -``` - -**Sending source templates** - -Some sources support sending templates, which can be used to display rich content such as buttons or cards. You -can send source templates by setting the type to `source.template`. Please refer to the source documentation -to see the expected values for the `payload` field. - -```json5 -{ - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "message": { - "payload": { - "template_type": "buttons", - "buttons": ["Welcome to our shop"] - }, - "type": "source.template" - } -} -``` - -**Sample response** - -```json5 -{ - "id": "{UUID}", - "content": [ - { - "text": "{String}", - "type": "text" - } - ], - "state": "pending|failed|delivered", - "sender_type": "{string/enum}", - // See glossary - "sent_at": "{string}" - //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients -} -``` - -### Channels - -Please refer to our [channel](glossary.md#channel) definition for more -information. - -#### List channels - -`POST /channels.list` - -**Sample response** - -```json5 -{ - "data": [ - { - "id": "channel-uuid-1", - "name": "my page 1", - "source": "facebook", - "source_channel_id": "fb-page-id-1", - "image_url": "http://example.org/avatar.jpeg" // optional - }, - { - "id": "channel-uuid-2", - "name": "my page 2", - "source": "facebook", - "source_channel_id": "fb-page-id-2" - } - ] -} -``` - -### Tags - -Please refer to our [tag](glossary.md#tag) definition for more -information. - -#### Creating a tag - -`POST /tags.create` - -**Sample request** - -```json5 -{ - "name": "Urgent", - "color": "tag-red" // one of tag-red | tag-blue | tag-green | tag-purple -} -``` - -If the tag is successfully created, the request returns status code `201` (created) with the tag ID in the response body. - -**Sample response** - -```json5 -{ - "id": "TAG-UUID" -} -``` - -#### Updating a tag - -`POST /tags.update` - -**Sample request** - -```json -{ - "id": "TAG-ID", - "name": "Urgent", - "color": "tag-blue" // one of tag-red | tag-blue | tag-green | tag-purple -} -``` - -If action is successful, the request returns status code `200`. - -**Sample response** - -```json5 -{} -``` - -#### Deleting a tag - -`POST /tags.delete` - -**Sample request** - -```json -{ - "id": "ID-OF-THE-TAG" -} -``` - -If action is successful, returns HTTP status `200`. - -**Sample response** - -```json5 -{} -``` - -#### Listing tags - -`POST /tags.list` - -**Sample response** - -```json5 -{ - "tags": [ - { - "id": "TAG-ID", - "name": "name of the tag", - "color": "RED" - } - ] -} -``` - -### Metadata - -Refer to our [metadata](glossary.md#metadata) definition for more -information. - -### Setting metadata - -`POST /metadata.set` - -```json -{ - "conversation_id": "conversation-id", - "key": "ad.id", - "value": "Grace" -} -``` - -The endpoint returns status code `200` if the operation was successful, and `400` if not. - -### Removing metadata - -`POST /metadata.remove` - -```json -{ - "conversation_id": "conversation-id", - "key": "ad.id" -} -``` - -This endpoint returns status code `200` if the operation was successful, and `500` if not. - -## Pagination - -By default, paginated endpoints return a maximum of 20 elements on the first page. - -The size of the returned page can be controlled by the `page_size` field of the -body. You can move back and forth between pages using the `cursor` field of the -body. - -Paginated endpoints _always_ respond with the following JSON format: - -```json -{ - "data": [ - { - "id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "field1": "answer is 42", - "field2": "this is fine" - } - ], - "response_metadata": { - "previous_cursor": "", - "next_cursor": "", - "filtered_total": 1, - "total": 1 - } -} -``` - -The response comes in two parts: - -- `data` - - An array of objects. Object specification depends on the endpoint. - -- `response_metadata` - An object with the following fields: - - - `previous_cursor` - - The ID of first elements in the previous page of data. Empty if the returned - page is the first one. - - - `next_cursor` - - The ID of first elements in the next page of data. Empty if the returned - page is the last one. - - - `filtered_total` - - The total number of elements across pages in the context of the current - filter selection. Only applicable to paginated endpoints that can filter - data. - - - `total` - - The total number of elements across all pages. diff --git a/docs/docs/api/introduction.md b/docs/docs/api/introduction.md new file mode 100644 index 0000000000..43a234c61c --- /dev/null +++ b/docs/docs/api/introduction.md @@ -0,0 +1,16 @@ +--- +title: Introduction +sidebar_label: Introduction +--- + +This documents offers a high-level overview of the different parts that +compose the Airy Core API. + +Once you connect Airy Core to a [source](/getting-started/glossary.md#source), the +platform will immediately start consuming conversational data and store it in +its streaming data platform. Airy Core exposes three different ways of +interacting with data: + +- an [HTTP API](/api/endpoints/introduction.md) +- A [WebSocket server](/api/websocket.md) +- A [Webhook integration](/api/webhook.md) diff --git a/docs/docs/api/webhook.md b/docs/docs/api/webhook.md index 519c11e2c4..4a8b23d453 100644 --- a/docs/docs/api/webhook.md +++ b/docs/docs/api/webhook.md @@ -10,7 +10,7 @@ integration pattern: - Call the [subscribe](#subscribing) endpoint - Consume on your URL of choice [events](#event-payload) - React to those events by calling the [send - message](api/http.md#send-a-message) endpoint + message](/api/endpoints/messages.md#send) endpoint You must de-duplicate messages on arrival as the webhook _does not_ guarantee events uniqueness. @@ -94,9 +94,9 @@ request with the following structure: }, "source": "facebook", "sent_at": "2020-07-20T14:18:08.584Z", - "text": "Message to be sent" + "content": '{"text":"Hello World"}' } ``` For possible values of `sender.type` see the [Message model -documentation](glossary.md#fields) +documentation](/getting-started/glossary.md#fields) diff --git a/docs/docs/api/websocket.md b/docs/docs/api/websocket.md index 9145c1b591..5678140783 100644 --- a/docs/docs/api/websocket.md +++ b/docs/docs/api/websocket.md @@ -3,27 +3,26 @@ title: WebSocket sidebar_label: WebSocket --- -## Introduction - -The Airy Core Platform offers a WebSocket server that allows clients to connect -and receive near real-time updates on communication data. The WebSocket server -uses the +Airy Core offers a WebSocket server that allows clients to connect and receive +near real-time updates on communication data. The WebSocket server uses the [STOMP](https://en.wikipedia.org/wiki/Streaming_Text_Oriented_Messaging_Protocol) protocol endpoint at `/ws.communication`. -To execute the handshake with `/ws.communicaiton` you need to set an `Authorization` header where the -value is the authorization token obtained [from the API](http.md#authentication). +To execute the handshake with `/ws.communication` you must set an +`Authorization` header where the value is the authorization token obtained [from +the API](/api/introduction#authentication). ## Outbound Queues -Outbound queues follow the pattern `/queue/:event_type[/:action}]` and -deliver JSON encoded payloads. +Outbound queues follow the pattern `/queue/:event_type[/:action}]` and deliver +JSON encoded payloads. ### Message `/queue/message` -Incoming payloads notify connected clients that a message was created or updated. +Incoming payloads notify connected clients that a message was created or +updated. **Sample payload** @@ -33,12 +32,8 @@ Incoming payloads notify connected clients that a message was created or updated "channel_id": "{UUID}", "message": { "id": "{UUID}", - "content": { - "text": "{String}", - "type": "text" - // Determines the schema of the content - }, - // typed source message model + "content": '{"text":"Hello World"}', + // source message payload "delivery_state": "{String}", // delivery state of message, one of PENDING, FAILED, DELIVERED "sender_type": "{string/enum}", @@ -75,7 +70,8 @@ the value only for a more recent count. `/queue/channel/connected` -Incoming payloads notify connected clients whenever a channel was connected or updated. +Incoming payloads notify connected clients whenever a channel was connected or +updated. **Sample payload** diff --git a/docs/docs/apps/ui.md b/docs/docs/apps/ui.md new file mode 100644 index 0000000000..399d2da48a --- /dev/null +++ b/docs/docs/apps/ui.md @@ -0,0 +1,4 @@ +--- +title: UI +sidebar_label: UI +--- diff --git a/docs/docs/cli/airy.md b/docs/docs/cli/airy.md new file mode 100644 index 0000000000..505636c335 --- /dev/null +++ b/docs/docs/cli/airy.md @@ -0,0 +1,30 @@ +--- +title: Airy +sidebar_label: Airy +--- + +## airy + +airy controls an Airy Core instance + +### Synopsis + +airy controls an Airy Core instance + +### Options + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) + -h, --help help for airy +``` + +### SEE ALSO + +* [airy api](airy_api.md) - Interacts with the Airy Core HTTP API +* [airy config](airy_config.md) - Manages an Airy Core instance via airy.yaml +* [airy init](airy_init.md) - Inits your airy configuration +* [airy status](airy_status.md) - Reports the status of an Airy Core instance +* [airy ui](airy_ui.md) - Opens the Airy Core UI in your local browser +* [airy version](airy_version.md) - Prints version information + diff --git a/docs/docs/cli/airy_api.md b/docs/docs/cli/airy_api.md new file mode 100644 index 0000000000..4ee830de85 --- /dev/null +++ b/docs/docs/cli/airy_api.md @@ -0,0 +1,32 @@ +--- +title: Airy Api +sidebar_label: Airy Api +--- + +## airy api + +Interacts with the Airy Core HTTP API + +### Synopsis + +Interacts with the Airy Core HTTP API + +### Options + +``` + -h, --help help for api +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy](airy.md) - airy controls an Airy Core instance +* [airy api login](airy_api_login.md) - Login into an Airy Core instance +* [airy api signup](airy_api_signup.md) - Signs users up in Airy Core + diff --git a/docs/docs/cli/airy_api_login.md b/docs/docs/cli/airy_api_login.md new file mode 100644 index 0000000000..51300fc744 --- /dev/null +++ b/docs/docs/cli/airy_api_login.md @@ -0,0 +1,36 @@ +--- +title: Airy Api Login +sidebar_label: Airy Api Login +--- + +## airy api login + +Login into an Airy Core instance + +### Synopsis + +Login into an Airy Core instance + +``` +airy api login [flags] +``` + +### Options + +``` + -e, --email string Email (default "grace@example.com") + -h, --help help for login + -p, --password string Password (default "the_answer_is_42") +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy api](airy_api.md) - Interacts with the Airy Core HTTP API + diff --git a/docs/docs/cli/airy_api_signup.md b/docs/docs/cli/airy_api_signup.md new file mode 100644 index 0000000000..6d9836ea7e --- /dev/null +++ b/docs/docs/cli/airy_api_signup.md @@ -0,0 +1,38 @@ +--- +title: Airy Api Signup +sidebar_label: Airy Api Signup +--- + +## airy api signup + +Signs users up in Airy Core + +### Synopsis + +Signs users up in Airy Core + +``` +airy api signup [flags] +``` + +### Options + +``` + -e, --email string Email (default "grace@hopper.com") + -f, --firstName string First name (default "Grace") + -h, --help help for signup + -l, --lastName string Last name (default "Hopper") + -p, --password string Password (default "the_answer_is_42") +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy api](airy_api.md) - Interacts with the Airy Core HTTP API + diff --git a/docs/docs/cli/airy_config.md b/docs/docs/cli/airy_config.md new file mode 100644 index 0000000000..f4df7bb3e0 --- /dev/null +++ b/docs/docs/cli/airy_config.md @@ -0,0 +1,33 @@ +--- +title: Airy Config +sidebar_label: Airy Config +--- + +## airy config + +Manages an Airy Core instance via airy.yaml + +### Synopsis + +Manages an Airy Core instance via airy.yaml + +### Options + +``` + --config string Configuration file for an Airy Core instance (default "./airy.yaml") + -h, --help help for config + --kube-config string Kubernetes config file for the cluster of an Airy Core instance (default "~/.airy/kube.conf") +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy](airy.md) - airy controls an Airy Core instance +* [airy config apply](airy_config_apply.md) - Applies configuration values from airy.yaml configuration to an Airy Core instance + diff --git a/docs/docs/cli/airy_config_apply.md b/docs/docs/cli/airy_config_apply.md new file mode 100644 index 0000000000..25d43cce7e --- /dev/null +++ b/docs/docs/cli/airy_config_apply.md @@ -0,0 +1,36 @@ +--- +title: Airy Config Apply +sidebar_label: Airy Config Apply +--- + +## airy config apply + +Applies configuration values from airy.yaml configuration to an Airy Core instance + +### Synopsis + +Applies configuration values from airy.yaml configuration to an Airy Core instance + +``` +airy config apply [flags] +``` + +### Options + +``` + -h, --help help for apply +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) + --config string Configuration file for an Airy Core instance (default "./airy.yaml") + --kube-config string Kubernetes config file for the cluster of an Airy Core instance (default "~/.airy/kube.conf") +``` + +### SEE ALSO + +* [airy config](airy_config.md) - Manages an Airy Core instance via airy.yaml + diff --git a/docs/docs/cli/airy_init.md b/docs/docs/cli/airy_init.md new file mode 100644 index 0000000000..d2b8344dc2 --- /dev/null +++ b/docs/docs/cli/airy_init.md @@ -0,0 +1,34 @@ +--- +title: Airy Init +sidebar_label: Airy Init +--- + +## airy init + +Inits your airy configuration + +### Synopsis + +Inits your airy configuration + +``` +airy init [flags] +``` + +### Options + +``` + -h, --help help for init +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy](airy.md) - airy controls an Airy Core instance + diff --git a/docs/docs/cli/airy_status.md b/docs/docs/cli/airy_status.md new file mode 100644 index 0000000000..1f2c0167bf --- /dev/null +++ b/docs/docs/cli/airy_status.md @@ -0,0 +1,34 @@ +--- +title: Airy Status +sidebar_label: Airy Status +--- + +## airy status + +Reports the status of an Airy Core instance + +### Synopsis + +Reports the status of an Airy Core instance + +``` +airy status [flags] +``` + +### Options + +``` + -h, --help help for status +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy](airy.md) - airy controls an Airy Core instance + diff --git a/docs/docs/cli/airy_ui.md b/docs/docs/cli/airy_ui.md new file mode 100644 index 0000000000..5cc826efda --- /dev/null +++ b/docs/docs/cli/airy_ui.md @@ -0,0 +1,34 @@ +--- +title: Airy Ui +sidebar_label: Airy Ui +--- + +## airy ui + +Opens the Airy Core UI in your local browser + +### Synopsis + +Opens the Airy Core UI in your local browser + +``` +airy ui [flags] +``` + +### Options + +``` + -h, --help help for ui +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy](airy.md) - airy controls an Airy Core instance + diff --git a/docs/docs/cli/airy_version.md b/docs/docs/cli/airy_version.md new file mode 100644 index 0000000000..d38b3873d2 --- /dev/null +++ b/docs/docs/cli/airy_version.md @@ -0,0 +1,34 @@ +--- +title: Airy Version +sidebar_label: Airy Version +--- + +## airy version + +Prints version information + +### Synopsis + +Prints version information + +``` +airy version [flags] +``` + +### Options + +``` + -h, --help help for version +``` + +### Options inherited from parent commands + +``` + --apihost string Airy Core HTTP API host (default "http://api.airy") + --cli-config string config file (default is $HOME/.airy/cli.yaml) +``` + +### SEE ALSO + +* [airy](airy.md) - airy controls an Airy Core instance + diff --git a/docs/docs/overview/architecture.md b/docs/docs/concepts/architecture.md similarity index 70% rename from docs/docs/overview/architecture.md rename to docs/docs/concepts/architecture.md index d68ccd1eb9..56b8c92c7b 100644 --- a/docs/docs/overview/architecture.md +++ b/docs/docs/concepts/architecture.md @@ -1,25 +1,25 @@ --- -title: The Airy Core Platform architecture +title: The Airy Core architecture sidebar_label: Architecture --- ## Overview -The Airy Core Platform is a messaging platform that contains a backend and frontend system. +Airy Core is a messaging platform that contains a backend and frontend system. The `backend` system is a streaming platform. Its role is to: - Ingest conversational events from different sources (mostly via webhook integrations), process them, and store them in an Apache Kafka cluster. -- Make the processed events available and accessible through the Airy [API](api/http.md). -- Expose conversational events via a [webhook](api/webhook.md) integration. +- Make the processed events available and accessible through the [Core API](/api/introduction). +- Expose conversational events via a [webhook](/api/webhook) integration. - Manage authentication and authorization features. The `frontend` system contains a demo application and the JavaScript integration of the [Chat Plugin](sources/chat-plugin.md). Having that in mind, these are the docker containers – or the `Airy apps` – -which run as part of the Airy Core Platform: +which run as part of Airy Core: ## Sources @@ -46,10 +46,11 @@ which run as part of the Airy Core Platform: ## Airy Controller -The Airy Core Platform ships with a Kubernetes controller, which is responsible for starting and reloading the appropriate Airy apps based on the provided configuration. -The controller as a deployment named `airy-controller`. +Airy Core ships with a Kubernetes controller, which is responsible for starting +and reloading the appropriate Airy apps based on the provided configuration. The +controller as a deployment named `airy-controller`. ## Airy CLI -Every release features a command line binary, used to configure and fetch status information from the Airy Core Platform. -This tool is referred to as the `Airy CLI` throughout the documentation. +Every release features a command line binary, used to configure and fetch status +information from your Airy Core instance. This tool is referred to as the `Airy CLI` throughout the documentation. diff --git a/docs/docs/overview/design-principles.md b/docs/docs/concepts/design-principles.md similarity index 74% rename from docs/docs/overview/design-principles.md rename to docs/docs/concepts/design-principles.md index bbdda5b1c1..645f5b0b18 100644 --- a/docs/docs/overview/design-principles.md +++ b/docs/docs/concepts/design-principles.md @@ -3,22 +3,22 @@ title: Design Principles sidebar_label: Design Principles --- -The design of the Airy Core Platform heavily relies on a few core ideas. The +The design of the Airy Core platform heavily relies on a few core ideas. The goal of this document is to provide context about these ideas and how they affected the way the platform is built. ## One source of truth, no shared state -The most central idea behind the design of the Airy Core Platform is composed of +The most central idea behind the Airy Core design is composed of two connected principles. Here's the first one: > There's one source of truth for data and that place is a [Apache > Kafka](https://kafka.apache.org). -We mean that _all_ of the data the Airy Core Platform lives in Kafka. One way of -thinking about the Airy Core Platform as a strongly typed (via -[Avro](https://avro.apache.org)) data pipeline. The HTTP endpoints the platform -provide also solely rely on Kafka via a feature called [interactive +We mean _all_ of the data of an Airy Core instance lives in Kafka. One way of +thinking about it: as a strongly typed (via [Avro](https://avro.apache.org)) +data pipeline. The HTTP endpoints the platform provide also solely rely on Kafka +via a feature called [interactive queries](https://kafka.apache.org/documentation/streams/developer-guide/interactive-queries.html). And here's the second principle: @@ -28,7 +28,7 @@ And here's the second principle: What we mean is that we do not allow services to talk to each other and share state via internal HTTP calls. Let's use an example to clarify: imagine we have a service dealing with `conversations` data that needs `channels` data (see our -[glossary](glossary.md) for more information) to build a JSON response. Many +[glossary](getting-started/glossary.md) for more information) to build a JSON response. Many systems would work like this: - A client asks for `conversations` @@ -36,7 +36,7 @@ systems would work like this: - Once it obtains a response, it merges the data with the `conversations` - It returns the data to the client -In the Airy Core Platform, it works like this: +In Airy Core, it works like this: - A client asks for `conversations` - the service in charge has both `conversations` and `channels` data @@ -51,11 +51,11 @@ we avoid any dependencies between services. Our _default_ choice for testing is high-level integration tests. As "integration tests" may mean different things to different people, we explain in -the following what it means for the Airy Core Platform. +the following what it means for us. -Most components of the Airy Core Platform have multiple dependencies. For -example, our HTTP endpoints are Kafka Streams applications that expose data via -interactive queries. These endpoints depend on: +Most components of Airy Core have multiple dependencies. For example, our HTTP +endpoints are Kafka Streams applications that expose data via interactive +queries. These endpoints depend on: - Apache Kafka - Apache Zookeeper (indirectly as Kafka depends on it) diff --git a/docs/docs/overview/kafka.md b/docs/docs/concepts/kafka.md similarity index 97% rename from docs/docs/overview/kafka.md rename to docs/docs/concepts/kafka.md index e81b9fd1a6..a7a2523b45 100644 --- a/docs/docs/overview/kafka.md +++ b/docs/docs/concepts/kafka.md @@ -4,7 +4,7 @@ sidebar_label: Kafka --- The goal of this document is to provide information about how we use Kafka in -the Airy Core Platform. +Airy Core. ## Topic naming conventions diff --git a/docs/docs/overview/release-process.md b/docs/docs/concepts/release-process.md similarity index 77% rename from docs/docs/overview/release-process.md rename to docs/docs/concepts/release-process.md index 7f11157026..0b96370ef9 100644 --- a/docs/docs/overview/release-process.md +++ b/docs/docs/concepts/release-process.md @@ -3,10 +3,10 @@ title: Release Process sidebar_label: Release Process --- -The Airy Core Platform follows a scheduled release process: we release a new -version every two-weeks. This approach allows us to ship smaller releases which -ease the risk of breaking changes and brings new features and bug-fixes to our -users in a timely manner. +Airy Core follows a scheduled release process: we release a new version every +two-weeks. This approach allows us to ship smaller releases which ease the risk +of breaking changes and brings new features and bug-fixes to our users in a +timely manner. Here's an outline of the process: diff --git a/docs/docs/getting-started/cli.md b/docs/docs/getting-started/cli.md new file mode 100644 index 0000000000..3e581c1d19 --- /dev/null +++ b/docs/docs/getting-started/cli.md @@ -0,0 +1,12 @@ +--- +title: Command Line Interface +sidebar_label: Overview +--- + +## CLI + +> _Start, manage, and test instances of Airy Core right from the terminal_ + +The Airy CLI is a developer tool to help you build, test, and manage Airy directly from your terminal. + +The CLI is easy to [install](/getting-started/installation.md) and works on macOS, Windows, and Linux. diff --git a/docs/docs/getting-started/deployment/introduction.md b/docs/docs/getting-started/deployment/introduction.md new file mode 100644 index 0000000000..a7fd62571a --- /dev/null +++ b/docs/docs/getting-started/deployment/introduction.md @@ -0,0 +1,13 @@ +--- +title: Introduction +sidebar_label: Introduction +--- + +You can choose to deploy Airy Core in many different ways: locally with Vagrant +or production-ready in your cloud or AWS, Google, Azure or Digital Ocean. + +The following documentation covers how to install Airy Core locally (using +Vagrant) or deploy it with various hosting options: + +- Try it locally with [Vagrant](vagrant.md) +- Install Airy Core in a [production environment](production.md) diff --git a/docs/docs/guides/airy-core-in-production.md b/docs/docs/getting-started/deployment/production.md similarity index 77% rename from docs/docs/guides/airy-core-in-production.md rename to docs/docs/getting-started/deployment/production.md index 989c8bedad..a326de23a5 100644 --- a/docs/docs/guides/airy-core-in-production.md +++ b/docs/docs/getting-started/deployment/production.md @@ -1,24 +1,24 @@ --- -title: Running the Airy Core Platform in production +title: Production sidebar_label: Production --- -This document provides our recommendations on how to run the Airy Core Platform +This document provides our recommendations on how to run the Airy Core in production environments. If you are not familiar with the architecture of the -system, we suggest you read the [Architecture](/overview/architecture.md) document before +system, we suggest you read the [Architecture](/concepts/architecture.md) document before proceeding. ## Requirements -The `Airy apps` are the services which comprise the `Airy Core Platform`. They -run as docker containers and require access to several other services to be in -place before they can be started: +The `Airy apps` are the services which comprise `Airy Core`. They run as docker +containers and require access to several other services to be in place before +they can be started: - `Kafka cluster`: Kafka, Zookeeper and the Confluent Schema registry. These three services comprise the Kafka store. They are the default storage system - of the Airy Core Platform. Kafka requires Zookeeper to work. The Confluent - Schema registry facilitates Avro typed data pipelines. All our Kafka based - applications require the registry to work. + of Airy Core. Kafka requires Zookeeper to work. The Confluent Schema registry + facilitates Avro typed data pipelines. All our Kafka based applications + require the registry to work. - `PostgreSQL`: Where we store authentication data. - `Redis`: The queuing system used by our webhook system relies on Redis. @@ -64,7 +64,7 @@ following environment variables to run: - `PARTITIONS` (default: 10) - `REPLICAS` (default: 1) - `AIRY_CORE_NAMESPACE` (default: ''). Helpful to namespace your topics in case - you are installing the Airy Core Platform in an existing Kafka cluster + you are installing the Airy Core in an existing Kafka cluster We do not recommend running Kafka on docker for production environments. However, we provide a way to deploy the whole Kafka cluster on top of Kubernetes @@ -73,7 +73,7 @@ with Helm as we use this approach for test installations. The default commit interval is set to 1000 ms (1 second). This is _not_ recommended for production usage. You change the `commitInterval` to a more suitable production value in the configuration file -`infrastructure/helm-chart/charts/apps/charts/airy-config/values.yaml`. +`infrastructure/helm-chart/charts/prerequisites/values.yaml`. To deploy Kafka on Kubernetes with Helm, you can run: @@ -134,16 +134,15 @@ helm template ./infrastructure/helm-chart ## Running the Airy apps -So far the Airy Core Platform has been tested on K3s, Minikube and AWS EKS. The -following configuration and deployment instructions are applicable to any -Kubernetes implementation as they depend on widely supported Kubernetes -features. In order to proceed with deploying the apps, we assume that you have a -running Kubernetes cluster, properly configured KUBECONF file and properly set -context. +So far Airy Core has been tested on K3s, Minikube and AWS EKS. The following +configuration and deployment instructions are applicable to any Kubernetes +implementation as they depend on widely supported Kubernetes features. In order +to proceed with deploying the apps, we assume that you have a running Kubernetes +cluster, properly configured KUBECONF file and properly set context. -The Airy Core Platform ships with a Kubernetes controller, which is responsible for -starting and reloading the appropriate Airy apps based on the provided configuration. -The controller as a deployment named `airy-controller`. +Airy Core ships with a Kubernetes controller, which is responsible for starting +and reloading the appropriate Airy apps based on the provided configuration. The +controller as a deployment named `airy-controller`. ### Configuration @@ -180,8 +179,9 @@ Most message sources allow users to send rich data such as images, videos and au the Urls that host this data expire which is why after some time you may find that conversations have inaccessible content. -The Airy Core Platform allows you to persist this data to a storage of your choice. To take advantage of this -you must provide access credentials to your storage. The platform currently supports [s3](https://aws.amazon.com/s3/): +Airy Core allows you to persist this data to a storage of your choice. To take +advantage of this you must provide access credentials to your storage. The +platform currently supports [s3](https://aws.amazon.com/s3/): ```yaml apps: @@ -203,9 +203,11 @@ must configure the system via the `airy.yaml` file, then you can proceed: helm install core ./helm-chart/charts/apps/ --values ./airy.yaml --timeout 1000s ``` -The API `Airy apps`, the Frontend UI and the Frontend Chatplugin start by default, while all the other apps are optional and are started if there is provided configuration for them in the `airy.yaml` file. +The API `Airy apps`, the Frontend UI and the Frontend of the Airy Live Chat +plugin start by default, while all the other apps are optional and are started +if there is provided configuration for them in the `airy.yaml` file. -At this point you should have a running `Airy Core Platform` in your environment 🎉. +At this point you should have a running `Airy Core` in your environment 🎉. If afterwards you need to modify or add other config parameters in the `airy.yaml` file, after editing the file run: @@ -214,10 +216,12 @@ If afterwards you need to modify or add other config parameters in the airy config apply --config ./airy.yaml --kube-config /path/to/your/kube.conf ``` -Make sure you point the `--kube-config` flag to your Kubernetes configuration file. +Make sure you point the `--kube-config` flag to your Kubernetes configuration +file. -If you want to deploy the Airy Core Platform with a specific version, you must set the version in your -`airy.yaml` file, under the `global.appImageTag` configuration key. +If you want to deploy a specific version of Airy Core, you must set the version +in your `airy.yaml` file, under the `global.appImageTag` configuration key to +the desired version. ## Network @@ -225,10 +229,10 @@ If you want to deploy the Airy Core Platform with a specific version, you must s The helm chart creates separate NodePort service for every source with the naming convention `sources-SOURCE_NAME-webhook`. These services must be exposed -publicly on the Internet, so that the sources can send messages and events to -the webhook services, inside the Kubernetes cluster. +publicly on the Internet, so that Airy Core can integrate with the source via a +webhook. -To get the ports on which the webhook services are running, you can run: +Find out on which ports the webhook services are running: ```sh kubectl get service -l airy=sources.webhook --output jsonpath={.items[*].spec.ports[*].nodePort} @@ -256,21 +260,23 @@ Ingress resources. You can choose an [Kubernetes ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) in accordance to your needs or preferences. If you are using the [Traefik](https://traefik.io/) ingress controller, you can edit the -`infrastructure/helm-chart/charts/ingress/templates/ingress.yaml` file to modify the `host` records and apply the ingress helm chart, which is already included in the repository: +`infrastructure/helm-chart/templates/ingress.yaml` file to modify the `host` +records and apply the Kubernetes manifest: -```sh -helm install ingress infrastructure/helm-chart/charts/ingress/ +```bash script +kubectl apply -f infrastructure/helm-chart/templates/ingress.yaml ``` You must set appropriate `host` attributes in the rules for: - API endpoints (defaults to `api.airy`) +- Webhooks endpoints (defaults to `webhooks.airy`) - Demo (defaults to `demo.airy`) - Chat plugin (defaults to `chatplugin.airy`) If you are not using Traefik, you can use the -`infrastructure/helm-chart/charts/ingress/templates/ingress.yaml` file as a guide to create your own -Kubernetes manifest for your preferred ingress controller. +`infrastructure/helm-chart/templates/ingress.yaml` file as a guide to create +your own Kubernetes manifest for your preferred ingress controller. If your Kubernetes cluster is not directly reachable on the Internet, you will need a public LoadBalancer or a `reverse proxy` to tunnel the traffic to the diff --git a/docs/docs/guides/airy-core-in-test-env.md b/docs/docs/getting-started/deployment/vagrant.md similarity index 50% rename from docs/docs/guides/airy-core-in-test-env.md rename to docs/docs/getting-started/deployment/vagrant.md index 7f38ee4162..db5cfd8c89 100644 --- a/docs/docs/guides/airy-core-in-test-env.md +++ b/docs/docs/getting-started/deployment/vagrant.md @@ -1,91 +1,58 @@ --- -title: Running the Airy Core Platform in a test environment -sidebar_label: Test +title: Vagrant +sidebar_label: Vagrant --- -The goal of this document is to provide an overview of how to run the Airy Core -Platform on your local machine. +import useBaseUrl from '@docusaurus/useBaseUrl'; -To facilitate bootstrapping the Airy Core Platform on a single machine, we -included a [Vagrant](https://www.vagrantup.com) configuration, inside the -`infrastructure` directory. +The goal of this document is to provide an overview of how to run Airy Core on +your local machine using [Vagrant](https://www.vagrantup.com). -The Vagrant box is based on Alpine Linux and contains a pre-configured -Kubernetes cluster [K3OS](https://k3os.io/) to deploy and run the Airy Core -Platform. components. - -## Getting started - -To bootstrap a test installation, refer to the [bootstrapping](/index.md#bootstrapping-the-airy-core-platform) document. - -## Manage your Vagrant box +To facilitate bootstrapping Airy Core on a single machine, we included a Vagrant +configuration inside the `infrastructure` directory. -You can ssh inside the Airy Core Platform box for testing and debugging purposes -with `vagrant ssh` or run commands directly with `vagrant ssh -c COMMAND` +The Vagrant box is based on Alpine Linux and contains a pre-configured +Kubernetes cluster [K3OS](https://k3os.io/) to deploy and run Airy Core +components. -### Status +## Run the Bootstrap script -To view the status of the Vagrant box run: +Create an Airy Core instance locally by entering the following commands: -```sh -cd infrastructure -vagrant status +```bash +git clone -b main https://github.com/airyhq/airy +cd airy +./scripts/bootstrap.sh ``` -or +The bootstrap installation requires +[Vagrant](https://www.vagrantup.com/downloads) and +[VirtualBox](https://www.virtualbox.org/wiki/Downloads). If they are not found, +the script will attempt to install them for you. -```sh -cd infrastructure -vagrant ssh -c /vagrant/scripts/status.sh -``` +If Vagrant or VirtualBox cannot be installed with the `bootstrap.sh` script, you +need to install them manually. -The status command will print the following information: +The script will also ask for your administrative credentials as we are using the +[Vagrant Host Manager +Plugin](https://github.com/devopsgroup-io/vagrant-hostmanager) to add entries to +your hosts file. You can skip this step and add the following lines to your +hosts file yourself. -```sh -"Your public url for the Facebook Webhook is:" -${FACEBOOK_WEBHOOK_PUBLIC_URL}/facebook - -"Your public url for the Google Webhook is:" -${GOOGLE_WEBHOOK_PUBLIC_URL}/google - -"Your public url for the Twilio Webhook is:" -${TWILIO_WEBHOOK_PUBLIC_URL}/twilio - -"You can access the API of the Airy Core Platform at:" -"http://api.airy/" - -"Example:" -"curl -X POST -H 'Content-Type: application/json' -d '{\"first_name\": \"Grace\",\"last_name\": \"Hopper\",\"password\": \"the_answer_is_42\",\"email\": \"grace@example.com\"}' ``` - -### Inspect Kubernetes - -```sh -cd infrastructure -vagrant ssh -kubectl get pods +192.168.50.5 demo.airy +192.168.50.5 api.airy +192.168.50.5 chatplugin.airy ``` -### Start, stop, restart - -You can stop, start or restart the Airy Core Platform box with the following -commands: - -```sh -cd infrastructure -vagrant halt -vagrant up -vagrant reload -``` - -### Re-create the environment - -You can delete and re-create the whole environment with the following commands: +After the bootstrap process finishes, it will download the Kubernetes +configuration file to the local host machine under `~/.airy/kube.conf`. That +file is required for the Airy Command Line tool (Airy CLI), in order to access +the Kubernetes cluster where your Airy Core instance is running. You can also +use that configuration file with the `kubectl` utility, for example: ```sh -cd infrastructure -vagrant destroy -vagrant up +kubectl --kubeconfig ~/.airy/kube.conf get pods ``` ## Access the API @@ -94,18 +61,20 @@ The API services are available under the domain `http://api.airy` from your local machine. You can see an example request to the API by running the `status` command. -## Access the frontend UI +## Access the UI -The frontend UI for the demo app can be accessed through http://demo.airy. +The UI can be accessed through http://demo.airy. The frontend UI for the Airy chat plugin can be accessed through -http://chatplugin.airy/example. +http://chatplugin.airy/example. Refer to [the Airy Live Chat +plugin](/sources/chat-plugin.md) documentation for detailed information. ## Public webhooks The public webhook URLs are generated during the bootstrap process and are displayed after the process finishes. Find your current webhook URLs and your -API local address by running the `status` command. +API local address by running the `/vagrant/scripts/status.sh` command from +inside the Airy Core Vagrant box. In order to integrate with the webhook of most sources on your local machine, we included a [ngrok](https://ngrok.com/) client as a sidecar container in each @@ -135,13 +104,19 @@ If you prefer to use your own ngrok implementation or point the ngrok client to connect to the service provided by the ngrok company at `https://ngrok.io`, change the setting for `server_addr` in the ConfigMap or in this helm chart document -`infrastructure/helm-chart/charts/apps/charts/airy-config/templates/sources.yaml`. +`infrastructure/helm-chart/templates/ngrok.yaml`. + +Ngrok can be disabled during the bootstrap process: + +```bash +NGROK_ENABLED=false ./scripts/bootstrap.sh +``` The bootstrap process creates a random URL which is then provisioned inside the Helm chart. To configure these URLs, you can specify them in the -`infrastructure/helm-chart/charts/apps/charts/airy-config/values.yaml` document. -Alternatively you can edit the `airy.yaml` file by setting the following -parameter (see `airy.tpl.yaml` for more examples): +`infrastructure/helm-chart/values.yaml` document. Alternatively you can edit the +`airy.yaml` file by setting the following parameter (see `airy.tpl.yaml` for +more examples): ``` sources: @@ -149,7 +124,8 @@ sources: webhookPublicUrl: https://public-url-for-SOURCE_NAME-webhook ``` -After preparing the configuration, run the following commands to apply the changes: +After preparing the configuration, run the following commands to apply the +changes: ```sh cd infrastructure @@ -160,30 +136,31 @@ helm upgrade core ~/airy-core/helm-chart/charts/apps/ --values /vagrant/airy.yam ## Connect sources -Integrating sources into the `Airy Core Platform` often requires specific -configuration settings, refer to the source specific docs for details. You must -provide the settings in `infrastructure/airy.yaml` configuration file. An -example of the configuration can be found in `airy.tpl.yaml`. +Integrating sources into the `Airy Core` often requires specific configuration +settings, refer to the source specific docs for details. You must provide the +settings in `infrastructure/airy.yaml` configuration file. An example of the +configuration can be found in `airy.tpl.yaml`. -After setting the configuration, you need the Airy command line binary (Airy CLI), to communicate with the core installation and apply the installation. -Building and releasing the Airy CLI is part of the regular release process of the Airy Core Platform. -You can download the Airy CLI from the releases page on Github https://github.com/airyhq/airy/releases. +After setting the configuration, you need the Airy command line binary (Airy +CLI), to communicate with the core installation and apply the installation. +Building and releasing the Airy CLI is part of the regular release process of +the Airy Core. You can download the Airy CLI from the releases page on Github +https://github.com/airyhq/airy/releases. -After downloading, run the following commands: +After downloading it, run the following commands: ```sh airy init airy apply config --config ./airy.yaml ``` -Make sure that the argument `` points to your `airy.yaml` configuration file. - -The Airy CLI considers that the kubernetes configuration file is located under `~/.airy/kube.conf`. -If you modified the location of the file, make sure to set the appropriate path with the `--kube-config` flag. +The Airy CLI considers that the Kubernetes configuration file is located under +`~/.airy/kube.conf`. If you modified the location of the file, make sure to set +the appropriate path with the `--kube-config` flag. -## Uninstall the Airy Core Platform +## Uninstall Airy Core -You can remove the Airy Core Platform Box from your machine completely running +You can remove the Airy Core Vagrant box from your machine completely running the following commands: ```sh @@ -191,6 +168,96 @@ cd infrastructure vagrant destroy ``` +## Manage your Vagrant box + +You can ssh inside the Airy Core box for testing and debugging purposes with +`vagrant ssh` or run commands directly with `vagrant ssh -c COMMAND` + +### Status + +To view the status of the Vagrant box run: + +```sh +cd infrastructure +vagrant status +``` + +or + +```sh +cd infrastructure +vagrant ssh -c /vagrant/scripts/status.sh +``` + +The status command will print the following information: + +```sh +"Your public url for the Facebook Webhook is:" +${FACEBOOK_WEBHOOK_PUBLIC_URL}/facebook + +"Your public url for the Google Webhook is:" +${GOOGLE_WEBHOOK_PUBLIC_URL}/google + +"Your public url for the Twilio Webhook is:" +${TWILIO_WEBHOOK_PUBLIC_URL}/twilio + +"You can access the API of Airy Core at:" +"http://api.airy/" + +"Example:" +"curl -X POST -H 'Content-Type: application/json' -d '{\"first_name\": \"Grace\",\"last_name\": \"Hopper\",\"password\": \"the_answer_is_42\",\"email\": \"grace@example.com\"}' +``` + +### Overwrite default CPUs and memory + +You can specify number of CPU and memory (in MB) you want to use for your Airy Core box with the following ENV variables: + +```sh +AIRY_CORE_CPUS=2 AIRY_CORE_MEMORY=4096 ./scripts/bootstrap.sh +``` + +### Inspect Kubernetes + +```sh +cd infrastructure +vagrant ssh +kubectl get pods +``` + +### Start, stop, restart + +You can stop, start or restart the Airy Core box with the following +commands: + +```sh +cd infrastructure +vagrant halt +vagrant up +vagrant reload +``` + +:::note + +If you bootstrapped your Airy Core with custom CPU/RAM values, you must specify them again when you restart your box. + +```sh +cd infrastructure +vagrant halt +AIRY_CORE_CPUS=2 AIRY_CORE_MEMORY=4096 vagrant up +``` + +::: + +### Re-create the environment + +You can delete and re-create the whole environment with the following commands: + +```sh +cd infrastructure +vagrant destroy +vagrant up +``` + ## Known Issues If you have just installed VirtualBox and see this error during the bootstrap diff --git a/docs/docs/glossary.md b/docs/docs/getting-started/glossary.md similarity index 80% rename from docs/docs/glossary.md rename to docs/docs/getting-started/glossary.md index 26f8c25169..85c6bdded4 100644 --- a/docs/docs/glossary.md +++ b/docs/docs/getting-started/glossary.md @@ -4,7 +4,7 @@ title: Glossary sidebar_label: Glossary --- -This document aims to provide an high-level overview of the Airy Core Platform +This document aims to provide an high-level overview of the Airy Core technical vocabulary. It provides definition of the most important terms used both in the code and in the rest of the documentation. @@ -16,12 +16,11 @@ model and glossary do not correspond exactly. The former is the exact machine representation of the data we store and the latter is a conceptual artifact we created to discuss and solve problems. -The Airy Core Platform allows its [users](#user) to process messaging data from -a variety of [sources](#source), which are integrated via [source -providers](#provider). Users] connect sources via [channels](#channel). -Once the channel is connected, the Airy Core Platform ingests source data and -transforms them into [conversations](#conversation), [contacts](#contact), and -[messages](#message). +Airy Core allows its [users](#user) to process messaging data from a variety of +[sources](#source), which are integrated via [source providers](#provider). +Users connect sources via [channels](#channel). Once the channel is connected, +Airy Core ingests source data and transforms them into +[conversations](#conversation), [contacts](#contact), and [messages](#message). ## Channel @@ -79,7 +78,7 @@ Identifies the participant that sent the message. Interpretation is based on the - `channelId` uuid -- `content` string Immutable string version of the ingested content. APIs dynamically parse and map it to a schema using the mapping library. +- `content` string Immutable string version of the ingested content. - `offset` long sequence number of message within a conversation @@ -119,20 +118,20 @@ e.g. A tag is a specialized metadata, which is used to tag [conversations](#conversation). As the use case of tagging conversations is so -common, the Airy Core Platform provides specialized endpoints and filters for -tagging conversations. +common, Airy Core provides specialized endpoints and filters for tagging +conversations. ## Source A source represents a system that generates messaging data that a user wants to -process with the Airy Core Platform. +process with Airy Core. ### Provider -Source providers are API platforms that allow the Airy Core Platform to connect -to one or more of their sources typically via a webhook. E.g. Twilio is a source -provider for the Twilio SMS and WhatsApp sources. +Source providers are API platforms that allow Airy Core to connect to one or +more of their sources typically via a webhook. E.g. Twilio is a source provider +for the Twilio SMS and WhatsApp sources. ## User -A user represents one authorized agent in the Airy Core Platform. +A user represents one authorized agent in Airy Core. diff --git a/docs/docs/getting-started/installation.md b/docs/docs/getting-started/installation.md new file mode 100644 index 0000000000..762bd3841d --- /dev/null +++ b/docs/docs/getting-started/installation.md @@ -0,0 +1,154 @@ +--- +title: Installation +sidebar_label: Installation +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +You can run the entire Airy Core on your machine [inside an isolated Vagrant box](/getting-started/deployment/vagrant.md). We recommend to install the Aiy CLI first which will aid you in the process of installing and managing your Airy Core instance. + +## Install the Airy CLI + +### Download the binary with curl + +1. Download the latest release with: + + + + +```bash +curl "https://airy-core-binaries.s3.amazonaws.com/$(curl -L -s https://airy-core-binaries.s3.amazonaws.com/stable.txt)/darwin/amd64/airy" -o "airy" +``` + +:::note + +To download a specific version, replace the `$(curl -L -s https://airy-core-binaries.s3.amazonaws.com/stable.txt)` portion of the command with the specific version. + +For example, to download version 0.6.0 on macOS, type: + +curl https://airy-core-binaries.s3.amazonaws.com/0.6.0/darwin/amd64/airy -o "airy" +::: + + + + +```bash +curl -LO "https://airy-core-binaries.s3.amazonaws.com/$(curl -L -s https://airy-core-binaries.s3.amazonaws.com/stable.txt)/linux/amd64/airy" -o "airy" +``` + +:::note + +To download a specific version, replace the `$(curl -L -s https://airy-core-binaries.s3.amazonaws.com/stable.txt)` portion of the command with the specific version. + +For example, to download version 0.6.0 on Linux, type: + +curl https://airy-core-binaries.s3.amazonaws.com/0.6.0/linux/amd64/airy -o "airy" +::: + + + + + + + + +1. Validate the binary (optional) +2. Make the **airy** binary executable. + +```bash +chmod +x ./airy +``` + +4. Move the **airy** binary to a file location on your system PATH. + +``` +sudo mv ./airy /usr/local/bin/airy && \ +sudo chown root: /usr/local/bin/airy +``` + + + + + +2. Validate the binary (optional) +3. Install **airy** + +```bash +sudo install -o root -g root -m 0755 airy /usr/local/bin/airy +``` + + + + +### Build the Airy CLI from source + +1. Build the cli target with Bazel + +```bash +bazel build //infrastructure/cli:airy +``` + +2. Move the **airy** binary to a file location on your system PATH. + +```bash +sudo cp bazel-out/darwin-fastbuild/bin/infrastructure/cli/airy /usr/local/bin/airy +``` + +## Bootstrap Airy Core + +Create an Airy Core instance locally by entering the following commands: + +```bash +git clone -b main https://github.com/airyhq/airy +cd airy +./scripts/bootstrap.sh +``` + +The bootstrap installation requires +[Vagrant](https://www.vagrantup.com/downloads) and +[VirtualBox](https://www.virtualbox.org/wiki/Downloads). If they are not found, +the script will attempt to install them for you. + +If Vagrant or VirtualBox cannot be installed with the `bootstrap.sh` script, you +need to install them manually. + +The script will also ask for your administrative credentials as we are using the +[Vagrant Host Manager +Plugin](https://github.com/devopsgroup-io/vagrant-hostmanager) to add entries to +your hosts file. You can skip this step and add the following lines to your +hosts file yourself. + +``` +192.168.50.5 demo.airy +192.168.50.5 api.airy +192.168.50.5 chatplugin.airy +``` + +After the bootstrap process finishes, it will download the Kubernetes +configuration file to the local host machine under `~/.airy/kube.conf`. That +file is required for the Airy Command Line tool (Airy CLI), in order to access +the Kubernetes cluster where your Airy Core instance is running. You can also +use that configuration file with the `kubectl` utility, for example: + +```sh +kubectl --kubeconfig ~/.airy/kube.conf get pods +``` + +Check out our [guide for running Airy Core in a test +environment](getting-started/deployment/vagrant.md) for detailed information. diff --git a/docs/docs/getting-started/introduction.md b/docs/docs/getting-started/introduction.md new file mode 100644 index 0000000000..380fd4f891 --- /dev/null +++ b/docs/docs/getting-started/introduction.md @@ -0,0 +1,48 @@ +--- +title: Introduction +sidebar_label: Introduction +slug: / +--- + +## What is Airy Core? + +> Airy Core is an **open source**, **fully-featured**, **production-ready** messaging platform. + +With Airy Core you can process conversational data from a variety of sources: + +- Facebook Messenger +- WhatsApp Business API +- Google's Business Messages +- SMS +- Website Chat Plugins +- Your own conversational channels + +You can then use Airy Core to: + +- Unify your messaging channels +- Stream your conversational data wherever you want +- Integrate with different NLP frameworks +- Mediate open requests with Agents via our messaging UI +- Analyze your conversations + +Since Airy's infrastructure is built around Apache Kafka, it can process a large +amount of conversations and messages simultaneously and stream the relevant +conversational data to wherever you need it. + +## Airy Core Components + +The platform contains the following core components: + +- An ingestion platform that heavily relies on Apache Kafka to process incoming + webhook data from different sources. We make sense of the data and reshape it + into source independent contacts, conversations, and messages (see our + glossary for formal definitions). + +- An HTTP API that allows you to manage the data sets the platform handles. + +- A webhook integration server that allows you to programmatically participate + in conversations by sending messages. The webhook integration exposes events + you can "listen" to and react programmatically. + +- A WebSocket server that allows you to receive near real-time updates about the + data flowing through the system. diff --git a/docs/docs/getting-started/quickstart.md b/docs/docs/getting-started/quickstart.md new file mode 100644 index 0000000000..08c9092fb3 --- /dev/null +++ b/docs/docs/getting-started/quickstart.md @@ -0,0 +1,88 @@ +--- +title: Quickstart +sidebar_label: Quickstart +--- + +Learn the basics with Airy Core's Quickstart: In this guide we are gonna set up +our first source, Airy's Live Chat Plugin. We then use the plugin to send +messages, and check them out in the UI, your terminal and directly in Apache Kafka. + +:::tip What you will learn + +- How to set up your first Source +- How to send Messages +- How to use the API to list conversations +- How to consume directly from Kafka + +::: + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +## How to setup your first source + +The [Airy Live Chat Plugin](/sources/chat-plugin.md) source is well suited for a +first integration because it does not require any configuration. + +Once you [signed up](/api/endpoints/users.md#signup), you must [log +in](/api/authentication.md#login) so you can obtain a valid JWT token for the +upcoming API calls: + +```bash +token=$(echo $(curl -H 'Content-Type: application/json' -d \ +"{ \ +\"email\":\"grace@example.com\", \ +\"password\":\"the_answer_is_42\" \ +}" api.airy/users.login) | jq -r '.token') +curl -H "Content-Type: application/json" -H "Authorization: $token" -d \ +"{ + \"name\": \"chat plugin source\" +}" api.airy/chatplugin.connect +``` + +channels_connect + +The ID from the response is the `channel_id`. It is required for +the next steps, so note it down. + +## Send messages via the Chat Plugin + +Pass the `channel_id` as a query parameter when opening the demo page in your +browser. This authenticates the chat plugin and enables you to send messages +immediately: + +``` +http://chatplugin.airy/example?channel_id= +``` + +You can now type a message in the text box and send it 🎉 + +chatplugin working + +## Use the HTTP API to list conversations + +To see how messages are flowing through the system, [list +conversations](/api/endpoints/conversations.md#list) for the channel you have just +created. it should return the message you have just sent. + +conversations.list + +```bash +curl -H "Content-Type: application/json" -H "Authorization: $token" -d "{}" \ +api.airy/conversations.list | jq . +``` + +## Consume directly from Apache Kafka + +You can also consume the messages directly from the Kafka +`application.communication.messages` topic: + +``` +cd infrastructure && vagrant ssh +kubectl exec -it kafka-0 -- /bin/bash +kafka-console-consumer \ +--bootstrap-server airy-cp-kafka:9092 \ +--topic application.communication.messages \ +--from-beginning +``` + +Kafka Topic diff --git a/docs/docs/getting-started/troubleshooting.md b/docs/docs/getting-started/troubleshooting.md new file mode 100644 index 0000000000..2fac16b0fe --- /dev/null +++ b/docs/docs/getting-started/troubleshooting.md @@ -0,0 +1,28 @@ +--- +title: Troubleshooting +sidebar_label: Troubleshooting +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +Airy Core is free and open-source for users who wish to self-host the platform. +That doesn't mean that you are alone with your problems. There are 2 ways to get +help quickly: Community Support & Enterprise Support by the engineers who built +the platform. + +Community Support + +## Community Support + +Airy’s [Community Slack](https://airy.co/community) is a great place to reach +out for help. Our community and Core developers are often logged in and ready to +answer questions. + +Enterprise Support + +## Enterprise Support + +Looking for help & tips running a full scale messaging platform? Airy’s Support +engineers can help. + +Fill out [the form](https://airy.co/get-a-demo) to get quick support. diff --git a/docs/docs/guides/contributing.md b/docs/docs/guides/contributing.md index e817bdfd75..faca35cd21 100644 --- a/docs/docs/guides/contributing.md +++ b/docs/docs/guides/contributing.md @@ -11,7 +11,7 @@ started. ## Work with the code -The Airy Core Platform uses [Bazel](https://bazel.build/) to build and test +The Airy Core uses [Bazel](https://bazel.build/) to build and test itself. We suggest you to install [bazelisk](https://github.com/bazelbuild/bazelisk), a small utility that will install the right version of Bazel for you. diff --git a/docs/docs/index.md b/docs/docs/index.md deleted file mode 100644 index c01ac13125..0000000000 --- a/docs/docs/index.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -id: index -title: Home -slug: / ---- - -import useBaseUrl from '@docusaurus/useBaseUrl'; - -The Airy Core Platform is a fully-featured, production ready messaging platform -that allows you to process messaging data from a variety of sources (like -Facebook messenger or Google business messages). The core platform contains the -following components: - -- An ingestion platform that heavily relies on [Apache - Kafka](https://kafka.apache.org) to process incoming webhook data from - different sources. We make sense of the data and reshape it into source - independent contacts, conversations, and messages (see our - [glossary](glossary.md) for formal definitions). - -- An [HTTP API](api/http.md) that allows you to manage the data sets the - platform handles. - -- A [webhook](api/webhook) integration server that allows to programmatically - participate in conversations by sending messages. The webhook integration - exposes events you can "listen" to and react programmatically. - -- A [WebSocket](api/websocket) server that allows you to receive near real-time - updates about the data flowing through the system. - -## Bootstrap the Airy Core Platform - -Run the Airy Core Platform locally by entering the following commands: - -```bash -git clone -b main https://github.com/airyhq/airy -cd airy -./scripts/bootstrap.sh -``` - -The bootstrap installation requires -[Vagrant](https://www.vagrantup.com/downloads) and -[VirtualBox](https://www.virtualbox.org/wiki/Downloads). If they are not found, -the script will attempt to install them for you. - -If Vagrant or VirtualBox cannot be installed with the `bootstrap.sh` script, you -need to install them manually. - -The script will also ask for your administrative credentials as we are using the -[Vagrant Host Manager -Plugin](https://github.com/devopsgroup-io/vagrant-hostmanager) to add entries to -your hosts file. You can skip this step and add the following lines to your -hosts file yourself. - -``` -192.168.50.5 demo.airy -192.168.50.5 api.airy -192.168.50.5 chatplugin.airy -``` - -After the bootstrap process finishes, it will download the Kubernetes configiration file to the local host machine under `~/.airy/kube.conf`. -That file is required for the Airy Command Line tool (Airy CLI), in order to access the Kubernetes cluster where the Airy Core Platform is running. -You can also use that configuration file with the `kubectl` utility, for example: - -```sh -kubectl --kubeconfig ~/.airy/kube.conf get pods -``` - -Check out our [guide for running in test environment](guides/airy-core-in-test-env.md) for detailed information. - -## Connect a Chat Plugin source - -The chat plugin source is well suited for a first integration because it does -not require any configuration. - -Once you [signed up](api/http#signup), you must [log in](api/http#login) so you -can obtain a valid JWT token for the upcoming API calls: - -```bash -token=$(echo $(curl -H 'Content-Type: application/json' -d \ -"{ \ -\"email\":\"grace@example.com\", \ -\"password\":\"the_answer_is_42\" \ -}" api.airy/users.login) | jq -r '.token') -curl -H "Content-Type: application/json" -H "Authorization: $token" -d \ -"{ - \"name\": \"chat plugin source\" -}" api.airy/chatplugin.connect -``` - -channels_connect - -The ID from the response is the `channel_id`. It is required for -the next steps, so note it down. - -## Send messages via the Chat Plugin - -Pass the `channel_id` as a query parameter when opening the demo page in your -browser. This authenticates the chat plugin and enables you to send messages -immediately: - -``` -http://chatplugin.airy/example?channel_id= -``` - -You can now type a message in the text box and send it 🎉 - -chatplugin working - -To see how messages are flowing through the system, [list -conversations](api/http.md#list-conversations) for the channel you have just created. -it should return the message you have just sent. - -conversations.list - -```bash -curl -H "Content-Type: application/json" -H "Authorization: $token" -d "{}" \ -api.airy/conversations.list | jq . -``` - -You can also consume the messages directly from the Kafka -`application.communication.messages` topic: - -```bash -cd infrastructure && vagrant ssh -kubectl exec -it kafka-0 -- /bin/bash -kafka-console-consumer \ ---bootstrap-server airy-cp-kafka:9092 \ ---topic application.communication.messages \ ---from-beginning -``` - -Kafka Topic diff --git a/docs/docs/guides/airy-core-and-rasa.md b/docs/docs/integrations/rasa.md similarity index 63% rename from docs/docs/guides/airy-core-and-rasa.md rename to docs/docs/integrations/rasa.md index d418115411..dda5a3f0a4 100644 --- a/docs/docs/guides/airy-core-and-rasa.md +++ b/docs/docs/integrations/rasa.md @@ -1,19 +1,20 @@ --- -title: How to connect the Airy Core Platform and Rasa -sidebar_label: Connecting Rasa +title: Rasa integration +sidebar_label: Rasa --- import useBaseUrl from '@docusaurus/useBaseUrl'; :::tip What you will learn -- How to forward Airy Core Platform messages to Rasa +- How to forward Airy Core messages to Rasa - How to configure Rasa to receive and reply to messages using Airy ::: -> Rasa is an open source machine learning framework for automated text and voice-based conversations. -> Understand messages, hold conversations, and connect to messaging channels and APIs. +> Rasa is an open source machine learning framework for automated text and +> voice-based conversations. Understand messages, hold conversations, and +> connect to messaging channels and APIs. > > \- From the [Rasa documentation](https://rasa.com/docs/rasa/) @@ -23,26 +24,26 @@ This is perfectly fine for simple use cases, but as your platform grows and you want to scale your bot interactions across many channels you will need a dedicated solution for storing and routing messages. -This is where the Airy Core Platform can provide great scale benefits: You can -connect a wide array of messaging channels and service them in a single inbox. -For Rasa, you can think of it as a forward messaging router that will persist -your data and make it available for export to anywhere within your organization. +This is where Airy Core can provide great scale benefits: You can connect a wide +array of messaging channels and service them in a single inbox. For Rasa, you +can think of it as a forward messaging router that will persist your data and +make it available for export to anywhere within your organization. This guide covers how to configure your Rasa installation so that it can use the -Airy Core Platform to send and receive messages. +Airy Core to send and receive messages. :::note Prerequisites -- A running Airy Core Platform installation [Get Started](index.md#bootstrapping-the-airy-core-platform) +- A running Airy Core installation [Get Started](getting-started/installation.md) - A local Rasa setup: For convenience, we recommend [the Docker setup](https://rasa.com/docs/rasa/docker/building-in-docker/) or [a demo repository](https://github.com/airyhq/rasa-demo) we created for this guide ::: ## Configuring Airy -The Airy Core Platform can forward messages from your sources (Messenger, +The Airy Core can forward messages from your sources (Messenger, WhatsApp etc.) to downstream messaging frameworks like Rasa, which can in turn -reply using the Airy Core Platform API. +reply using the Airy Core API. To do this we follow the [webhook documentation](api/webhook.md) to forward in- and outbound messages to Rasa. When doing so set the `url` parameter so that it @@ -63,25 +64,25 @@ should look like so: } ``` -Once you have done this, the Airy Core Platform will start sending messages to -the url you specified. +Once you have done this, the Airy Core will start sending messages to the url +you specified. -successful webhook connection log +successful webhook connection log ## Configuring Rasa We will be implementing a [custom connector](https://rasa.com/docs/rasa/connectors/custom-connectors/) as we want -to make use of the Airy Core Platform API. +to make use of the Airy Core API. The first step is to create a new directory `channels/` in our Rasa project and copy this [connector file](https://github.com/airyhq/rasa-demo/blob/master/channels/airy.py) into it. The connector requires the following configuration values: -- `auth_token` the Airy Core Platform JWT token you used +- `auth_token` the Airy Core JWT token you used to connect the webhook. -- `api_host` The url where you host your Airy Core Platform API (`http://api.airy` for a local installation). +- `api_host` The url where you host your Airy Core API (`http://api.airy` for a local installation). Add them to your existing Rasa `credentials.yml`: @@ -95,7 +96,7 @@ Now you should have a working integration 🎉. To test the connection write a message to one of your channels: The Airy Core Platform will forward it to your Rasa installation, which will respond using the -Airy Core Platform API. This is what you should see in the logs of the demo -repository: +Airy Core API. This is what you should see in the logs of the demo repository: -send message successful connection log +send message successful connection log diff --git a/docs/docs/sources/chat-plugin.md b/docs/docs/sources/chat-plugin.md index b58220dd99..ccc0478502 100644 --- a/docs/docs/sources/chat-plugin.md +++ b/docs/docs/sources/chat-plugin.md @@ -1,10 +1,11 @@ --- -title: Chat Plugin -sidebar_label: Chat Plugin +title: Airy Live Chat Plugin +sidebar_label: Airy Live Chat Plugin --- -The Airy Core Chat Plugin is a fully-featured [source](/glossary.md#source) that -enables conversations with anonymous website visitors through a web chat plugin. +The Airy Live Chat Plugin is a fully-featured +[source](/getting-started/glossary#source) that enables conversations with +anonymous website visitors through a web chat plugin. :::tip What you will learn @@ -16,7 +17,7 @@ enables conversations with anonymous website visitors through a web chat plugin. ## Connect -Connects a Chat Plugin source to the Airy Core Platform. +Connects a Chat Plugin source to Airy Core. ``` POST /chatplugin.connect @@ -89,7 +90,7 @@ browser. ## HTTP API The HTTP api adheres to standards laid out in the [core -API](api/http.md#introduction). +API](/api/introduction#authentication). ### Authenticating web users @@ -126,14 +127,8 @@ previous conversation using the [resume endpoint](#get-a-resume-token). "messages": [ { "id": "{UUID}", - "content": [ - { - "text": "{String}", - "type": "text" - // Determines the schema of the content - } - ], - // typed source message model + "content": '{"text":"Hello World"}', + // source message payload "state": "{String}", // delivery state of message, one of PENDING, FAILED, DELIVERED "sender_type": "{string/enum}", @@ -179,7 +174,6 @@ header. { "message": { "text": "{String}" - "type": "text" } } ``` @@ -189,11 +183,8 @@ header. ```json5 { id: "{UUID}", - content: { - text: "{String}", - type: "text" - // Determines the schema of the content - }, + "content": '{"text":"Hello World"}', + // source message payload state: "{String}", // delivery state of message, one of PENDING, FAILED, DELIVERED sender_type: "{string/enum}", @@ -221,8 +212,8 @@ The WebSocket connection endpoint is at `/ws.chatplugin`. { message: { id: "{UUID}", - content: "{String}", - // source content string + "content": '{"text":"Hello World"}', + // source message payload state: "{String}", // delivery state of message, one of PENDING, FAILED, DELIVERED sender_type: "{string/enum}", diff --git a/docs/docs/sources/facebook.md b/docs/docs/sources/facebook.md index e26e3bda09..328beb6009 100644 --- a/docs/docs/sources/facebook.md +++ b/docs/docs/sources/facebook.md @@ -1,6 +1,6 @@ --- -title: Facebook -sidebar_label: Facebook +title: Facebook Messenger +sidebar_label: Facebook Messenger --- import useBaseUrl from '@docusaurus/useBaseUrl'; @@ -11,7 +11,7 @@ Core Platform instance. :::tip What you will learn - The required steps to configure the Facebook source -- How to connect a Facebook page to the Airy Core Platform +- How to connect a Facebook page to Airy Core ::: @@ -47,7 +47,9 @@ Now you can use the app id and the app secret for the following environment vari :::note -Refer to the [test](/guides/airy-core-in-test-env#connect-sources) guide or the [production](/guides/airy-core-in-production#connect-sources) one to set these variables in your Airy Core Platform instance. +Refer to the [test](getting-started/deployment/vagrant.md#connect-sources) guide +or the [production](getting-started/deployment/production.md#connect-sources) +one to set these variables in your Airy Core instance. ::: @@ -60,7 +62,10 @@ a value of your choice. :::note -Refer to the [test](/guides/airy-core-in-test-env#connect-sources) guide or the [production](/guides/airy-core-in-production#connect-sources) one to set these variables in your Airy Core Platform instance. +Refer to the [test](/getting-started/deployment/vagrant.md#connect-sources) +guide or the +[production](/getting-started/deployment/production.md#connect-sources) one to +set these variables in your Airy Core instance. ::: @@ -71,24 +76,24 @@ click on "Edit subscription". You will see something like this: Facebook edit subscription Once the verification process has been completed, Facebook will immediately -start sending events to your Airy Core Platform instance. +start sending events to your Airy Core instance. ### Obtain a page token -The next step is to obtain a page token, so the Airy Core Platform can send messages -on behalf of your page. The fastest way to get one is to use the graph explorer that -Facebook provides [Graph +The next step is to obtain a page token, so that Airy Core can send messages on +behalf of your page. The fastest way to get one is to use the graph explorer +that Facebook provides [Graph Explorer](https://developers.facebook.com/tools/explorer/). On the `User or Page` option, select `Get Page Token` and click on `Generate Access Token`: Facebook token page -You're now ready to connect a Facebook page to the Airy Core Platform 🎉. +You're now ready to connect a Facebook page to your Airy Core instace 🎉. ## Connect -Connects a Facebook page to the Airy Core Platform. +Connects a Facebook page to Airy Core. ``` POST /facebook.connect @@ -124,7 +129,7 @@ POST /facebook.connect ## Disconnect -Disconnects a Facebook page from the Airy Core Platform +Disconnects a Facebook page from Airy Core ``` POST /facebook.disconnect @@ -170,43 +175,3 @@ the nature of the request, the response time may vary. ] } ``` - -## Send a template message - -With Facebook messenger you can send [templates](https://developers.facebook.com/docs/messenger-platform/send-messages/templates) to your contacts, -which is useful for automations, FAQs, receipts and many more use cases. To send Facebook templates using the [send message API](/api/http.md#send-a-message) you have to -first build an attachment for Facebook using their template model. Quoting from the docs: - -> The body of the request follows a standard format for all template types, with the `message.attachment.payload` property containing the type and content details that are specific to each template type: -> -> ```json5 -> { -> "recipient": { -> "id": "" -> }, -> "message": { -> "attachment": { -> "type": "template", -> "payload": { -> "template_type": "" -> // ... -> } -> } -> } -> } -> ``` - -Next take the `message.attachment.payload` field and add it to the `message` field on the API request like so: - -```json5 -{ - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "message": { - "payload": { - "template_type": "" - // ... - }, - "type": "source.template" - } -} -``` diff --git a/docs/docs/sources/google.md b/docs/docs/sources/google.md index fc23eeb091..66e9de904f 100644 --- a/docs/docs/sources/google.md +++ b/docs/docs/sources/google.md @@ -1,10 +1,10 @@ --- -title: Google -sidebar_label: Google +title: Google’s Business Messages +sidebar_label: Google’s Business Messages --- The Google source provides a channel of communication between your Google -Business Location and your running instance of the Airy Core Platform. +Business Location and your running instance of Airy Core. :::tip What you will learn @@ -27,11 +27,11 @@ against your partner key. You must also set the environment variable `GOOGLE_PARTNER_KEY` to your partner key Once the verification process has been completed, Google will immediately start -sending events to your Airy Core Platform instance. +sending events to your Airy Core instance. ## Connect -Connects a Google Business Account to the Airy Core Platform. +Connects a Google Business Account to Airy Core. ``` POST /google.connect diff --git a/docs/docs/sources/introduction.md b/docs/docs/sources/introduction.md new file mode 100644 index 0000000000..f6fcf443df --- /dev/null +++ b/docs/docs/sources/introduction.md @@ -0,0 +1,30 @@ +--- +title: Introduction +sidebar_label: Introduction +--- + +One of the crucial features Airy Core provides is the ability to process +conversational data from a variety of sources (like Facebook Messenger, Google +Business Messages, and so on). + +The ingestion platform processes incoming webhook data from different sources. +It then makes sense of the data and reshapes it into source independent +contacts, conversations, and messages (see our [glossary](/getting-started/glossary.md) for definitions). + +Of course, due the very nature of the problem, the code is very specific to the +thirty-party source it deals with. This frees you from dealing with these +integrations yourself. + +While sources are all different, their architecture follows a few key +principles: + +- The webhook integration ingests payload data as raw as you get it in a source + specific topic. + +- We only extracts metadata from the source data as we translate events into + conversations and messages, the content is not parsed at ingestion time, we let + it travel untouched through the system. + +These principles allow you to reprocess data from a conversation platform at any +given point time. If the data pipeline has a bug, say the messages are counted +incorrectly, you can reprocess the data and fix a bug for past data as well. diff --git a/docs/docs/sources/sms-twilio.md b/docs/docs/sources/sms-twilio.md index a930c9c39d..dcc1776fac 100644 --- a/docs/docs/sources/sms-twilio.md +++ b/docs/docs/sources/sms-twilio.md @@ -1,9 +1,9 @@ --- title: SMS via Twilio -sidebar_label: SMS - Twilio +sidebar_label: SMS --- -The Twilio sms source provides a channel for sending and receiving SMS using the +The Twilio SMS source provides a channel for sending and receiving SMS using the [Twilio API](https://www.twilio.com/). :::note @@ -22,7 +22,7 @@ import TwilioSource from './twilio-source.mdx' After you created a Twilio phone number you must [point its webhook integration](https://www.twilio.com/docs/sms/tutorials/how-to-receive-and-reply-java#configure-your-webhook-url) -to your running Airy Core Platform instance. +to your running Airy Core instance. Next call the Platform API: diff --git a/docs/docs/sources/whatsapp-twilio.md b/docs/docs/sources/whatsapp-twilio.md index 5fdc57e2e8..7ae5b66603 100644 --- a/docs/docs/sources/whatsapp-twilio.md +++ b/docs/docs/sources/whatsapp-twilio.md @@ -1,6 +1,6 @@ --- title: WhatsApp via Twilio -sidebar_label: WhatsApp - Twilio +sidebar_label: WhatsApp Business API --- The Twilio WhatsApp source provides a channel for sending and receiving WhatsApp @@ -23,9 +23,9 @@ import TwilioSource from './twilio-source.mdx' After you created a Twilio phone number, you must [point its webhook integration](https://www.twilio.com/docs/sms/tutorials/how-to-receive-and-reply-java#configure-your-webhook-url) -to your Airy Core Platform running instance. +to your Airy Core running instance. -Next call the Airy Core Platform API for connecting channels: +Next call the Airy Core API for connecting channels: ``` POST /twilio.whatsapp.connect diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 7eb2bec065..e9740534e6 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -12,6 +12,9 @@ module.exports = { apiKey: '768788b65303eb29ca1f195847ed1e78', indexName: 'airy', }, + googleAnalytics: { + trackingID: 'UA-74312428-5', + }, hideableSidebar: true, prism: { theme: require('prism-react-renderer/themes/github'), @@ -31,7 +34,6 @@ module.exports = { }, }, plugins: ['plugin-image-zoom'], - scripts: ['https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js'], presets: [ [ '@docusaurus/preset-classic', @@ -39,7 +41,6 @@ module.exports = { docs: { routeBasePath: '/', sidebarPath: require.resolve('./sidebars.js'), - editUrl: 'https://github.com/airyhq/airy/edit/main/docs/', }, theme: { customCss: require.resolve('./src/css/custom.css'), diff --git a/docs/package.json b/docs/package.json index 733a2dc0a4..f9d9797130 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,11 +11,11 @@ "serve": "docusaurus serve" }, "dependencies": { - "@docusaurus/core": "2.0.0-alpha.66", - "@docusaurus/preset-classic": "2.0.0-alpha.66", - "@mdx-js/react": "^1.5.8", - "clsx": "^1.1.1", + "@docusaurus/core": "2.0.0-alpha.70", + "@docusaurus/preset-classic": "2.0.0-alpha.70", + "@mdx-js/react": "1.6.22", "plugin-image-zoom": "ataft/plugin-image-zoom", + "clsx": "^1.1.1", "react": "^16.8.4", "react-dom": "^16.8.4" }, diff --git a/docs/sidebars.js b/docs/sidebars.js index 4bdeca8203..a1ed7b50fd 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -1,11 +1,38 @@ module.exports = { docs: [ - 'index', { - Overview: ['overview/architecture', 'overview/design-principles', 'overview/release-process', 'overview/kafka'], + '🚀 Getting Started': [ + 'getting-started/introduction', + 'getting-started/installation', + { + Deployment: [ + 'getting-started/deployment/introduction', + 'getting-started/deployment/vagrant', + 'getting-started/deployment/production', + ], + }, + 'getting-started/quickstart', + { + CLI: [ + 'getting-started/cli', + 'cli/airy', + 'cli/airy_version', + 'cli/airy_init', + 'cli/airy_config', + 'cli/airy_config_apply', + 'cli/airy_api', + 'cli/airy_api_signup', + 'cli/airy_api_login', + 'cli/airy_status', + ], + }, + 'getting-started/troubleshooting', + 'getting-started/glossary', + ], }, { - Sources: [ + '💬 Sources': [ + 'sources/introduction', 'sources/chat-plugin', 'sources/facebook', 'sources/google', @@ -14,17 +41,44 @@ module.exports = { ], }, { - Guides: [ - 'guides/contributing', + '🔌 API': [ + 'api/introduction', + 'api/authentication', { - Deployment: ['guides/airy-core-in-test-env', 'guides/airy-core-in-production'], + 'HTTP Endpoints': [ + 'api/endpoints/introduction', + 'api/endpoints/channels', + 'api/endpoints/conversations', + 'api/endpoints/messages', + 'api/endpoints/metadata', + 'api/endpoints/tags', + 'api/endpoints/users', + ], }, - 'guides/airy-core-and-rasa', + 'api/websocket', + 'api/webhook', + ], + }, + { + '✨ Apps': ['apps/ui'], + }, + { + '🛠️ Integrations': [ + { + 'Conversational AI /NLP': ['integrations/rasa'], + }, + ], + }, + { + '⚙️ Concepts': [ + 'concepts/architecture', + 'concepts/design-principles', + 'concepts/release-process', + 'concepts/kafka', ], }, { - 'API Reference': ['api/http', 'api/websocket', 'api/webhook'], + '📚 Guides': ['guides/contributing'], }, - 'glossary', ], }; diff --git a/docs/static/img/favicon.ico b/docs/static/img/favicon.ico index 6c9f5a0553..1e4eaa4369 100644 Binary files a/docs/static/img/favicon.ico and b/docs/static/img/favicon.ico differ diff --git a/docs/static/img/home/chatplugin.gif b/docs/static/img/getting-started/quickstart/chatplugin.gif similarity index 100% rename from docs/static/img/home/chatplugin.gif rename to docs/static/img/getting-started/quickstart/chatplugin.gif diff --git a/docs/static/img/home/connect_chatplugin_channel.gif b/docs/static/img/getting-started/quickstart/connect_chatplugin_channel.gif similarity index 100% rename from docs/static/img/home/connect_chatplugin_channel.gif rename to docs/static/img/getting-started/quickstart/connect_chatplugin_channel.gif diff --git a/docs/static/img/home/conversation_list.gif b/docs/static/img/getting-started/quickstart/conversation_list.gif similarity index 100% rename from docs/static/img/home/conversation_list.gif rename to docs/static/img/getting-started/quickstart/conversation_list.gif diff --git a/docs/static/img/home/messages_topic.gif b/docs/static/img/getting-started/quickstart/messages_topic.gif similarity index 100% rename from docs/static/img/home/messages_topic.gif rename to docs/static/img/getting-started/quickstart/messages_topic.gif diff --git a/docs/static/img/getting-started/troubleshooting/community.png b/docs/static/img/getting-started/troubleshooting/community.png new file mode 100644 index 0000000000..8a2892d689 Binary files /dev/null and b/docs/static/img/getting-started/troubleshooting/community.png differ diff --git a/docs/static/img/getting-started/troubleshooting/enterprise.png b/docs/static/img/getting-started/troubleshooting/enterprise.png new file mode 100644 index 0000000000..cda46c8acb Binary files /dev/null and b/docs/static/img/getting-started/troubleshooting/enterprise.png differ diff --git a/docs/static/img/getting-started/troubleshooting/troubleshooting.png b/docs/static/img/getting-started/troubleshooting/troubleshooting.png new file mode 100644 index 0000000000..7174cea8cd Binary files /dev/null and b/docs/static/img/getting-started/troubleshooting/troubleshooting.png differ diff --git a/docs/static/img/guides/airy-core-and-rasa/success.jpg b/docs/static/img/integrations/rasa/success.jpg similarity index 100% rename from docs/static/img/guides/airy-core-and-rasa/success.jpg rename to docs/static/img/integrations/rasa/success.jpg diff --git a/docs/static/img/guides/airy-core-and-rasa/webhook_success.jpg b/docs/static/img/integrations/rasa/webhook_success.jpg similarity index 100% rename from docs/static/img/guides/airy-core-and-rasa/webhook_success.jpg rename to docs/static/img/integrations/rasa/webhook_success.jpg diff --git a/docs/yarn.lock b/docs/yarn.lock index bfcbe6b0e1..bc5f6e5ccf 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2,6 +2,25 @@ # yarn lockfile v1 +"@algolia/autocomplete-core@^1.0.0-alpha.35": + version "1.0.0-alpha.39" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.0.0-alpha.39.tgz#46d4c612243df75da9f2c57edd6f6d7b08633f13" + integrity sha512-Iaer2aItGbNlJr5/lI65zR0yfFCEVedBwm8A3MTLB6Gj/A5sXscL+X4mP04hQemUMqZ9c2cLryVN1UI0h09t3w== + dependencies: + "@algolia/autocomplete-shared" "1.0.0-alpha.39" + +"@algolia/autocomplete-preset-algolia@^1.0.0-alpha.35": + version "1.0.0-alpha.39" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.39.tgz#efbd238cf8fba4ed178344cca70b84addb0f0209" + integrity sha512-0E9dvwk1ibGpQk7Kq1M8bqcxZ5ToXowAxcICLpy6SwQoWAV4P5lygkeU3gkkEwqZCzCdRbB+KbahUP62ie26Jw== + dependencies: + "@algolia/autocomplete-shared" "1.0.0-alpha.39" + +"@algolia/autocomplete-shared@1.0.0-alpha.39": + version "1.0.0-alpha.39" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.0.0-alpha.39.tgz#5f661a09150cb5a049d4697eb57fffb4adbceb63" + integrity sha512-t0tOPVBjWicKWtysQZbblXmFDRToTgXXtjSeiDCeAfD9lCN7jx52F8kkT1ZnzhmAHcSpcaLagjTLttcyJwJjwQ== + "@algolia/cache-browser-local-storage@4.6.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.6.0.tgz#79d825280f96ac5fc61df138a38aab3b658f3b65" @@ -120,24 +139,36 @@ dependencies: "@babel/highlight" "^7.10.4" +"@babel/code-frame@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + "@babel/compat-data@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.1.tgz#d7386a689aa0ddf06255005b4b991988021101a0" integrity sha512-725AQupWJZ8ba0jbKceeFblZTY90McUBWMwHhkFQ9q1zKPJ95GUktljFcgcsIVwRnTnRKlcYzfiNImg5G9m6ZQ== -"@babel/core@7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" - integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== +"@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41" + integrity sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw== + +"@babel/core@7.12.9": + version "7.12.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" + integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.6" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.5" - "@babel/types" "^7.11.5" + "@babel/generator" "^7.12.5" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.7" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.9" + "@babel/types" "^7.12.7" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -147,6 +178,27 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.12.3": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" + integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.10" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.10" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.10" + "@babel/types" "^7.12.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/core@^7.7.5", "@babel/core@^7.9.0": version "7.12.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" @@ -169,7 +221,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.11.6", "@babel/generator@^7.12.1": +"@babel/generator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.1.tgz#0d70be32bdaa03d7c51c8597dda76e0df1f15468" integrity sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg== @@ -178,6 +230,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.12.10", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" + integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA== + dependencies: + "@babel/types" "^7.12.11" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" @@ -185,6 +246,13 @@ dependencies: "@babel/types" "^7.10.4" +"@babel/helper-annotate-as-pure@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d" + integrity sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ== + dependencies: + "@babel/types" "^7.12.10" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" @@ -220,6 +288,16 @@ browserslist "^4.12.0" semver "^5.5.0" +"@babel/helper-compilation-targets@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz#cb470c76198db6a24e9dbc8987275631e5d29831" + integrity sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw== + dependencies: + "@babel/compat-data" "^7.12.5" + "@babel/helper-validator-option" "^7.12.1" + browserslist "^4.14.5" + semver "^5.5.0" + "@babel/helper-create-class-features-plugin@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz#3c45998f431edd4a9214c5f1d3ad1448a6137f6e" @@ -265,6 +343,15 @@ "@babel/template" "^7.10.4" "@babel/types" "^7.10.4" +"@babel/helper-function-name@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz#1fd7738aee5dcf53c3ecff24f1da9c511ec47b42" + integrity sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA== + dependencies: + "@babel/helper-get-function-arity" "^7.12.10" + "@babel/template" "^7.12.7" + "@babel/types" "^7.12.11" + "@babel/helper-get-function-arity@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" @@ -272,6 +359,13 @@ dependencies: "@babel/types" "^7.10.4" +"@babel/helper-get-function-arity@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf" + integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag== + dependencies: + "@babel/types" "^7.12.10" + "@babel/helper-hoist-variables@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" @@ -293,7 +387,14 @@ dependencies: "@babel/types" "^7.12.1" -"@babel/helper-module-transforms@^7.11.0", "@babel/helper-module-transforms@^7.12.1": +"@babel/helper-module-imports@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" + integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== + dependencies: + "@babel/types" "^7.12.5" + +"@babel/helper-module-transforms@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== @@ -367,16 +468,33 @@ dependencies: "@babel/types" "^7.11.0" +"@babel/helper-split-export-declaration@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz#1b4cc424458643c47d37022223da33d76ea4603a" + integrity sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g== + dependencies: + "@babel/types" "^7.12.11" + "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== +"@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== + "@babel/helper-validator-option@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9" integrity sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A== +"@babel/helper-validator-option@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f" + integrity sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw== + "@babel/helper-wrap-function@^7.10.4": version "7.12.3" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz#3332339fc4d1fbbf1c27d7958c27d34708e990d9" @@ -387,7 +505,7 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helpers@^7.10.4", "@babel/helpers@^7.12.1": +"@babel/helpers@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.1.tgz#8a8261c1d438ec18cb890434df4ec768734c1e79" integrity sha512-9JoDSBGoWtmbay98efmT2+mySkwjzeFeAL9BuWNoVQpkPFQF8SIIFUfY5os9u8wVzglzoiPRSW7cuJmBDUt43g== @@ -396,6 +514,15 @@ "@babel/traverse" "^7.12.1" "@babel/types" "^7.12.1" +"@babel/helpers@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" + integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + "@babel/highlight@^7.10.4", "@babel/highlight@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" @@ -405,11 +532,16 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.5", "@babel/parser@^7.12.1", "@babel/parser@^7.12.3", "@babel/parser@^7.9.4": +"@babel/parser@^7.10.4", "@babel/parser@^7.12.1", "@babel/parser@^7.12.3": version "7.12.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw== +"@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.5", "@babel/parser@^7.12.7": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" + integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== + "@babel/plugin-proposal-async-generator-functions@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e" @@ -459,7 +591,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": +"@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz#3ed4fff31c015e7f3f1467f190dbe545cd7b046c" integrity sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg== @@ -475,16 +607,15 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" - integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== +"@babel/plugin-proposal-numeric-separator@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz#8bf253de8139099fea193b297d23a9d406ef056b" + integrity sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.12.1": +"@babel/plugin-proposal-object-rest-spread@7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== @@ -501,7 +632,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.10.3", "@babel/plugin-proposal-optional-chaining@^7.12.1": +"@babel/plugin-proposal-optional-chaining@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz#cce122203fc8a32794296fc377c6dedaf4363797" integrity sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw== @@ -510,6 +641,15 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-syntax-optional-chaining" "^7.8.0" +"@babel/plugin-proposal-optional-chaining@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz#e02f0ea1b5dc59d401ec16fb824679f683d3303c" + integrity sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-proposal-private-methods@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz#86814f6e7a21374c980c10d38b4493e703f4a389" @@ -561,14 +701,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz#39abaae3cbf710c4373d8429484e6ba21340166c" - integrity sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-jsx@^7.12.1": +"@babel/plugin-syntax-jsx@7.12.1", "@babel/plugin-syntax-jsx@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg== @@ -661,6 +794,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-transform-block-scoping@^7.12.11": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz#d93a567a152c22aea3b1929bb118d1d0a175cdca" + integrity sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-classes@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz#65e650fcaddd3d88ddce67c0f834a3d436a32db6" @@ -801,7 +941,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-replace-supers" "^7.12.1" -"@babel/plugin-transform-parameters@^7.10.4", "@babel/plugin-transform-parameters@^7.12.1": +"@babel/plugin-transform-parameters@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz#d2e963b038771650c922eff593799c96d853255d" integrity sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg== @@ -838,6 +978,13 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.12.1" +"@babel/plugin-transform-react-jsx-development@^7.12.7": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.12.tgz#bccca33108fe99d95d7f9e82046bfe762e71f4e7" + integrity sha512-i1AxnKxHeMxUaWVXQOSIco4tvVvvCxMSfeBMnMM06mpaJt3g+MpxYQQrDfojUQldP1xxraPSJYSMEljoWM/dCg== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.12.12" + "@babel/plugin-transform-react-jsx-self@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz#ef43cbca2a14f1bd17807dbe4376ff89d714cf28" @@ -862,6 +1009,17 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.12.1" +"@babel/plugin-transform-react-jsx@^7.12.10", "@babel/plugin-transform-react-jsx@^7.12.12": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz#b0da51ffe5f34b9a900e9f1f5fb814f9e512d25e" + integrity sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.10" + "@babel/helper-module-imports" "^7.12.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.12.1" + "@babel/types" "^7.12.12" + "@babel/plugin-transform-react-pure-annotations@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz#05d46f0ab4d1339ac59adf20a1462c91b37a1a42" @@ -884,14 +1042,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-runtime@^7.9.0": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz#04b792057eb460389ff6a4198e377614ea1e7ba5" - integrity sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg== +"@babel/plugin-transform-runtime@^7.12.1": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562" + integrity sha512-xOrUfzPxw7+WDm9igMgQCbO3cJKymX7dFdsgRr1eu9n3KjjyU4pptIXbXPseQDquw+W+RuJEJMHKHNsPNNm3CA== dependencies: - "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-module-imports" "^7.12.5" "@babel/helper-plugin-utils" "^7.10.4" - resolve "^1.8.1" semver "^5.5.1" "@babel/plugin-transform-shorthand-properties@^7.12.1": @@ -917,6 +1074,13 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-regex" "^7.10.4" +"@babel/plugin-transform-sticky-regex@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz#560224613ab23987453948ed21d0b0b193fa7fad" + integrity sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-template-literals@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz#b43ece6ed9a79c0c71119f576d299ef09d942843" @@ -931,6 +1095,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-transform-typeof-symbol@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz#de01c4c8f96580bd00f183072b0d0ecdcf0dec4b" + integrity sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-typescript@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz#d92cc0af504d510e26a754a7dbc2e5c8cd9c7ab4" @@ -955,7 +1126,79 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.1" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/preset-env@^7.9.0", "@babel/preset-env@^7.9.5": +"@babel/preset-env@^7.12.1": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" + integrity sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw== + dependencies: + "@babel/compat-data" "^7.12.7" + "@babel/helper-compilation-targets" "^7.12.5" + "@babel/helper-module-imports" "^7.12.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-validator-option" "^7.12.11" + "@babel/plugin-proposal-async-generator-functions" "^7.12.1" + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-dynamic-import" "^7.12.1" + "@babel/plugin-proposal-export-namespace-from" "^7.12.1" + "@babel/plugin-proposal-json-strings" "^7.12.1" + "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" + "@babel/plugin-proposal-numeric-separator" "^7.12.7" + "@babel/plugin-proposal-object-rest-spread" "^7.12.1" + "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.12.7" + "@babel/plugin-proposal-private-methods" "^7.12.1" + "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-class-properties" "^7.12.1" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.12.1" + "@babel/plugin-transform-arrow-functions" "^7.12.1" + "@babel/plugin-transform-async-to-generator" "^7.12.1" + "@babel/plugin-transform-block-scoped-functions" "^7.12.1" + "@babel/plugin-transform-block-scoping" "^7.12.11" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-computed-properties" "^7.12.1" + "@babel/plugin-transform-destructuring" "^7.12.1" + "@babel/plugin-transform-dotall-regex" "^7.12.1" + "@babel/plugin-transform-duplicate-keys" "^7.12.1" + "@babel/plugin-transform-exponentiation-operator" "^7.12.1" + "@babel/plugin-transform-for-of" "^7.12.1" + "@babel/plugin-transform-function-name" "^7.12.1" + "@babel/plugin-transform-literals" "^7.12.1" + "@babel/plugin-transform-member-expression-literals" "^7.12.1" + "@babel/plugin-transform-modules-amd" "^7.12.1" + "@babel/plugin-transform-modules-commonjs" "^7.12.1" + "@babel/plugin-transform-modules-systemjs" "^7.12.1" + "@babel/plugin-transform-modules-umd" "^7.12.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" + "@babel/plugin-transform-new-target" "^7.12.1" + "@babel/plugin-transform-object-super" "^7.12.1" + "@babel/plugin-transform-parameters" "^7.12.1" + "@babel/plugin-transform-property-literals" "^7.12.1" + "@babel/plugin-transform-regenerator" "^7.12.1" + "@babel/plugin-transform-reserved-words" "^7.12.1" + "@babel/plugin-transform-shorthand-properties" "^7.12.1" + "@babel/plugin-transform-spread" "^7.12.1" + "@babel/plugin-transform-sticky-regex" "^7.12.7" + "@babel/plugin-transform-template-literals" "^7.12.1" + "@babel/plugin-transform-typeof-symbol" "^7.12.10" + "@babel/plugin-transform-unicode-escapes" "^7.12.1" + "@babel/plugin-transform-unicode-regex" "^7.12.1" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.12.11" + core-js-compat "^3.8.0" + semver "^5.5.0" + +"@babel/preset-env@^7.9.5": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.1.tgz#9c7e5ca82a19efc865384bb4989148d2ee5d7ac2" integrity sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg== @@ -1038,6 +1281,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-react@^7.12.5": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.12.10.tgz#4fed65f296cbb0f5fb09de6be8cddc85cc909be9" + integrity sha512-vtQNjaHRl4DUpp+t+g4wvTHsLQuye+n0H/wsXIZRn69oz/fvNC7gQ4IK73zGJBaxvHoxElDvnYCthMcT7uzFoQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-react-display-name" "^7.12.1" + "@babel/plugin-transform-react-jsx" "^7.12.10" + "@babel/plugin-transform-react-jsx-development" "^7.12.7" + "@babel/plugin-transform-react-pure-annotations" "^7.12.1" + "@babel/preset-react@^7.9.4": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.12.1.tgz#7f022b13f55b6dd82f00f16d1c599ae62985358c" @@ -1051,29 +1305,37 @@ "@babel/plugin-transform-react-jsx-source" "^7.12.1" "@babel/plugin-transform-react-pure-annotations" "^7.12.1" -"@babel/preset-typescript@^7.9.0": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.12.1.tgz#86480b483bb97f75036e8864fe404cc782cc311b" - integrity sha512-hNK/DhmoJPsksdHuI/RVrcEws7GN5eamhi28JkO52MqIxU8Z0QpmiSOQxZHWOHV7I3P4UjHV97ay4TcamMA6Kw== +"@babel/preset-typescript@^7.12.1": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.12.7.tgz#fc7df8199d6aae747896f1e6c61fc872056632a3" + integrity sha512-nOoIqIqBmHBSEgBXWR4Dv/XBehtIFcw9PqZw6rFYuKrzsZmOQm3PR5siLBnKZFEsDb03IegG8nSjU/iXXXYRmw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-validator-option" "^7.12.1" "@babel/plugin-transform-typescript" "^7.12.1" -"@babel/runtime-corejs3@^7.10.4": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.1.tgz#51b9092befbeeed938335a109dbe0df51451e9dc" - integrity sha512-umhPIcMrlBZ2aTWlWjUseW9LjQKxi1dpFlQS8DzsxB//5K+u6GLTC/JliPKHsd5kJVPIU6X/Hy0YvWOYPcMxBw== +"@babel/runtime-corejs3@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz#ffee91da0eb4c6dae080774e94ba606368e414f4" + integrity sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ== dependencies: core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.8.4": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -1083,7 +1345,16 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5", "@babel/traverse@^7.12.1", "@babel/traverse@^7.9.0": +"@babel/template@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" + integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.12.7" + "@babel/types" "^7.12.7" + +"@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e" integrity sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw== @@ -1098,7 +1369,22 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.12.1", "@babel/types@^7.4.4", "@babel/types@^7.9.5": +"@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376" + integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w== + dependencies: + "@babel/code-frame" "^7.12.11" + "@babel/generator" "^7.12.11" + "@babel/helper-function-name" "^7.12.11" + "@babel/helper-split-export-declaration" "^7.12.11" + "@babel/parser" "^7.12.11" + "@babel/types" "^7.12.12" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.4.4", "@babel/types@^7.9.5": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.1.tgz#e109d9ab99a8de735be287ee3d6a9947a190c4ae" integrity sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA== @@ -1107,72 +1393,85 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12", "@babel/types@^7.12.5", "@babel/types@^7.12.7": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" + integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== -"@docsearch/css@^1.0.0-alpha.28": - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-1.0.0-alpha.28.tgz#c8a2cd8c1bb3a6855c51892e9dbdab5d42fe6e23" - integrity sha512-1AhRzVdAkrWwhaxTX6/R7SnFHz8yLz1W8I/AldlTrfbNvZs9INk1FZiEFTJdgHaP68nhgQNWSGlQiDiI3y2RYg== +"@docsearch/css@3.0.0-alpha.32": + version "3.0.0-alpha.32" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.0.0-alpha.32.tgz#3d89c8db4035531d201f74ef2115f72094a24036" + integrity sha512-wafLX/jT1NPAwifPhzMJX394PjKdqf5TA4cz/JgvBYR1/+MiErLk/pyCmocXkawWGR17/6u2qw3wYvXu/Qe/DQ== -"@docsearch/react@^1.0.0-alpha.27": - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-1.0.0-alpha.28.tgz#4f039ed79f8b3332b19a57677b219aebc5010e9d" - integrity sha512-XjJOnCBXn+UZmtuDmgzlVIHnnvh6yHVwG4aFq8AXN6xJEIX3f180FvGaowFWAxgdtHplJxFGux0Xx4piHqBzIw== +"@docsearch/react@^3.0.0-alpha.31": + version "3.0.0-alpha.32" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.0.0-alpha.32.tgz#ae3fa82e9c88683d9415bc439c4af7e2c0cfa5b7" + integrity sha512-2jqzPJu4y0mWiwwm+Kfgf/97Q8XaGxj1+jJfGJpJLkJyD8S2tK4OikyIRWI9gI9k3m48HxFm0+P8uAYYtIyjqA== dependencies: - "@docsearch/css" "^1.0.0-alpha.28" - "@francoischalifour/autocomplete-core" "^1.0.0-alpha.28" - "@francoischalifour/autocomplete-preset-algolia" "^1.0.0-alpha.28" + "@algolia/autocomplete-core" "^1.0.0-alpha.35" + "@algolia/autocomplete-preset-algolia" "^1.0.0-alpha.35" + "@docsearch/css" "3.0.0-alpha.32" algoliasearch "^4.0.0" -"@docusaurus/core@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-alpha.66.tgz#4e1d4296322df48c331f6051a8c0d39d99bd356b" - integrity sha512-9HKqObYoyArpzSTIDguyUXm7z54bpV3dSWSc0PbKGu0Us6zP1TiOuhRDX1diFsKyvjNy7VbCe8XH8LJIdKi5dQ== +"@docusaurus/core@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-alpha.70.tgz#81bff8b093421a0c740fac02903dd23938806077" + integrity sha512-ccDcr5eb5T3C6k7VoqTclBFwjVkIHK1zISdhqzRNVl8AZTql1bYMvGUJP+2WbF6RSdmsGTNWreaUlrJc00dQqw== dependencies: - "@babel/core" "^7.9.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1" - "@babel/plugin-proposal-optional-chaining" "^7.10.3" + "@babel/core" "^7.12.3" + "@babel/generator" "^7.12.5" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.12.1" "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-runtime" "^7.9.0" - "@babel/preset-env" "^7.9.0" - "@babel/preset-react" "^7.9.4" - "@babel/preset-typescript" "^7.9.0" - "@babel/runtime" "^7.9.2" - "@babel/runtime-corejs3" "^7.10.4" - "@docusaurus/types" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" - "@docusaurus/utils-validation" "2.0.0-alpha.66" + "@babel/plugin-transform-runtime" "^7.12.1" + "@babel/preset-env" "^7.12.1" + "@babel/preset-react" "^7.12.5" + "@babel/preset-typescript" "^7.12.1" + "@babel/runtime" "^7.12.5" + "@babel/runtime-corejs3" "^7.12.5" + "@babel/traverse" "^7.12.5" + "@docusaurus/cssnano-preset" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" + "@docusaurus/utils-validation" "2.0.0-alpha.70" "@endiliey/static-site-generator-webpack-plugin" "^4.0.0" - "@hapi/joi" "^17.1.1" "@svgr/webpack" "^5.4.0" - babel-loader "^8.1.0" - babel-plugin-dynamic-import-node "^2.3.0" + babel-loader "^8.2.1" + babel-plugin-dynamic-import-node "2.3.0" boxen "^4.2.0" cache-loader "^4.1.0" chalk "^3.0.0" - chokidar "^3.3.0" + chokidar "^3.4.3" + clean-css "^4.2.3" commander "^4.0.1" - copy-webpack-plugin "^6.0.3" + copy-webpack-plugin "^6.3.0" core-js "^2.6.5" css-loader "^3.4.2" del "^5.1.0" detect-port "^1.3.0" - eta "^1.1.1" + eta "^1.11.0" express "^4.17.1" - file-loader "^6.0.0" - fs-extra "^8.1.0" + file-loader "^6.2.0" + fs-extra "^9.0.1" globby "^10.0.1" - html-minifier-terser "^5.0.5" + html-minifier-terser "^5.1.1" html-tags "^3.1.0" - html-webpack-plugin "^4.0.4" - import-fresh "^3.2.1" + html-webpack-plugin "^4.5.0" + import-fresh "^3.2.2" inquirer "^7.2.0" is-root "^2.1.0" + joi "^17.2.1" leven "^3.1.0" - lodash "^4.5.2" + lodash "^4.17.20" lodash.flatmap "^4.5.0" lodash.has "^4.5.2" lodash.isplainobject "^4.0.6" @@ -1180,17 +1479,17 @@ mini-css-extract-plugin "^0.8.0" nprogress "^0.2.0" null-loader "^3.0.0" - optimize-css-assets-webpack-plugin "^5.0.3" + optimize-css-assets-webpack-plugin "^5.0.4" pnp-webpack-plugin "^1.6.4" postcss-loader "^3.0.0" postcss-preset-env "^6.7.0" react-dev-utils "^10.2.1" - react-helmet "^6.0.0-beta" + react-helmet "^6.1.0" react-loadable "^5.5.0" react-loadable-ssr-addon "^0.3.0" - react-router "^5.1.2" + react-router "^5.2.0" react-router-config "^5.1.1" - react-router-dom "^5.1.2" + react-router-dom "^5.2.0" resolve-pathname "^3.0.0" semver "^6.3.0" serve-handler "^6.1.3" @@ -1198,74 +1497,85 @@ std-env "^2.2.1" terser-webpack-plugin "^4.1.0" update-notifier "^4.1.0" - url-loader "^4.1.0" - wait-file "^1.0.5" + url-loader "^4.1.1" + wait-on "^5.2.0" webpack "^4.44.1" webpack-bundle-analyzer "^3.6.1" webpack-dev-server "^3.11.0" webpack-merge "^4.2.2" webpackbar "^4.0.0" -"@docusaurus/mdx-loader@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-alpha.66.tgz#9d4b3bd038587118b7f6d6915ba6c04fdf3f3c5c" - integrity sha512-IvtrTNeAaynEGgfCbC4CeBgO76Mu76cGogBGv8a84bYeyCOtlxOJoH6JHkJ7T/v5D6lM16qzwx5oqesZ0kZuzA== - dependencies: - "@babel/parser" "^7.9.4" - "@babel/traverse" "^7.9.0" - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" - "@mdx-js/mdx" "^1.5.8" - "@mdx-js/react" "^1.5.8" +"@docusaurus/cssnano-preset@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-alpha.70.tgz#75dc56a71dc365a450729fd109b86fab72a6f560" + integrity sha512-Zwk3SrlE5r/z5j/tjDcs4XoyeoyymCtEovoxLWLV7wb+iR1qb+Jdso4TRShAepbW/ff6SzjCZ8hRy8ahXPD9TA== + dependencies: + cssnano-preset-advanced "^4.0.7" + postcss "^7.0.2" + postcss-combine-duplicated-selectors "^9.1.0" + postcss-sort-media-queries "^1.7.26" + +"@docusaurus/mdx-loader@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-alpha.70.tgz#4cc3c92a5a89ffdc8313da998d4646564940b3e7" + integrity sha512-CDR4O4z7wO5/S8O3TAggCynnuBIGIlUT9q9uhhkDe8h5XDhF8n8d6bwqir0O+fUMN3EnyrMq6z1g4IDRB5G2vw== + dependencies: + "@babel/parser" "^7.12.5" + "@babel/traverse" "^7.12.5" + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" + "@mdx-js/mdx" "^1.6.21" + "@mdx-js/react" "^1.6.21" escape-html "^1.0.3" - file-loader "^6.0.0" - fs-extra "^8.1.0" + file-loader "^6.2.0" + fs-extra "^9.0.1" github-slugger "^1.3.0" gray-matter "^4.0.2" - loader-utils "^1.2.3" + loader-utils "^2.0.0" mdast-util-to-string "^1.1.0" remark-emoji "^2.1.0" stringify-object "^3.3.0" unist-util-visit "^2.0.2" - url-loader "^4.1.0" - -"@docusaurus/plugin-content-blog@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-alpha.66.tgz#278318aff3993c4a2b0487cc8343354086393ba8" - integrity sha512-voK5ZUZcUn5blIDakYNKQ42wPMZLfrZnvEJuwh/8S/W1oNbPN935NBu9vL23fHEmp9L2MGykAdaCmev0Su04yQ== - dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/mdx-loader" "2.0.0-alpha.66" - "@docusaurus/types" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" - "@docusaurus/utils-validation" "2.0.0-alpha.66" - "@hapi/joi" "^17.1.1" + url-loader "^4.1.1" + webpack "^4.44.1" + +"@docusaurus/plugin-content-blog@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-alpha.70.tgz#795a5ddf181dfb314873a5dc33010d1a5bd94d28" + integrity sha512-qWXlSDovkhCZLJR0Wz4e3YcNjlelpuSNkS1rJ8sI1ehs/n32lj7A/nVoRfS/LnOMfIciY48vVPr64VLb6dfEeg== + dependencies: + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/mdx-loader" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" + "@docusaurus/utils-validation" "2.0.0-alpha.70" chalk "^3.0.0" - feed "^4.1.0" - fs-extra "^8.1.0" + feed "^4.2.1" + fs-extra "^9.0.1" globby "^10.0.1" + joi "^17.2.1" loader-utils "^1.2.3" - lodash "^4.5.2" + lodash "^4.17.20" reading-time "^1.2.0" remark-admonitions "^1.2.1" webpack "^4.44.1" -"@docusaurus/plugin-content-docs@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-alpha.66.tgz#ace6f69f090883da3b383138718eec08e0fae3c2" - integrity sha512-jvFKJR7BgjIq6xdmPg+7d2DS1fBeuIfmRTtB/apgfIW8NWO5N0DRYXOj0lgpw/ICwW//o8cLbrN+jkLlzTV/eg== - dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/mdx-loader" "2.0.0-alpha.66" - "@docusaurus/types" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" - "@docusaurus/utils-validation" "2.0.0-alpha.66" - "@hapi/joi" "17.1.1" +"@docusaurus/plugin-content-docs@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-alpha.70.tgz#42dfa40786e819b42974dd167048b190b37bbee5" + integrity sha512-LZre12Q0sxLgi2XgjQbNQMV+jFG7v0+8hRzgBL+iCRiLCa4NlV7+M6mEHJGJJXSKqbfH7CelaUOESqEgPpVQXQ== + dependencies: + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/mdx-loader" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" + "@docusaurus/utils-validation" "2.0.0-alpha.70" chalk "^3.0.0" execa "^3.4.0" - fs-extra "^8.1.0" + fs-extra "^9.0.1" globby "^10.0.1" - import-fresh "^3.2.1" + import-fresh "^3.2.2" + joi "^17.2.1" loader-utils "^1.2.3" lodash "^4.17.19" lodash.flatmap "^4.5.0" @@ -1278,143 +1588,161 @@ utility-types "^3.10.0" webpack "^4.44.1" -"@docusaurus/plugin-content-pages@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-alpha.66.tgz#2ae8a0340a1398647cc8a1c941eab15a3196e728" - integrity sha512-mY26Aeb/Wf+NFLy70YvXgdLTB+2iPN0SKOVKYwgg6ZN7Nm2kPwEpSVRq2iwiqlWk2G/vOM+ADm99Gxvm3kS61A== - dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/mdx-loader" "2.0.0-alpha.66" - "@docusaurus/types" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" - "@docusaurus/utils-validation" "2.0.0-alpha.66" - "@hapi/joi" "17.1.1" +"@docusaurus/plugin-content-pages@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-alpha.70.tgz#6cb937c9601d92bb616c7d95974d780d1a708ef7" + integrity sha512-HiFa5l1RDs155ATyYKkPtyIs/d6WJgSAyVfY5ji0Bsixp/K/Kh9YUZYMeTfeMIdhGYe3AAJz+PSZHYRpwTo1wA== + dependencies: + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/mdx-loader" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" + "@docusaurus/utils-validation" "2.0.0-alpha.70" globby "^10.0.1" + joi "^17.2.1" loader-utils "^1.2.3" + lodash "^4.17.19" minimatch "^3.0.4" remark-admonitions "^1.2.1" slash "^3.0.0" webpack "^4.44.1" -"@docusaurus/plugin-debug@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-alpha.66.tgz#4f44c39d21c6e85c7c7a24279006323e7b7837a2" - integrity sha512-9AZaEUxaY0CDOCWXQMfY3TzG79HkquZlVeJOZaA6IvCoK/Oq3B58TMNLiQyA6TA2DYf5ZYQorLJaMd02x5qBQw== +"@docusaurus/plugin-debug@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-alpha.70.tgz#7a41d24151a92195311c85ab827656cf705a0c68" + integrity sha512-h/x5KtS/YJerhY6C6sJOaP9gMaSVnjj1qZ6r9E/IFujQJ7bSKnk1unqBQpVXADkQhP081ENPL01ubc0/JbE1Mw== dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/types" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" react-json-view "^1.19.1" -"@docusaurus/plugin-google-analytics@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-alpha.66.tgz#ac494deb6d94c161dba760ee8221f007b60e83a4" - integrity sha512-HVWRLHtlQYpVqH3MHloUmktJMXt7oMDQzBlKzrwAMiWUK1oXFX35DrKjTt2SE2SADpObnwWFjo0E71YT0ApQLw== +"@docusaurus/plugin-google-analytics@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-alpha.70.tgz#9476314353d585716cbdd408319ff30bdbda4f87" + integrity sha512-Ah9W83ZnA0VvmflKNuGq5f/CaEjWJxhjkISQn09/ykEvXfWV33000Bhck4RoCr5YxD+GBEBT5suG5LKH7Qkigw== dependencies: - "@docusaurus/core" "2.0.0-alpha.66" + "@docusaurus/core" "2.0.0-alpha.70" -"@docusaurus/plugin-google-gtag@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-alpha.66.tgz#d780ea3ed91a065eb9cf4042fafbdd6a7e7c7d75" - integrity sha512-MVnzApLSQaC38nVS+A/WkXEV4kHeX6Q/KM2DqkLeovNWLBtkQ0aHL3bvn1clAEmB33Pia0v93mzG+I1+9mrquA== +"@docusaurus/plugin-google-gtag@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-alpha.70.tgz#a90e54830a6f95a83cf51b82e7e6adcf6a699dc1" + integrity sha512-K3s894PqMPQnGXEZs0bSs2bRE3bVXFYSb/RN+K9sNd7zxGuOX4UytuvpXP+1r0Hj/YTwQIjj7AKsND0ZpDJHyw== dependencies: - "@docusaurus/core" "2.0.0-alpha.66" + "@docusaurus/core" "2.0.0-alpha.70" -"@docusaurus/plugin-sitemap@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-alpha.66.tgz#afb96066e5b51c2bb3b67ac5d9d13802be5b1d0c" - integrity sha512-ztDevVIREyq8g+QhSGpDqscVqtubcPnEE3a4JwWSALQ2D6JscIxg897axwZSZNUMxrHBuXRjOEYOtVb/O/stVg== +"@docusaurus/plugin-sitemap@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-alpha.70.tgz#1eb02e4a4ecf5fb2bdf641a6f962ae421ff86916" + integrity sha512-ev9yNLPoeHP03jTz67daGd7yA7YhUwHeoWz14SyiKuU7OYtwL/8SJTn/V5kMDRl7o8FRQt9T//mRkpa270hmXw== dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/types" "2.0.0-alpha.66" - "@hapi/joi" "17.1.1" - fs-extra "^8.1.0" + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + fs-extra "^9.0.1" + joi "^17.2.1" sitemap "^3.2.2" -"@docusaurus/preset-classic@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-alpha.66.tgz#02db88bd1faea52ebc4cd56dd85c5249bd90bab8" - integrity sha512-FjxjchzUS6vOUSr9Pc5kqOSQAnc+cAYsR4pTlqwD2uOJcZMr2vQ6jeKbJnhEmUYwAvzdKOVnCndnxbA+Ii8L3w== - dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/plugin-content-blog" "2.0.0-alpha.66" - "@docusaurus/plugin-content-docs" "2.0.0-alpha.66" - "@docusaurus/plugin-content-pages" "2.0.0-alpha.66" - "@docusaurus/plugin-debug" "2.0.0-alpha.66" - "@docusaurus/plugin-google-analytics" "2.0.0-alpha.66" - "@docusaurus/plugin-google-gtag" "2.0.0-alpha.66" - "@docusaurus/plugin-sitemap" "2.0.0-alpha.66" - "@docusaurus/theme-classic" "2.0.0-alpha.66" - "@docusaurus/theme-search-algolia" "2.0.0-alpha.66" - -"@docusaurus/theme-classic@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-alpha.66.tgz#45318a28751cadf59105e8ddb648ac2d1632af9a" - integrity sha512-WsWqzfzA2gIF5TUMGSbiAeDeNZtKvsgymTQzalcwyhyT/QI0ywcag+03Bmjeq4H3PTC3qU+tkhddO2Rh5w/YCw== - dependencies: - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/plugin-content-blog" "2.0.0-alpha.66" - "@docusaurus/plugin-content-docs" "2.0.0-alpha.66" - "@docusaurus/plugin-content-pages" "2.0.0-alpha.66" - "@docusaurus/types" "2.0.0-alpha.66" - "@docusaurus/utils-validation" "2.0.0-alpha.66" - "@hapi/joi" "^17.1.1" - "@mdx-js/mdx" "^1.5.8" - "@mdx-js/react" "^1.5.8" +"@docusaurus/preset-classic@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-alpha.70.tgz#7857f606eecdbaa34f8df83d62812908be02126f" + integrity sha512-Zx98KryJjHiqzGisWKR0glXl0HXuf/YbcK9yUl6ySyS+6cIMAuGMS0HGLgbvvEmYjywz7nMLpijzGderEOihjQ== + dependencies: + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/plugin-content-blog" "2.0.0-alpha.70" + "@docusaurus/plugin-content-docs" "2.0.0-alpha.70" + "@docusaurus/plugin-content-pages" "2.0.0-alpha.70" + "@docusaurus/plugin-debug" "2.0.0-alpha.70" + "@docusaurus/plugin-google-analytics" "2.0.0-alpha.70" + "@docusaurus/plugin-google-gtag" "2.0.0-alpha.70" + "@docusaurus/plugin-sitemap" "2.0.0-alpha.70" + "@docusaurus/theme-classic" "2.0.0-alpha.70" + "@docusaurus/theme-search-algolia" "2.0.0-alpha.70" + +"@docusaurus/theme-classic@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-alpha.70.tgz#58e2dceee1076980700865df460e771e8d78cb68" + integrity sha512-lKU+fgSd08fo3LNYTw31Wty7RgAdFm8bEOwBNkKZcCFnatTSG4qyDbrDZclCQT/SpXSv9XIEKUc0irg2IH6Qrg== + dependencies: + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/plugin-content-blog" "2.0.0-alpha.70" + "@docusaurus/plugin-content-docs" "2.0.0-alpha.70" + "@docusaurus/plugin-content-pages" "2.0.0-alpha.70" + "@docusaurus/theme-common" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" + "@docusaurus/utils-validation" "2.0.0-alpha.70" + "@mdx-js/mdx" "^1.6.21" + "@mdx-js/react" "^1.6.21" "@types/react-toggle" "^4.0.2" clsx "^1.1.1" copy-text-to-clipboard "^2.2.0" - infima "0.2.0-alpha.13" + infima "0.2.0-alpha.18" + joi "^17.2.1" lodash "^4.17.19" - parse-numeric-range "^0.0.2" - prism-react-renderer "^1.1.0" - prismjs "^1.20.0" + parse-numeric-range "^1.2.0" + prism-react-renderer "^1.1.1" + prismjs "^1.22.0" prop-types "^15.7.2" - react-router-dom "^5.1.2" + react-router-dom "^5.2.0" react-toggle "^4.1.1" -"@docusaurus/theme-search-algolia@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-alpha.66.tgz#a808c8618523f473c85c691ea62388688de5e32a" - integrity sha512-5k/Fwt81Gyjv9vPE+gO8mraEHx5IqEmHLwqld5yXj7yix5XrxywkaanHqC0cFJG4MFUBgF6vNjJC8CtfLnT4Tw== - dependencies: - "@docsearch/react" "^1.0.0-alpha.27" - "@docusaurus/core" "2.0.0-alpha.66" - "@docusaurus/utils" "2.0.0-alpha.66" - "@hapi/joi" "^17.1.1" +"@docusaurus/theme-common@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-alpha.70.tgz#fa42aef2ec1b535d37f72fc978a3138c49667a37" + integrity sha512-Ge/dLGPCJhtyvumSMg0BlWcF00d1Qd2KnHf8kL/0nTxe257yNTHIOK95LKhIPAdcVgxG+ge9N0XcBm4KaubASQ== + dependencies: + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/plugin-content-blog" "2.0.0-alpha.70" + "@docusaurus/plugin-content-docs" "2.0.0-alpha.70" + "@docusaurus/plugin-content-pages" "2.0.0-alpha.70" + "@docusaurus/types" "2.0.0-alpha.70" + +"@docusaurus/theme-search-algolia@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-alpha.70.tgz#7f41241e0d22e89438817a3d4a27d880116c06c1" + integrity sha512-xuoWZ+HUKzn1A5vPlNZM8mtyRL5uo15o34OX/i7HkTRmBVymWO1bBE0lECfDVJU2JUYGmwjpDXhZzNLDZmZRWg== + dependencies: + "@docsearch/react" "^3.0.0-alpha.31" + "@docusaurus/core" "2.0.0-alpha.70" + "@docusaurus/theme-common" "2.0.0-alpha.70" + "@docusaurus/utils" "2.0.0-alpha.70" algoliasearch "^4.0.0" algoliasearch-helper "^3.1.1" clsx "^1.1.1" - eta "^1.1.1" + eta "^1.11.0" + joi "^17.2.1" lodash "^4.17.19" -"@docusaurus/types@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-alpha.66.tgz#192b166cb62fe85e0218f01e3c8272e2986b5086" - integrity sha512-Zd2Kguw0+3faifr83ruIV4i/+KqfqM+zK3DpqCBxdtkP+ORLKbgsIQ48fJ40OOhQrvl38Ay4E+1w7USrrkj4Qg== +"@docusaurus/types@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-alpha.70.tgz#44b98290919cca2505aea334daecf762c7537d10" + integrity sha512-QoHmMiJhRDq5P/4o3eUIiJebdwRjShFlal01DST5B8MZo4k0ogl57FNHqJvIHc93NgonZzFlvC/auLlBnc/d4Q== dependencies: "@types/webpack" "^4.41.0" commander "^4.0.1" querystring "0.2.0" webpack-merge "^4.2.2" -"@docusaurus/utils-validation@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-alpha.66.tgz#e888332ceb3339fc7e06a2d1d0311f4346747598" - integrity sha512-vlenwY3THondey21x1qAUZyDz9qiG7ec2CBM9HgY1Ns8XhrKah9zz7TEGXjqM9lhqMQQRkvcCcveti9EXR0fcA== +"@docusaurus/utils-validation@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-alpha.70.tgz#04f24a7b3a4568ca164a8c1a4cf0caa8ba5caa6e" + integrity sha512-GJonaRjiJtlCk1+RfKA9f0YwRsSRGFMVbl6DrFidTgs4FmRb0hQsN4fnllsBvBJtbDZYwPTQ3T7c4cKJ/Ll7bQ== dependencies: - "@docusaurus/utils" "2.0.0-alpha.66" - "@hapi/joi" "17.1.1" + "@docusaurus/utils" "2.0.0-alpha.70" chalk "^3.0.0" + joi "^17.2.1" -"@docusaurus/utils@2.0.0-alpha.66": - version "2.0.0-alpha.66" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-alpha.66.tgz#ef679896e7d7e536cc8196cc303f5f2ced1f5ebb" - integrity sha512-47jGB+Z3YVM6Xf1hxyNbJLMmc1qoTLmfwSf7NseKSkpjucbc5Ueivr+oVYp5yWoZw5sT5bObmdJYfJoD/RrbOg== +"@docusaurus/utils@2.0.0-alpha.70": + version "2.0.0-alpha.70" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-alpha.70.tgz#01779efcb4ff3bf39f9e74b3ef06fc2c8a43633a" + integrity sha512-xNSUcE7fGcneH00CPCEY0SP5V7H6pLEcu620UiU/m1367tCMsmv+MZcnII2ACcjAtvhjS22v/KLippM3VeTXqQ== dependencies: + "@docusaurus/types" "2.0.0-alpha.70" + chalk "^3.0.0" escape-string-regexp "^2.0.0" - fs-extra "^8.1.0" + fs-extra "^9.0.1" gray-matter "^4.0.2" + lodash "^4.17.20" lodash.camelcase "^4.3.0" lodash.kebabcase "^4.1.1" resolve-pathname "^3.0.0" @@ -1430,81 +1758,11 @@ url "^0.11.0" webpack-sources "^1.4.3" -"@francoischalifour/autocomplete-core@^1.0.0-alpha.28": - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/@francoischalifour/autocomplete-core/-/autocomplete-core-1.0.0-alpha.28.tgz#6b9d8491288e77f831e9b345d461623b0d3f5005" - integrity sha512-rL9x+72btViw+9icfBKUJjZj87FgjFrD2esuTUqtj4RAX3s4AuVZiN8XEsfjQBSc6qJk31cxlvqZHC/BIyYXgg== - -"@francoischalifour/autocomplete-preset-algolia@^1.0.0-alpha.28": - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/@francoischalifour/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.28.tgz#a5ad7996f42e43e4acbb4e0010d663746d0e9997" - integrity sha512-bprfNmYt1opFUFEtD2XfY/kEsm13bzHQgU80uMjhuK0DJ914IjolT1GytpkdM6tJ4MBvyiJPP+bTtWO+BZ7c7w== - -"@hapi/address@2.x.x": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" - integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== - -"@hapi/address@^4.0.1": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.1.0.tgz#d60c5c0d930e77456fdcde2598e77302e2955e1d" - integrity sha512-SkszZf13HVgGmChdHo/PxchnSaCJ6cetVqLzyciudzZRT0jcOouIF/Q93mgjw8cce+D+4F4C1Z/WrfFN+O3VHQ== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@hapi/bourne@1.x.x": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" - integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== - -"@hapi/formula@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128" - integrity sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A== - -"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": - version "8.5.1" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" - integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== - "@hapi/hoek@^9.0.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" integrity sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw== -"@hapi/joi@17.1.1", "@hapi/joi@^17.1.1": - version "17.1.1" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-17.1.1.tgz#9cc8d7e2c2213d1e46708c6260184b447c661350" - integrity sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg== - dependencies: - "@hapi/address" "^4.0.1" - "@hapi/formula" "^2.0.0" - "@hapi/hoek" "^9.0.0" - "@hapi/pinpoint" "^2.0.0" - "@hapi/topo" "^5.0.0" - -"@hapi/joi@^15.1.0": - version "15.1.1" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" - integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== - dependencies: - "@hapi/address" "2.x.x" - "@hapi/bourne" "1.x.x" - "@hapi/hoek" "8.x.x" - "@hapi/topo" "3.x.x" - -"@hapi/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-2.0.0.tgz#805b40d4dbec04fc116a73089494e00f073de8df" - integrity sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw== - -"@hapi/topo@3.x.x": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" - integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== - dependencies: - "@hapi/hoek" "^8.3.0" - "@hapi/topo@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7" @@ -1512,24 +1770,24 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@mdx-js/mdx@^1.5.8": - version "1.6.19" - resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.19.tgz#a89522f53d0712691115b301a4fbd04933714a6f" - integrity sha512-L3eLhEFnV/2bcb9XwOegsRmLHd1oEDQPtTBVezhptQ5U1YM+/WQNzx1apjzVTAyukwOanUXnTUMjRUtqJNgFCg== +"@mdx-js/mdx@^1.6.21": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" + integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA== dependencies: - "@babel/core" "7.11.6" - "@babel/plugin-syntax-jsx" "7.10.4" + "@babel/core" "7.12.9" + "@babel/plugin-syntax-jsx" "7.12.1" "@babel/plugin-syntax-object-rest-spread" "7.8.3" - "@mdx-js/util" "1.6.19" - babel-plugin-apply-mdx-type-prop "1.6.19" - babel-plugin-extract-import-names "1.6.19" + "@mdx-js/util" "1.6.22" + babel-plugin-apply-mdx-type-prop "1.6.22" + babel-plugin-extract-import-names "1.6.22" camelcase-css "2.0.1" - detab "2.0.3" + detab "2.0.4" hast-util-raw "6.0.1" lodash.uniq "4.5.0" - mdast-util-to-hast "9.1.1" + mdast-util-to-hast "10.0.1" remark-footnotes "2.0.0" - remark-mdx "1.6.19" + remark-mdx "1.6.22" remark-parse "8.0.3" remark-squeeze-paragraphs "4.0.0" style-to-object "0.3.0" @@ -1537,15 +1795,15 @@ unist-builder "2.0.3" unist-util-visit "2.0.3" -"@mdx-js/react@^1.5.8": - version "1.6.19" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.19.tgz#fce0f2b802804258b67817550bf3186dde2b1bd6" - integrity sha512-RS37Tagqyp2R0XFPoUZeSbZC5uJQRPhqOHWeT1LEwxESjMWb3VORHz7E827ldeQr3UW6VEQEyq/THegu+bLj6A== +"@mdx-js/react@1.6.22", "@mdx-js/react@^1.6.21": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" + integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== -"@mdx-js/util@1.6.19": - version "1.6.19" - resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.19.tgz#5d4d8f66536d6653963ab2600490b52c3df546be" - integrity sha512-bkkQNSHz3xSr3KRHUQ2Qk2XhewvvXAOUqjIUKwcQuL4ijOA4tUHZfUgXExi5CpMysrX7izcsyICtXjZHlfJUjg== +"@mdx-js/util@1.6.22": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" + integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" @@ -1588,6 +1846,23 @@ dependencies: mkdirp "^1.0.4" +"@sideway/address@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.0.tgz#0b301ada10ac4e0e3fa525c90615e0b61a72b78d" + integrity sha512-wAH/JYRXeIFQRsxerIuLjgUu2Xszam+O5xKeatJ4oudShOOirfmsQ1D6LL54XOU2tizpCYku+s1wmU0SYdpoSA== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -2254,12 +2529,17 @@ async@^2.6.2: dependencies: lodash "^4.17.14" +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^9.6.1: +autoprefixer@^9.4.7, autoprefixer@^9.6.1: version "9.8.6" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== @@ -2272,6 +2552,13 @@ autoprefixer@^9.6.1: postcss "^7.0.32" postcss-value-parser "^4.1.0" +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -2281,36 +2568,42 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-loader@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" - integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw== +babel-loader@^8.2.1: + version "8.2.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" + integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g== dependencies: - find-cache-dir "^2.1.0" + find-cache-dir "^3.3.1" loader-utils "^1.4.0" - mkdirp "^0.5.3" - pify "^4.0.1" + make-dir "^3.1.0" schema-utils "^2.6.5" -babel-plugin-apply-mdx-type-prop@1.6.19: - version "1.6.19" - resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.19.tgz#423792e9f7cd06e5b270e66c661ac9e454cdb4fe" - integrity sha512-zAuL11EaBbeNpfTqsa9xP7mkvX3V4LaEV6M9UUaI4zQtTqN5JwvDyhNsALQs5Ud7WFQSXtoqU74saTgE+rgZOw== +babel-plugin-apply-mdx-type-prop@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b" + integrity sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ== dependencies: "@babel/helper-plugin-utils" "7.10.4" - "@mdx-js/util" "1.6.19" + "@mdx-js/util" "1.6.22" -babel-plugin-dynamic-import-node@^2.3.0, babel-plugin-dynamic-import-node@^2.3.3: +babel-plugin-dynamic-import-node@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== dependencies: object.assign "^4.1.0" -babel-plugin-extract-import-names@1.6.19: - version "1.6.19" - resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.19.tgz#637fad6c47e6dc69e08716cc90e3a87a2fba8c9c" - integrity sha512-5kbSEhQdg1ybR9OnxybbyR1PXw51z6T6ZCtX3vYSU6t1pC/+eBlSzWXyU2guStbwQgJyxS+mHWSNnL7PUdzAlw== +babel-plugin-extract-import-names@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" + integrity sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ== dependencies: "@babel/helper-plugin-utils" "7.10.4" @@ -2563,6 +2856,17 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.6.4, browserslist@^4. escalade "^3.1.1" node-releases "^1.1.65" +browserslist@^4.14.5, browserslist@^4.16.1: + version "4.16.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" + integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== + dependencies: + caniuse-lite "^1.0.30001181" + colorette "^1.2.1" + electron-to-chromium "^1.3.649" + escalade "^3.1.1" + node-releases "^1.1.70" + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -2766,6 +3070,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, can resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001154.tgz#f3bbc245ce55e4c1cd20fa731b097880181a7f17" integrity sha512-y9DvdSti8NnYB9Be92ddMZQrcOe04kcQtcxtBx4NkB04+qZ+JUWotnXBJTmxlKudhxNTQ3RRknMwNU2YQl/Org== +caniuse-lite@^1.0.30001181: + version "1.0.30001181" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001181.tgz#4f0e5184e1ea7c3bf2727e735cbe7ca9a451d673" + integrity sha512-m5ul/ARCX50JB8BSNM+oiPmQrR5UmngaQ3QThTTp5HcIIQGP/nPBs82BYLE+tigzm3VW+F4BJIhUyaVtEweelQ== + ccount@^1.0.0, ccount@^1.0.3: version "1.1.0" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" @@ -2888,6 +3197,21 @@ chokidar@^3.3.0, chokidar@^3.4.1: optionalDependencies: fsevents "~2.1.2" +chokidar@^3.4.3: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -3228,10 +3552,10 @@ copy-text-to-clipboard@^2.2.0: resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-2.2.0.tgz#329dd6daf8c42034c763ace567418401764579ae" integrity sha512-WRvoIdnTs1rgPMkgA2pUOa/M4Enh2uzCwdKsOMYNAJiz/4ZvEJgmbF4OmninPmlFdAWisfeh0tH+Cpf7ni3RqQ== -copy-webpack-plugin@^6.0.3: - version "6.2.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.2.1.tgz#8015e4d5c5e637ab7b39c76daa9e03c7a4bf1ae5" - integrity sha512-VH2ZTMIBsx4p++Lmpg77adZ0KUyM5gFR/9cuTrbneNnJlcQXUFvsNariPqq2dq2kV3F2skHiDGPQCyKWy1+U0Q== +copy-webpack-plugin@^6.3.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e" + integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== dependencies: cacache "^15.0.5" fast-glob "^3.2.4" @@ -3253,6 +3577,14 @@ core-js-compat@^3.6.2: browserslist "^4.8.5" semver "7.0.0" +core-js-compat@^3.8.0: + version "3.8.3" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.3.tgz#9123fb6b9cad30f0651332dc77deba48ef9b0b3f" + integrity sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog== + dependencies: + browserslist "^4.16.1" + semver "7.0.0" + core-js-pure@^3.0.0: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" @@ -3496,6 +3828,18 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +cssnano-preset-advanced@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-4.0.7.tgz#d981527b77712e2f3f3f09c73313e9b71b278b88" + integrity sha512-j1O5/DQnaAqEyFFQfC+Z/vRlLXL3LxJHN+lvsfYqr7KgPH74t69+Rsy2yXkovWNaJjZYBpdz2Fj8ab2nH7pZXw== + dependencies: + autoprefixer "^9.4.7" + cssnano-preset-default "^4.0.7" + postcss-discard-unused "^4.0.1" + postcss-merge-idents "^4.0.1" + postcss-reduce-idents "^4.0.2" + postcss-zindex "^4.0.1" + cssnano-preset-default@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" @@ -3728,10 +4072,10 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -detab@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.3.tgz#33e5dd74d230501bd69985a0d2b9a3382699a130" - integrity sha512-Up8P0clUVwq0FnFjDclzZsy9PadzRn5FFxrr47tQQvMHqyiFYVbpH8oXDzWtF0Q7pYy3l+RPmtBl+BsFF6wH0A== +detab@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" + integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g== dependencies: repeat-string "^1.5.4" @@ -3911,6 +4255,11 @@ electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.585: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.585.tgz#71cdb722c73488b9475ad1c572cf43a763ef9081" integrity sha512-xoeqjMQhgHDZM7FiglJAb2aeOxHZWFruUc3MbAGTgE7GB8rr5fTn1Sdh5THGuQtndU3GuXlu91ZKqRivxoCZ/A== +electron-to-chromium@^1.3.649: + version "1.3.650" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.650.tgz#24e821fff2ed61fd71fee092f2a0631b3c0c22a6" + integrity sha512-j6pRuNylFBbroG6NB8Lw/Im9oDY74s2zWHBP5TmdYg73cBuL6cz//SMgolVa0gIJk/DSL+kO7baJ1DSXW1FUZg== + elliptic@^6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" @@ -4110,10 +4459,10 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eta@^1.1.1: - version "1.11.0" - resolved "https://registry.yarnpkg.com/eta/-/eta-1.11.0.tgz#cfc260fb4e77e1be96ac141f3e50b28da3e3c182" - integrity sha512-lfqIE6qD55WFYT6E0phTBUe0sapHJhfvRDB7jSpXxFGwzDaP69kQqRyF7krBe8I1QzF5nE1yAByiIOLB630x4Q== +eta@^1.11.0: + version "1.12.1" + resolved "https://registry.yarnpkg.com/eta/-/eta-1.12.1.tgz#d985766591676c323f02dfc48a67539212745937" + integrity sha512-H8npoci2J/7XiPnVcCVulBSPsTNGvGaINyMjQDU8AFqp9LGsEYS88g2CiU+d01Sg44WtX7o4nb8wUJ9vnI+tiA== etag@~1.8.1: version "1.8.1" @@ -4360,10 +4709,10 @@ fbjs@^0.8.0, fbjs@^0.8.4: setimmediate "^1.0.5" ua-parser-js "^0.7.18" -feed@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.1.tgz#b246ef891051c7dbf088ca203341d9fb0444baee" - integrity sha512-l28KKcK1J/u3iq5dRDmmoB2p7dtBfACC2NqJh4dI2kFptxH0asfjmOfcxqh5Sv8suAlVa73gZJ4REY5RrafVvg== +feed@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e" + integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ== dependencies: xml-js "^1.6.11" @@ -4379,7 +4728,7 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-loader@^6.0.0: +file-loader@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== @@ -4491,6 +4840,11 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== +follow-redirects@^1.10.0: + version "1.13.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" + integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA== + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -4547,14 +4901,15 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== +fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== dependencies: + at-least-node "^1.0.0" graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" + jsonfile "^6.0.1" + universalify "^2.0.0" fs-minipass@^2.0.0: version "2.1.0" @@ -4591,6 +4946,11 @@ fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fsevents@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f" + integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -5052,7 +5412,7 @@ html-entities@^1.3.1: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== -html-minifier-terser@^5.0.1, html-minifier-terser@^5.0.5: +html-minifier-terser@^5.0.1, html-minifier-terser@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== @@ -5075,17 +5435,17 @@ html-void-elements@^1.0.0: resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w== -html-webpack-plugin@^4.0.4: - version "4.5.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz#625097650886b97ea5dae331c320e3238f6c121c" - integrity sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw== +html-webpack-plugin@^4.5.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.1.tgz#40aaf1b5cb78f2f23a83333999625c20929cda65" + integrity sha512-yzK7RQZwv9xB+pcdHNTjcqbaaDZ+5L0zJHXfi89iWIZmb/FtzxhLk0635rmJihcQbs3ZUF27Xp4oWGx6EK56zg== dependencies: "@types/html-minifier-terser" "^5.0.0" "@types/tapable" "^1.0.5" "@types/webpack" "^4.41.8" html-minifier-terser "^5.0.1" loader-utils "^1.2.3" - lodash "^4.17.15" + lodash "^4.17.20" pretty-error "^2.1.1" tapable "^1.1.3" util.promisify "1.0.0" @@ -5239,7 +5599,7 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.1.0, import-fresh@^3.2.1: +import-fresh@^3.1.0: version "3.2.2" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== @@ -5247,6 +5607,14 @@ import-fresh@^3.1.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.2.2: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-from@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" @@ -5287,10 +5655,10 @@ infer-owner@^1.0.3, infer-owner@^1.0.4: resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== -infima@0.2.0-alpha.13: - version "0.2.0-alpha.13" - resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.13.tgz#2d28a4cf0af988abe804cdab34652df921201055" - integrity sha512-BxCZ1pMcUF0PcL4WV07l/lvaeBBdUUw7uVqNyyeGAutzDpkDyFOl5gOv9wFAJKLo5yerPNFXxFPgDitNjctqIA== +infima@0.2.0-alpha.18: + version "0.2.0-alpha.18" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.18.tgz#8ac62711f13ef99b1f4a45b3ac14571722a2ccf6" + integrity sha512-ndSEffXzjgM/eiSm5jpLTX6ON9MmylzxqBnV2bTiC3kCSyDYdvzTs+bSwf+C4TWayuqnRTnBK1JUePo3m6Bnfg== inflight@^1.0.4: version "1.0.6" @@ -5804,6 +6172,17 @@ jest-worker@^26.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" +joi@^17.2.1, joi@^17.3.0: + version "17.3.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.3.0.tgz#f1be4a6ce29bc1716665819ac361dfa139fff5d2" + integrity sha512-Qh5gdU6niuYbUIUV5ejbsMiiFmBdw8Kcp8Buj2JntszCkCfxJ9Cz76OtHxOZMPXrt5810iDIXs+n1nNVoquHgg== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.0" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -5871,10 +6250,12 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" optionalDependencies: graceful-fs "^4.1.6" @@ -6163,7 +6544,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5, lodash@^4.5.2: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -6219,7 +6600,7 @@ make-dir@^2.0.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0, make-dir@^3.0.2: +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -6259,21 +6640,21 @@ mdast-squeeze-paragraphs@^4.0.0: dependencies: unist-util-remove "^2.0.0" -mdast-util-definitions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-3.0.1.tgz#06af6c49865fc63d6d7d30125569e2f7ae3d0a86" - integrity sha512-BAv2iUm/e6IK/b2/t+Fx69EL/AGcq/IG2S+HxHjDJGfLJtd6i9SZUS76aC9cig+IEucsqxKTR0ot3m933R3iuA== +mdast-util-definitions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" + integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ== dependencies: unist-util-visit "^2.0.0" -mdast-util-to-hast@9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-9.1.1.tgz#953ff12aed57464b11d7e5549a45913e561909fa" - integrity sha512-vpMWKFKM2mnle+YbNgDXxx95vv0CoLU0v/l3F5oFAG5DV7qwkZVWA206LsAdOnEVyf5vQcLnb3cWJywu7mUxsQ== +mdast-util-to-hast@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" + integrity sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA== dependencies: "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.3" - mdast-util-definitions "^3.0.0" + "@types/unist" "^2.0.0" + mdast-util-definitions "^4.0.0" mdurl "^1.0.0" unist-builder "^2.0.0" unist-util-generated "^1.0.0" @@ -6708,6 +7089,11 @@ node-releases@^1.1.52, node-releases@^1.1.65: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.65.tgz#52d9579176bd60f23eba05c4438583f341944b81" integrity sha512-YpzJOe2WFIW0V4ZkJQd/DGR/zdVwc/pI4Nl1CZrBO19FdRcSTmsuhdttw9rsTzzJLrNcSloLiBbEYx1C4f6gpA== +node-releases@^1.1.70: + version "1.1.70" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.70.tgz#66e0ed0273aa65666d7fe78febe7634875426a08" + integrity sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw== + normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -6909,7 +7295,7 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -optimize-css-assets-webpack-plugin@^5.0.3: +optimize-css-assets-webpack-plugin@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz#85883c6528aaa02e30bbad9908c92926bb52dc90" integrity sha512-wqd6FdI2a5/FdoiCNNkEvLeA//lHHfG24Ln2Xm2qqdIk4aOlsR18jwpyOihqQ8849W3qu2DX8fOYxpvTMj+93A== @@ -7088,10 +7474,10 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-numeric-range@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4" - integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ= +parse-numeric-range@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.2.0.tgz#aa70b00f29624ed13e9f943e9461b306e386b0fa" + integrity sha512-1q2tXpAOplPxcl8vrIGPWz1dJxxfmdRkCFcpxxMBerDnGuuHalOWF/xj9L8Nn5XoTUoB/6F0CeQBp2fMgkOYFg== parse5@^5.0.0: version "5.1.1" @@ -7356,6 +7742,14 @@ postcss-colormin@^4.0.3: postcss "^7.0.0" postcss-value-parser "^3.0.0" +postcss-combine-duplicated-selectors@^9.1.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-9.4.0.tgz#dae866debae5f93b58e13e6cc69419105e91336a" + integrity sha512-rMnO1H3wgR1T6QSlK3i8Slz9p3xD+0yOi4J7qwh/5PGR3z8jbgYvRlNKAIvXDtGBQbJKoWs4df5skL3a/fdUEA== + dependencies: + postcss "^7.0.0" + postcss-selector-parser "^6.0.0" + postcss-convert-values@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" @@ -7423,6 +7817,15 @@ postcss-discard-overridden@^4.0.1: dependencies: postcss "^7.0.0" +postcss-discard-unused@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-4.0.1.tgz#ee7cc66af8c7e8c19bd36f12d09c4bde4039abea" + integrity sha512-/3vq4LU0bLH2Lj4NYN7BTf2caly0flUB7Xtrk9a5K3yLuXMkHMqMO/x3sDq8W2b1eQFSCyY0IVz2L+0HP8kUUA== + dependencies: + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + uniqs "^2.0.0" + postcss-double-position-gradients@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" @@ -7524,6 +7927,16 @@ postcss-media-minmax@^4.0.0: dependencies: postcss "^7.0.2" +postcss-merge-idents@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-4.0.1.tgz#b7df282a92f052ea0a66c62d8f8812e6d2cbed23" + integrity sha512-43S/VNdF6II0NZ31YxcvNYq4gfURlPAAsJW/z84avBXQCaP4I4qRHUH18slW/SOlJbcxxCobflPNUApYDddS7A== + dependencies: + cssnano-util-same-parent "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + postcss-merge-longhand@^4.0.11: version "4.0.11" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" @@ -7789,6 +8202,14 @@ postcss-pseudo-class-any-link@^6.0.0: postcss "^7.0.2" postcss-selector-parser "^5.0.0-rc.3" +postcss-reduce-idents@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-4.0.2.tgz#30447a6ec20941e78e21bd4482a11f569c4f455b" + integrity sha512-Tz70Ri10TclPoCtFfftjFVddx3fZGUkr0dEDbIEfbYhFUOFQZZ77TEqRrU0e6TvAvF+Wa5VVzYTpFpq0uwFFzw== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + postcss-reduce-initial@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" @@ -7860,6 +8281,14 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: uniq "^1.0.1" util-deprecate "^1.0.2" +postcss-sort-media-queries@^1.7.26: + version "1.31.21" + resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-1.31.21.tgz#3225ec6eb490402602284ac99963b80461783cee" + integrity sha512-h+HbXXfOVFeLvCJOzl/Z9SqQ25MNpG/73k71756ftisaaJy75h06/Dn6KOwC4OCMN10ewT2PXMzHV03JNKwBbg== + dependencies: + postcss "^7.0.27" + sort-css-media-queries "1.5.0" + postcss-svgo@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" @@ -7898,6 +8327,15 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" +postcss-zindex@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-4.0.1.tgz#8db6a4cec3111e5d3fd99ea70abeda61873d10c1" + integrity sha512-d/8BlQcUdEugZNRM9AdCA2V4fqREUtn/wcixLN3L6ITgc2P/FMcVVYz8QZkhItWT9NB5qr8wuN2dJCE4/+dlrA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: version "7.0.35" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" @@ -7930,15 +8368,15 @@ pretty-time@^1.1.0: resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== -prism-react-renderer@^1.1.0: +prism-react-renderer@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.1.1.tgz#1c1be61b1eb9446a146ca7a50b7bcf36f2a70a44" integrity sha512-MgMhSdHuHymNRqD6KM3eGS0PNqgK9q4QF5P0yoQQvpB6jNjeSAi3jcSAz0Sua/t9fa4xDOMar9HJbLa08gl9ug== -prismjs@^1.20.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.22.0.tgz#73c3400afc58a823dd7eed023f8e1ce9fd8977fa" - integrity sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w== +prismjs@^1.22.0: + version "1.23.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33" + integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA== optionalDependencies: clipboard "^2.0.0" @@ -8195,7 +8633,7 @@ react-fast-compare@^3.1.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== -react-helmet@^6.0.0-beta: +react-helmet@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== @@ -8246,7 +8684,7 @@ react-router-config@^5.1.1: dependencies: "@babel/runtime" "^7.1.2" -react-router-dom@^5.1.2: +react-router-dom@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== @@ -8259,7 +8697,7 @@ react-router-dom@^5.1.2: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-router@5.2.0, react-router@^5.1.2: +react-router@5.2.0, react-router@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== @@ -8475,16 +8913,16 @@ remark-footnotes@2.0.0: resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== -remark-mdx@1.6.19: - version "1.6.19" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.19.tgz#9f5330a6b151c40643ddda81714d45a751b158e0" - integrity sha512-UKK1CFatVPNhgjsIlNQ3GjVl3+6O7x7Hag6oyntFTg8s7sgq+rhWaSfM/6lW5UWU6hzkj520KYBuBlsaSriGtA== +remark-mdx@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd" + integrity sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ== dependencies: - "@babel/core" "7.11.6" + "@babel/core" "7.12.9" "@babel/helper-plugin-utils" "7.10.4" - "@babel/plugin-proposal-object-rest-spread" "7.11.0" - "@babel/plugin-syntax-jsx" "7.10.4" - "@mdx-js/util" "1.6.19" + "@babel/plugin-proposal-object-rest-spread" "7.12.1" + "@babel/plugin-syntax-jsx" "7.12.1" + "@mdx-js/util" "1.6.22" is-alphabetical "1.0.4" remark-parse "8.0.3" unified "9.2.0" @@ -8596,7 +9034,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.1.6, resolve@^1.3.2: version "1.18.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== @@ -8683,12 +9121,7 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= - -rxjs@^6.5.3, rxjs@^6.6.0: +rxjs@^6.5.3, rxjs@^6.6.0, rxjs@^6.6.3: version "6.6.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== @@ -9043,6 +9476,11 @@ sockjs@0.3.20: uuid "^3.4.0" websocket-driver "0.6.5" +sort-css-media-queries@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-1.5.0.tgz#8f605ad372caad0b81be010311882c046e738093" + integrity sha512-QofNE7CEVH1AKdhS7L9IPbV9UtyQYNXyw++8lC+xG6iOLlpzsmncZRiKbihTAESvZ8wOhwnPoesHbMrehrQyyw== + sort-keys@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" @@ -9788,10 +10226,10 @@ unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.1, unist- unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" @@ -9847,7 +10285,7 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-loader@^4.1.0: +url-loader@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== @@ -9985,14 +10423,16 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -wait-file@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/wait-file/-/wait-file-1.0.5.tgz#377f48795f1765046a41bb0671c142ef8e509ae6" - integrity sha512-udLpJY/eOxlrMm3+XD1RLuF2oT9B7J7wiyR5/9xrvQymS6YR6trWvVhzOldHrVbLwyiRmLj9fcvsjzpSXeZHkw== +wait-on@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.2.1.tgz#05b66fcb4d7f5da01537f03e7cf96e8836422996" + integrity sha512-H2F986kNWMU9hKlI9l/ppO6tN8ZSJd35yBljMLa1/vjzWP++Qh6aXyt77/u7ySJFZQqBtQxnvm/xgG48AObXcw== dependencies: - "@hapi/joi" "^15.1.0" - fs-extra "^8.1.0" - rx "^4.1.0" + axios "^0.21.1" + joi "^17.3.0" + lodash "^4.17.20" + minimist "^1.2.5" + rxjs "^6.6.3" watchpack-chokidar2@^2.0.0: version "2.0.0" diff --git a/frontend/assets/BUILD b/frontend/assets/BUILD new file mode 100644 index 0000000000..7203704cad --- /dev/null +++ b/frontend/assets/BUILD @@ -0,0 +1,7 @@ +load("@com_github_airyhq_bazel_tools//web:typescript.bzl", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "assets", +) diff --git a/frontend/assets/airy_demo_login.png b/frontend/assets/images/icons/airy_demo_login.png similarity index 100% rename from frontend/assets/airy_demo_login.png rename to frontend/assets/images/icons/airy_demo_login.png diff --git a/frontend/assets/airy_primary_rgb.svg b/frontend/assets/images/icons/airy_primary_rgb.svg similarity index 100% rename from frontend/assets/airy_primary_rgb.svg rename to frontend/assets/images/icons/airy_primary_rgb.svg diff --git a/frontend/assets/index.ts b/frontend/assets/index.ts new file mode 100644 index 0000000000..b13bb4eb87 --- /dev/null +++ b/frontend/assets/index.ts @@ -0,0 +1 @@ +export * from './'; diff --git a/frontend/assets/scss/colors.scss b/frontend/assets/scss/colors.scss new file mode 100644 index 0000000000..6f9690baae --- /dev/null +++ b/frontend/assets/scss/colors.scss @@ -0,0 +1,29 @@ +:root { + --color-text-contrast: #212428; + --color-text-gray: #737373; + --color-dark-elements-gray: #98a4ab; + --color-light-gray: #cad5db; + --color-background-gray: #f7f7f7; + --color-template-gray: #f0f0f0; + --color-template-highlight: #fff; + --color-blue-white: #f5f8fa; + --color-airy-dark-blue: #1b4469; + --color-airy-logo-blue: #4bb3fd; + --color-hover-blue: #337bb3; + --color-airy-blue: #1578d4; + --color-airy-blue-hover: #1e62d0; + --color-airy-blue-pressed: #1b4469; + --color-fb-cta: #1877f2; + --color-fb-cta-border: #2281fd; + --color-background-blue: #f1faff; + --color-red-alert: #d51548; + --color-accent-magenta: #f7147d; + --color-error-background: #fae6e9; + --color-red-alert: #bf1a2f; + --color-highlight-yellow: #fbbd54; + --color-background-yellow: #fbf9ee; + --color-background-red: #fff7f9; + --color-soft-green: #0da36b; + --color-tag-green: #0e764f; + --color-tag-purple: #730a80; +} diff --git a/frontend/assets/scss/fonts.scss b/frontend/assets/scss/fonts.scss new file mode 100644 index 0000000000..7ee32d73a8 --- /dev/null +++ b/frontend/assets/scss/fonts.scss @@ -0,0 +1,95 @@ +@import url('https://fonts.googleapis.com/css?family=Lato:300,400,700,900'); + +@mixin font-s { + font-family: 'Lato', sans-serif; + font-size: 0.8rem; // 13px + line-height: 1rem; +} + +@mixin font-base { + font-family: 'Lato', sans-serif; + font-size: 1rem; // 16 px + line-height: 1.5rem; +} + +@mixin font-m { + font-family: 'Lato', sans-serif; + font-size: 1.25rem; // 20px + line-height: 2rem; +} + +@mixin font-l { + font-family: 'Lato', sans-serif; + font-size: 1.563rem; // 25px + line-height: 2rem; +} + +@mixin font-xl { + font-family: 'Lato', sans-serif; + font-size: 1.953rem; // 31px + line-height: 2.5rem; +} + +@mixin font-xxl { + font-family: 'Lato', sans-serif; + font-size: 2.441rem; // 39px + line-height: 3rem; +} + +@mixin font-xxxl { + font-family: 'Lato', sans-serif; + font-size: 3.052rem; // 48px + line-height: 3.5rem; +} + +@mixin font-4l { + font-family: 'Lato', sans-serif; + font-size: 3.815rem; // 61px + line-height: 4rem; +} + +@mixin font-5l { + font-family: 'Lato', sans-serif; + font-size: 4.815rem; // 76px + line-height: 4.5rem; +} + +.font-s { + @include font-s; +} + +.font-base { + @include font-base; +} + +.font-m { + @include font-m; +} + +.font-l { + @include font-l; +} + +.font-xl { + @include font-xl; +} + +.font-xl { + @include font-xl; +} + +.font-xxl { + @include font-xxl; +} + +.font-xxxl { + @include font-xxxl; +} + +.font-4l { + @include font-4l; +} + +.font-5l { + @include font-5l; +} diff --git a/frontend/chat-plugin/BUILD b/frontend/chat-plugin/BUILD index 790af5355d..22b4f6ccf7 100644 --- a/frontend/chat-plugin/BUILD +++ b/frontend/chat-plugin/BUILD @@ -8,6 +8,9 @@ load("@io_bazel_rules_docker//container:container.bzl", "container_image") module_deps = [ "//lib/typescript/types", + "//lib/typescript/httpclient", + "//lib/typescript/render", + "//lib/typescript/dates", ] web_app( @@ -44,8 +47,8 @@ ts_library( ts_config( name = "widget_tsconfig", - src = "tsconfig.json", - deps = ["//:tsconfig.json"], + src = "bazel.tsconfig.json", + deps = ["//:bazel.tsconfig.json"], ) pkg_tar( diff --git a/frontend/chat-plugin/bazel.tsconfig.json b/frontend/chat-plugin/bazel.tsconfig.json new file mode 100644 index 0000000000..bc81e96e30 --- /dev/null +++ b/frontend/chat-plugin/bazel.tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../bazel.tsconfig.json", + "compilerOptions": { + "jsxFactory": "h" + } +} diff --git a/frontend/chat-plugin/src/airyRenderProps/AiryInputBar/index.tsx b/frontend/chat-plugin/src/airyRenderProps/AiryInputBar/index.tsx index 66346b050f..4ce6e9a87b 100644 --- a/frontend/chat-plugin/src/airyRenderProps/AiryInputBar/index.tsx +++ b/frontend/chat-plugin/src/airyRenderProps/AiryInputBar/index.tsx @@ -20,7 +20,7 @@ const AiryInputBar = (props: Props) => { } }; - const onSubmit = (e: any) => { + const onSubmit = e => { e.preventDefault(); if (messageString.length) { setMessageString(''); @@ -28,7 +28,7 @@ const AiryInputBar = (props: Props) => { } }; - const handleInputAndChange = (e: any) => { + const handleInputAndChange = e => { const localValue = e.target.value; setMessageString(localValue); }; @@ -56,7 +56,7 @@ const AiryInputBar = (props: Props) => { }; return ( -
onSubmit(e)}> + onSubmit(e)}>