Adaptor untuk menggunakan perpustakaan Instantsearch.js yang mengagumkan dengan Server Pencarian Typesense, untuk membangun antarmuka pencarian yang kaya.
Berikut adalah contoh UI yang dapat Anda buat dengan adapater ini: song-search.typesense.org
Catatan: Jika antarmuka pencarian Anda dibuat pada komponen pelengkapan otomatis khusus, atau didasarkan pada @algolia/autocomplete-js, maka Anda tidak memerlukan adaptor ini untuk menggunakannya dengan Typesense, karena pustaka Typesense-js sudah mendukung pengambilan sisi klien data dari sumber data asinkron apa pun. Baca lebih lanjut di sini.
Orang-orang baik di Algolia telah membangun dan membuat Instantsearch.js menjadi sumber terbuka yang merupakan kumpulan komponen siap pakai yang dapat Anda gunakan untuk membangun pengalaman pencarian interaktif dengan cepat.
Dengan adaptor di repositori ini, Anda akan dapat menggunakan Instantsearch (dan sepupu React, Vue, dan Angular-nya) dengan data yang diindeks di server pencarian Typesense.
Jika Anda belum pernah menggunakan Pencarian Instan sebelumnya, kami sarankan untuk membaca panduan Memulai di sini. Setelah Anda membaca panduan ini, ikuti petunjuk di bawah ini untuk menyambungkan adaptor Typesense ke Pencarian Instan.
Berikut panduan dalam membangun antarmuka pencarian cepat dengan Typesense dan InstantSearch.js: https://typesense.org/docs/0.20.0/guide/search-ui-components.html
Berikut aplikasi starter demo yang menunjukkan cara menggunakan adaptor: https://github.com/typesense/typesense-instantsearch-demo
$ npm install --save typesense-instantsearch-adapter @babel/runtime
atau
$ yarn add typesense-instantsearch-adapter @babel/runtime
atau, Anda juga dapat langsung menyertakan adaptor melalui tag skrip di HTML Anda:
< script src =" https://cdn.jsdelivr.net/npm/typesense-instantsearch-adapter@2/dist/typesense-instantsearch-adapter.min.js " > </ script >
<!-- You might want to pin the version of the adapter used if you don't want to always receive the latest minor version -->
Karena ini adalah adaptor, ia tidak akan menginstal perpustakaan Instantsearch secara otomatis untuk Anda. Anda perlu menginstal salah satu dari yang berikut ini di aplikasi Anda secara langsung:
Anda akan menemukan informasi tentang cara memulai masing-masing perpustakaan di atas di repo masing-masing.
Kami juga merekomendasikan untuk memeriksa create-instantsearch-app untuk membuat UI Pencarian Anda dari template awal.
import instantsearch from "instantsearch.js" ;
import { searchBox , hits } from "instantsearch.js/es/widgets" ;
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [
{
host : "localhost" ,
path : "" , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
port : "8108" ,
protocol : "http" ,
} ,
] ,
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
} ,
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : "name,description,categories" ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
const search = instantsearch ( {
searchClient ,
indexName : "products" ,
} ) ;
search . addWidgets ( [
searchBox ( {
container : "#searchbox" ,
} ) ,
hits ( {
container : "#hits" ,
templates : {
item : `
<div class="hit-name">
{{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}}
</div>
` ,
} ,
} ) ,
] ) ;
search . start ( ) ;
Anda dapat menambahkan widget Pencarian Instan apa pun di sini yang didukung oleh adaptor.
Anda juga akan menemukan contoh yang berfungsi di test/support/testground. Untuk menjalankannya, jalankan npm run testground
dari folder root proyek.
import React from "react" ;
import ReactDOM from "react-dom" ;
import { SearchBox } from "react-instantsearch-dom" ;
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "" , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
protocol : "http" ,
} ,
] ,
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
} ,
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : "name,description,categories" ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
const App = ( ) => (
< InstantSearch indexName = "products" searchClient = { searchClient } >
< SearchBox / >
< Hits / >
< / InstantSearch >
) ;
Anda kemudian dapat menambahkan widget Instantsearch-React apa pun di sini yang didukung oleh adaptor.
Petunjuk di atas juga berlaku untuk React Native.
Aplikasi.vue:
< template >
< ais-instant-search :search-client = " searchClient " index-name = " products " >
< ais-search-box />
< ais-hits >
< div slot = " item " slot-scope = " { item } " >
< h2 >{{ item.name }}</ h2 >
</ div >
</ ais-hits >
</ ais-instant-search >
</ template >
< script >
import TypesenseInstantSearchAdapter from " typesense-instantsearch-adapter " ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ({
server : {
apiKey : " abcd " , // Be sure to use an API key that only allows search operations
nodes : [
{
host : " localhost " ,
path : " " , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
port : " 8108 " ,
protocol : " http " ,
},
],
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
},
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : " name,description,categories " ,
},
});
const searchClient = typesenseInstantsearchAdapter . searchClient ;
export default {
data () {
return {
searchClient,
};
},
};
</ script >
Anda kemudian dapat menambahkan widget Pencarian Instan apa pun di sini yang didukung oleh adaptor.
// app.component.ts
import { Component } from "@angular/core" ;
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [
{
host : "localhost" ,
path : "" , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
port : "8108" ,
protocol : "http" ,
} ,
] ,
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
} ,
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : "name,description,categories" ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
@ Component ( {
selector : "app-root" ,
templateUrl : "./app.component.html" ,
styleUrls : [ "./app.component.css" ] ,
} )
export class AppComponent {
config = {
indexName : "products" ,
searchClient ,
} ;
}
Anda kemudian dapat menambahkan widget Pencarian Instan apa pun di sini yang didukung oleh adaptor.
hierarchicalMenu
Untuk widget ini, Anda ingin membuat kolom independen dalam skema koleksi dengan konvensi penamaan khusus berikut:
field.lvl0
field.lvl1
field.lvl2
untuk hierarki bersarang field.lvl0 > field.lvl1 > field.lvl2
Masing-masing bidang ini juga dapat menampung serangkaian nilai. Ini berguna untuk menangani banyak hierarki.
sortBy
Saat membuat instance widget ini, Anda ingin menyetel nilai nama indeks ke format khusus ini:
search . addWidgets ( [
sortBy ( {
container : "#sort-by" ,
items : [
{ label : "Default" , value : "products" } ,
{ label : "Price (asc)" , value : "products/sort/price:asc" } ,
{ label : "Price (desc)" , value : "products/sort/price:desc" } ,
] ,
} ) ,
] ) ;
Pola umum untuk atribut value adalah: <index_name>[/sort/<sort_by>]
. Adaptor akan menggunakan nilai dalam <sort_by>
sebagai nilai untuk parameter pencarian sort_by
.
configure
Jika Anda perlu menentukan parameter pencarian filter_by
untuk Typesense, Anda ingin menggunakan widget configure
InstantSearch, bersama dengan facetFilters
, numericFilters
atau filters
.
Format untuk facetFilters
dan numericFilters
sama dengan Algolia seperti yang dijelaskan di sini. Namun filters
harus dalam format filter_by
Typesense seperti yang dijelaskan dalam tabel ini.
Menyetel filter_by
di dalam konfigurasi additionalQueryParameters
hanya berfungsi saat widget dimuat pada awalnya, karena Pencarian Instan secara internal kemudian menimpa bidang filter_by
. Baca lebih lanjut di sini.
index
Untuk Pencarian Gabungan / Multi-Indeks, Anda perlu menggunakan widget index
. Untuk kemudian dapat menentukan parameter pencarian yang berbeda untuk setiap indeks/koleksi, Anda dapat menentukannya menggunakan konfigurasi collectionSpecificSearchParameters
:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [ { host : "localhost" , path : "/" , port : "8108" , protocol : "http" } ] ,
} ,
// Search parameters that are common to all collections/indices go here:
additionalSearchParameters : {
numTypos : 3 ,
} ,
// Search parameters that need to be *overridden* on a per-collection-basis go here:
collectionSpecificSearchParameters : {
products : {
query_by : "name,description,categories" ,
} ,
brands : {
query_by : "name" ,
} ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
Pada dasarnya, parameter apa pun yang disetel di collectionSpecificSearchParameters
akan digabungkan dengan nilai di additionalSearchParameters
saat menanyakan Typesense, yang secara efektif menggantikan nilai di additionalSearchParameters
berdasarkan per koleksi.
geoSearch
Algolia menggunakan _geoloc
secara default untuk nama bidang yang menyimpan nilai lat long untuk sebuah rekaman. Di Typesense, Anda dapat memberi nama bidang lokasi geografis apa saja. Jika Anda menggunakan nama selain _geoloc
, Anda perlu menentukannya saat menginisialisasi adaptor seperti di bawah ini, sehingga InstantSearch dapat mengaksesnya:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
geoLocationField : "lat_lng_field" , // <<======
additionalSearchParameters ,
} ) ;
dynamicWidgets
Tersedia pada Server Typesense
v0.25.0.rc12
Widget dynamicWidgets
ini langsung berfungsi tanpa perubahan tambahan, namun jika Anda ingin mengontrol urutan tampilan aspek ini di UI, Instantsearch mengharapkan parameter yang disebut renderingContent
disetel.
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
renderingContent : {
// <<===== Add this, only if you want to control the order of the widgets displayed by dynamicWidgets
facetOrdering : {
facets : {
order : [ "size" , "brand" ] , // <<===== Change this as needed
} ,
} ,
} ,
additionalSearchParameters ,
} ) ;
Baca selengkapnya tentang semua opsi yang tersedia untuk renderingContent
dalam dokumentasi Algolia di sini.
Tersedia pada typeense-instantsearch-adapter
2.7.0-2
Jika ada kolom string di dokumen Anda yang memiliki titik dua :
pada nilainya (misalnya, ada kolom bernama { brand: "a:b" }
, maka Anda perlu menambahkan parameter seperti di bawah ini saat membuat instance adaptor:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
facetableFieldsWithSpecialCharacters : [ "brand" ] , // <======= Add string fields that have colons in their values here, to aid in parsing
additionalSearchParameters ,
} ) ;
Jika ada nama bidang numerik di dokumen Anda yang memiliki karakter khusus seperti >
, <
, =
(misalnya, ada bidang bernama { price>discount: 3.0 }
) maka Anda perlu menambahkan parameter seperti di bawah ini saat membuat instance adaptor:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
facetableFieldsWithSpecialCharacters : [ "price>discount" ] , // // <======= Add numeric fields that have >, < or = in their names, to aid in parsing
additionalSearchParameters ,
} ) ;
facet_by
Tersedia pada Typesense-instantsearch-adapter
2.8.0-1
dan Typesense Serverv0.26.0.rc25
Parameter facet_by
dikelola oleh InstantSearch secara internal saat Anda menggunakan berbagai widget filter.
Namun jika Anda perlu meneruskan opsi khusus ke parameter facet_by
(misalnya: opsi pengurutan sisi server), maka Anda dapat menggunakan parameter facetByOptions
seperti yang ditunjukkan di bawah ini:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
facetByOptions : {
brand : "(sort_by: _alpha:asc)" ,
category : "(sort_by: _alpha:desc)" ,
} , // <======= Add any facet_by parameter as a key value pair. Don't forget the surrounding parantheses in the value.
collectionSpecificFacetByOptions : {
collection1 : {
brand : "(sort_by: _alpha:desc)" ,
} ,
} , // <======= Use this parameter if multiple collections share the same field names, and you want to use different options for each field. This will override facetByOptions for that particular collection.
additionalSearchParameters ,
} ) ;
Perhatikan bahwa untuk mengurutkan dalam RefinementLists, selain mengurutkan di sisi Server Typesense, Anda juga harus meneruskan parameter sortBy
ke widget RefinementList untuk juga mengurutkan hasil dengan tepat di sisi klien.
filter_by
Tersedia pada typeense-instantsearch-adapter
2.8.0-5
Parameter filter_by
dikelola oleh InstantSearch secara internal saat Anda menggunakan berbagai widget filter.
Secara default, adaptor menggunakan pemfilteran yang tepat ( filter_by: field:=value
) saat mengirim kueri ke Typesense. Jika Anda perlu mengonfigurasi adaptor untuk menggunakan :
(pemfilteran tingkat kata tidak persis - filter_by: field:value
), Anda ingin membuat instance adaptor menggunakan konfigurasi filterByOptions
:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
filterByOptions : {
brand : { exactMatch : false } , // <========== Add this to do non-exact word-level filtering
category : { exactMatch : false } ,
} ,
collectionSpecificFilterByOptions : {
collection1 : {
brand : { exactMatch : false } ,
} ,
} , // <======= Use this parameter if multiple collections share the same field names, and you want to use different options for each field. This will override filterByOptions for that particular collection.
additionalSearchParameters ,
} ) ;
Tersedia pada typeense-instantsearch-adapter
2.9.0-0
Berikut cara menonaktifkan aturan override/kurasi, ketika pengguna memilih urutan pengurutan tertentu:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
sortByOptions : {
"field1:desc,field2:desc" : { enable_overrides : false } , // <========== Add this to disable sorting when this particular Typesense `sort_by` string is generated by the sortBy widget
} ,
collectionSpecificSortByOptions : {
collection2 : {
"field1:desc,field2:desc" : { enable_overrides : false } ,
} ,
} , // <======= Use this parameter if multiple collections share the same field names, and you want to use different options for each field. This will override sortByOptions for that particular collection.
additionalSearchParameters ,
} ) ;
Misalnya, jika Anda memiliki widget sortBy yang dikonfigurasi dengan nilai indexName products/sort/price:asc
, maka kunci di dalam sortByOptions
harus price:asc
.
Tersedia pada typeense-instantsearch-adapter
2.7.1-4
Secara default, ketika group_by
digunakan sebagai parameter pencarian, adaptor meratakan hasil di semua grup ke dalam satu daftar hit berurutan.
Jika Anda ingin mempertahankan grup, Anda ingin menyetel flattenGroupedHits: false
saat membuat instance adaptor.
Ini akan menempatkan pukulan pertama dalam grup sebagai pukulan utama, lalu menambahkan semua pukulan dalam grup di dalam kunci _grouped_hits
di dalam setiap pukulan.
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
flattenGroupedHits : false , // <=======
additionalSearchParameters ,
} ) ;
Tersedia pada typeense-instantsearch-adapter
2.7.0-3
Ide umumnya adalah pertama-tama menghubungkan siklus hidup kueri Instantsearch, mencegat kueri yang diketik dan mengirimkannya ke API penyematan, mengambil penyematan, lalu mengirim vektor ke Typesense untuk melakukan penelusuran vektor tetangga terdekat.
Berikut demo yang dapat Anda jalankan secara lokal untuk melihatnya beraksi: https://github.com/typesense/showcase-hn-comments-semantic-search.
Berikut cara melakukannya di Instantsearch.js:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
additionalSearchParameters ,
} ) ;
// from https://github.com/typesense/showcase-hn-comments-semantic-search/blob/8a33006cae58b425c53f56a64e1273e808cd9375/src/js/index.js#L101
const searchClient = typesenseInstantsearchAdapter . searchClient ;
search = instantsearch ( {
searchClient ,
indexName : INDEX_NAME ,
routing : true ,
async searchFunction ( helper ) {
// This fetches 200 (nearest neighbor) results for semantic / hybrid search
let query = helper . getQuery ( ) . query ;
const page = helper . getPage ( ) ; // Retrieve the current page
if ( query !== "" && [ "semantic" , "hybrid" ] . includes ( $ ( "#search-type-select" ) . val ( ) ) ) {
console . log ( helper . getQuery ( ) . query ) ;
helper
. setQueryParameter (
"typesenseVectorQuery" , // <=== Special parameter that only works in [email protected] and above
`embedding:([], k:200)` ,
)
. setPage ( page )
. search ( ) ;
console . log ( helper . getQuery ( ) . query ) ;
} else {
helper . setQueryParameter ( "typesenseVectorQuery" , null ) . setPage ( page ) . search ( ) ;
}
} ,
} ) ;
Ada dua mode cache:
Caching sisi server:
Untuk mengaktifkan caching sisi server, tambahkan parameter bernama useServerSideSearchCache: true
di blok konfigurasi server
dari adaptor typeense-instantsearch seperti ini:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "..." ,
nearestNode : { ... } ,
nodes : [ ... ] ,
useServerSideSearchCache : true // <<< Add this to send use_cache as a query parameter instead of post body parameter
} ,
additionalSearchParameters : { ... }
} ) ;
Hal ini akan menyebabkan adaptor menambahkan ?use_cache=true
sebagai parameter kueri URL ke semua permintaan pencarian yang dimulai oleh adaptor, yang kemudian akan menyebabkan Server Typesense mengaktifkan cache sisi server untuk permintaan ini.
Caching sisi klien:
Adaptor juga mengaktifkan caching sisi klien secara default, untuk mencegah panggilan jaringan yang tidak perlu ke server. TTL untuk cache sisi klien ini dapat dikonfigurasi seperti ini:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "..." ,
nearestNode : { ... } ,
nodes : [ ... ] ,
cacheSearchResultsForSeconds : 2 * 60 // <<< Add this to configure the TTL for client-side cache in the browser
} ,
additionalSearchParameters : { ... }
} ) ;
Server Ketik | typeense-pencarian instan-adaptor | pencarian instan.js | reaksi-pencarian instan | vue-pencarian instan | pencarian instan sudut |
---|---|---|---|---|---|
>= v0.25.0 | >= v2.7.1 | >= 4,51 | >= 6.39 | >= 4.8 | >= 4.4 |
>= v0.25.0.rc14 | >= v2.7.0-1 | >= 4,51 | >= 6.39 | >= 4.8 | >= 4.4 |
>= v0.25.0.rc12 | >= v2.6.0 | >= 4,51 | >= 6.39 | >= 4.8 | >= 4.4 |
>= v0.24 | >= v2.5.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.21 | >= v2.0.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.19 | >= v1.0.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.15 | >= v0.3.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.14 | >= v0.2.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.13 | >= v0.1.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.12 | >= v0.0.4 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
Jika versi tertentu dari perpustakaan di atas tidak berfungsi dengan adaptor, silakan buka masalah Github dengan detailnya.
Adaptor ini berfungsi dengan semua widget dalam daftar ini
$ npm install
$ npm run typesenseServer
$ FORCE_REINDEX=true npm run indexTestData
$ npm link typesense-instantsearch-adapter
$ npm run testground
$ npm test
Untuk merilis versi baru, kami menggunakan paket np:
$ npm install --global np
$ np
# Follow instructions that np shows you
Jika Anda memiliki pertanyaan atau mengalami masalah apa pun, silakan buat masalah Github dan kami akan berusaha sebaik mungkin untuk membantu.
© 2020-sekarang Typesense, Inc.