♻️ (mistral) Use new ai sdk Mistral core
This commit is contained in:
@ -20,7 +20,7 @@
|
||||
"@typebot.io/variables": "workspace:*",
|
||||
"@udecode/plate-common": "30.4.5",
|
||||
"@typebot.io/logic": "workspace:*",
|
||||
"ai": "3.0.31",
|
||||
"ai": "3.1.12",
|
||||
"chrono-node": "2.7.5",
|
||||
"date-fns": "2.30.0",
|
||||
"date-fns-tz": "2.0.0",
|
||||
@ -30,14 +30,14 @@
|
||||
"libphonenumber-js": "1.10.37",
|
||||
"node-html-parser": "6.1.5",
|
||||
"nodemailer": "6.9.8",
|
||||
"openai": "4.38.3",
|
||||
"openai": "4.47.1",
|
||||
"qs": "6.11.2",
|
||||
"stripe": "12.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typebot.io/forge": "workspace:*",
|
||||
"@typebot.io/forge-repository": "workspace:*",
|
||||
"@types/node": "^20.12.3",
|
||||
"@types/node": "20.4.2",
|
||||
"@types/nodemailer": "6.4.14",
|
||||
"@types/qs": "6.9.7"
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
"resize-observer": "1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.18",
|
||||
"@types/node": "20.4.2",
|
||||
"@types/qs": "6.9.7",
|
||||
"@types/react": "18.2.15",
|
||||
"@types/react-phone-number-input": "3.0.14",
|
||||
@ -29,7 +29,7 @@
|
||||
"autoprefixer": "10.4.13",
|
||||
"@typebot.io/prisma": "workspace:*",
|
||||
"esbuild": "0.17.5",
|
||||
"eslint": "8.32.0",
|
||||
"eslint": "8.44.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"@typebot.io/schemas": "workspace:*",
|
||||
"postcss": "8.4.21",
|
||||
|
@ -12,7 +12,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "29.4.0",
|
||||
"tsup": "6.5.0",
|
||||
"eslint": "8.32.0",
|
||||
"eslint": "8.44.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"jest": "29.4.1",
|
||||
"jest-environment-jsdom": "29.4.1",
|
||||
|
@ -15,6 +15,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.20.6",
|
||||
"ai": "3.0.31"
|
||||
"ai": "3.1.12"
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ export const convertTextToSpeech = createAction({
|
||||
{
|
||||
id: 'fetchVoices',
|
||||
fetch: async ({ credentials }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const response = await got
|
||||
.get(baseUrl + '/v1/voices', {
|
||||
headers: {
|
||||
@ -56,6 +58,8 @@ export const convertTextToSpeech = createAction({
|
||||
{
|
||||
id: 'fetchModels',
|
||||
fetch: async ({ credentials }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const response = await got
|
||||
.get(baseUrl + '/v1/models', {
|
||||
headers: {
|
||||
|
@ -2,9 +2,10 @@ import { option, createAction } from '@typebot.io/forge'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { auth } from '../auth'
|
||||
import { parseMessages } from '../helpers/parseMessages'
|
||||
import { OpenAIStream } from 'ai'
|
||||
// @ts-ignore
|
||||
import MistralClient from '../helpers/client'
|
||||
import { createMistral } from '@ai-sdk/mistral'
|
||||
import { apiBaseUrl } from '../constants'
|
||||
import ky from 'ky'
|
||||
import { generateText, streamText } from 'ai'
|
||||
|
||||
const nativeMessageContentSchema = {
|
||||
content: option.string.layout({
|
||||
@ -98,35 +99,38 @@ export const createChatCompletion = createAction({
|
||||
id: 'fetchModels',
|
||||
dependencies: [],
|
||||
fetch: async ({ credentials }) => {
|
||||
const client = new MistralClient(credentials.apiKey)
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const listModelsResponse: any = await client.listModels()
|
||||
const { data } = await ky
|
||||
.get(apiBaseUrl + '/v1/models', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${credentials.apiKey}`,
|
||||
},
|
||||
})
|
||||
.json<{ data: { id: string }[] }>()
|
||||
|
||||
return (
|
||||
listModelsResponse.data
|
||||
.sort(
|
||||
(a: { created: number }, b: { created: number }) =>
|
||||
b.created - a.created
|
||||
)
|
||||
.map((model: { id: any }) => model.id) ?? []
|
||||
)
|
||||
return data.map((model) => model.id)
|
||||
},
|
||||
},
|
||||
],
|
||||
run: {
|
||||
server: async ({ credentials: { apiKey }, options, variables, logs }) => {
|
||||
if (!options.model) return logs.add('No model selected')
|
||||
const client = new MistralClient(apiKey)
|
||||
|
||||
const response: any = await client.chat({
|
||||
model: options.model,
|
||||
const model = createMistral({
|
||||
apiKey,
|
||||
})(options.model)
|
||||
|
||||
const { text } = await generateText({
|
||||
model,
|
||||
messages: parseMessages({ options, variables }),
|
||||
tools: {},
|
||||
})
|
||||
|
||||
options.responseMapping?.forEach((mapping) => {
|
||||
if (!mapping.variableId) return
|
||||
if (!mapping.item || mapping.item === 'Message content')
|
||||
variables.set(mapping.variableId, response.choices[0].message.content)
|
||||
variables.set(mapping.variableId, text)
|
||||
})
|
||||
},
|
||||
stream: {
|
||||
@ -136,14 +140,16 @@ export const createChatCompletion = createAction({
|
||||
)?.variableId,
|
||||
run: async ({ credentials: { apiKey }, options, variables }) => {
|
||||
if (!options.model) return
|
||||
const client = new MistralClient(apiKey)
|
||||
const model = createMistral({
|
||||
apiKey,
|
||||
})(options.model)
|
||||
|
||||
const response: any = client.chatStream({
|
||||
model: options.model,
|
||||
const response = await streamText({
|
||||
model,
|
||||
messages: parseMessages({ options, variables }),
|
||||
})
|
||||
|
||||
return OpenAIStream(response)
|
||||
return response.toAIStream()
|
||||
},
|
||||
},
|
||||
},
|
||||
|
1
packages/forge/blocks/mistral/constants.ts
Normal file
1
packages/forge/blocks/mistral/constants.ts
Normal file
@ -0,0 +1 @@
|
||||
export const apiBaseUrl = 'https://api.mistral.ai'
|
@ -1,341 +0,0 @@
|
||||
// Taken from https://github.com/mistralai/client-js/blob/main/src/client.js
|
||||
// Lib seems not actively maintained, and we need this patch: https://github.com/mistralai/client-js/pull/42
|
||||
|
||||
let isNode = false
|
||||
|
||||
let fetch
|
||||
|
||||
const VERSION = '0.0.3'
|
||||
const RETRY_STATUS_CODES = [429, 500, 502, 503, 504]
|
||||
const ENDPOINT = 'https://api.mistral.ai'
|
||||
|
||||
/**
|
||||
* Initialize fetch
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function initializeFetch() {
|
||||
if (typeof globalThis.fetch === 'undefined')
|
||||
throw new Error('No fetch implementation found')
|
||||
if (typeof window === 'undefined') {
|
||||
isNode = true
|
||||
}
|
||||
fetch = globalThis.fetch
|
||||
}
|
||||
|
||||
initializeFetch()
|
||||
|
||||
/**
|
||||
* MistralAPIError
|
||||
* @return {MistralAPIError}
|
||||
* @extends {Error}
|
||||
*/
|
||||
class MistralAPIError extends Error {
|
||||
/**
|
||||
* A simple error class for Mistral API errors
|
||||
* @param {*} message
|
||||
*/
|
||||
constructor(message) {
|
||||
super(message)
|
||||
this.name = 'MistralAPIError'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MistralClient
|
||||
* @return {MistralClient}
|
||||
*/
|
||||
class MistralClient {
|
||||
/**
|
||||
* A simple and lightweight client for the Mistral API
|
||||
* @param {*} apiKey can be set as an environment variable MISTRAL_API_KEY,
|
||||
* or provided in this parameter
|
||||
* @param {*} endpoint defaults to https://api.mistral.ai
|
||||
* @param {*} maxRetries defaults to 5
|
||||
* @param {*} timeout defaults to 120 seconds
|
||||
*/
|
||||
constructor(
|
||||
apiKey = process.env.MISTRAL_API_KEY,
|
||||
endpoint = ENDPOINT,
|
||||
maxRetries = 5,
|
||||
timeout = 120
|
||||
) {
|
||||
this.endpoint = endpoint
|
||||
this.apiKey = apiKey
|
||||
|
||||
this.maxRetries = maxRetries
|
||||
this.timeout = timeout
|
||||
|
||||
if (this.endpoint.indexOf('inference.azure.com')) {
|
||||
this.modelDefault = 'mistral'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} method
|
||||
* @param {*} path
|
||||
* @param {*} request
|
||||
* @return {Promise<*>}
|
||||
*/
|
||||
_request = async function (method, path, request) {
|
||||
const url = `${this.endpoint}/${path}`
|
||||
const options = {
|
||||
method: method,
|
||||
headers: {
|
||||
'User-Agent': `mistral-client-js/${VERSION}`,
|
||||
Accept: request?.stream ? 'text/event-stream' : 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
},
|
||||
body: method !== 'get' ? JSON.stringify(request) : null,
|
||||
timeout: this.timeout * 1000,
|
||||
}
|
||||
|
||||
for (let attempts = 0; attempts < this.maxRetries; attempts++) {
|
||||
try {
|
||||
const response = await fetch(url, options)
|
||||
|
||||
if (response.ok) {
|
||||
if (request?.stream) {
|
||||
if (isNode) {
|
||||
return response.body
|
||||
} else {
|
||||
const reader = response.body.getReader()
|
||||
// Chrome does not support async iterators yet, so polyfill it
|
||||
const asyncIterator = async function* () {
|
||||
try {
|
||||
while (true) {
|
||||
// Read from the stream
|
||||
const { done, value } = await reader.read()
|
||||
// Exit if we're done
|
||||
if (done) return
|
||||
// Else yield the chunk
|
||||
yield value
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock()
|
||||
}
|
||||
}
|
||||
|
||||
return asyncIterator()
|
||||
}
|
||||
}
|
||||
return await response.json()
|
||||
} else if (RETRY_STATUS_CODES.includes(response.status)) {
|
||||
console.debug(
|
||||
`Retrying request on response status: ${response.status}`,
|
||||
`Response: ${await response.text()}`,
|
||||
`Attempt: ${attempts + 1}`
|
||||
)
|
||||
// eslint-disable-next-line max-len
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.pow(2, attempts + 1) * 500)
|
||||
)
|
||||
} else {
|
||||
throw new MistralAPIError(
|
||||
`HTTP error! status: ${response.status} ` +
|
||||
`Response: \n${await response.text()}`
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Request failed: ${error.message}`)
|
||||
if (error.name === 'MistralAPIError') {
|
||||
throw error
|
||||
}
|
||||
if (attempts === this.maxRetries - 1) throw error
|
||||
// eslint-disable-next-line max-len
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.pow(2, attempts + 1) * 500)
|
||||
)
|
||||
}
|
||||
}
|
||||
throw new Error('Max retries reached')
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chat completion request
|
||||
* @param {*} model
|
||||
* @param {*} messages
|
||||
* @param {*} tools
|
||||
* @param {*} temperature
|
||||
* @param {*} maxTokens
|
||||
* @param {*} topP
|
||||
* @param {*} randomSeed
|
||||
* @param {*} stream
|
||||
* @param {*} safeMode deprecated use safePrompt instead
|
||||
* @param {*} safePrompt
|
||||
* @param {*} toolChoice
|
||||
* @param {*} responseFormat
|
||||
* @return {Promise<Object>}
|
||||
*/
|
||||
_makeChatCompletionRequest = function (
|
||||
model,
|
||||
messages,
|
||||
tools,
|
||||
temperature,
|
||||
maxTokens,
|
||||
topP,
|
||||
randomSeed,
|
||||
stream,
|
||||
safeMode,
|
||||
safePrompt,
|
||||
toolChoice,
|
||||
responseFormat
|
||||
) {
|
||||
// if modelDefault and model are undefined, throw an error
|
||||
if (!model && !this.modelDefault) {
|
||||
throw new MistralAPIError('You must provide a model name')
|
||||
}
|
||||
return {
|
||||
model: model ?? this.modelDefault,
|
||||
messages: messages,
|
||||
tools: tools ?? undefined,
|
||||
temperature: temperature ?? undefined,
|
||||
max_tokens: maxTokens ?? undefined,
|
||||
top_p: topP ?? undefined,
|
||||
random_seed: randomSeed ?? undefined,
|
||||
stream: stream ?? undefined,
|
||||
safe_prompt: (safeMode || safePrompt) ?? undefined,
|
||||
tool_choice: toolChoice ?? undefined,
|
||||
response_format: responseFormat ?? undefined,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the available models
|
||||
* @return {Promise<Object>}
|
||||
*/
|
||||
listModels = async function () {
|
||||
const response = await this._request('get', 'v1/models')
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* A chat endpoint without streaming
|
||||
* @param {*} model the name of the model to chat with, e.g. mistral-tiny
|
||||
* @param {*} messages an array of messages to chat with, e.g.
|
||||
* [{role: 'user', content: 'What is the best French cheese?'}]
|
||||
* @param {*} tools a list of tools to use.
|
||||
* @param {*} temperature the temperature to use for sampling, e.g. 0.5
|
||||
* @param {*} maxTokens the maximum number of tokens to generate, e.g. 100
|
||||
* @param {*} topP the cumulative probability of tokens to generate, e.g. 0.9
|
||||
* @param {*} randomSeed the random seed to use for sampling, e.g. 42
|
||||
* @param {*} safeMode deprecated use safePrompt instead
|
||||
* @param {*} safePrompt whether to use safe mode, e.g. true
|
||||
* @param {*} toolChoice the tool to use, e.g. 'auto'
|
||||
* @param {*} responseFormat the format of the response, e.g. 'json_format'
|
||||
* @return {Promise<Object>}
|
||||
*/
|
||||
chat = async function ({
|
||||
model,
|
||||
messages,
|
||||
tools,
|
||||
temperature,
|
||||
maxTokens,
|
||||
topP,
|
||||
randomSeed,
|
||||
safeMode,
|
||||
safePrompt,
|
||||
toolChoice,
|
||||
responseFormat,
|
||||
}) {
|
||||
const request = this._makeChatCompletionRequest(
|
||||
model,
|
||||
messages,
|
||||
tools,
|
||||
temperature,
|
||||
maxTokens,
|
||||
topP,
|
||||
randomSeed,
|
||||
false,
|
||||
safeMode,
|
||||
safePrompt,
|
||||
toolChoice,
|
||||
responseFormat
|
||||
)
|
||||
const response = await this._request('post', 'v1/chat/completions', request)
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* A chat endpoint that streams responses.
|
||||
* @param {*} model the name of the model to chat with, e.g. mistral-tiny
|
||||
* @param {*} messages an array of messages to chat with, e.g.
|
||||
* [{role: 'user', content: 'What is the best French cheese?'}]
|
||||
* @param {*} tools a list of tools to use.
|
||||
* @param {*} temperature the temperature to use for sampling, e.g. 0.5
|
||||
* @param {*} maxTokens the maximum number of tokens to generate, e.g. 100
|
||||
* @param {*} topP the cumulative probability of tokens to generate, e.g. 0.9
|
||||
* @param {*} randomSeed the random seed to use for sampling, e.g. 42
|
||||
* @param {*} safeMode deprecated use safePrompt instead
|
||||
* @param {*} safePrompt whether to use safe mode, e.g. true
|
||||
* @param {*} toolChoice the tool to use, e.g. 'auto'
|
||||
* @param {*} responseFormat the format of the response, e.g. 'json_format'
|
||||
* @return {Promise<Object>}
|
||||
*/
|
||||
chatStream = async function* ({
|
||||
model,
|
||||
messages,
|
||||
tools,
|
||||
temperature,
|
||||
maxTokens,
|
||||
topP,
|
||||
randomSeed,
|
||||
safeMode,
|
||||
safePrompt,
|
||||
toolChoice,
|
||||
responseFormat,
|
||||
}) {
|
||||
const request = this._makeChatCompletionRequest(
|
||||
model,
|
||||
messages,
|
||||
tools,
|
||||
temperature,
|
||||
maxTokens,
|
||||
topP,
|
||||
randomSeed,
|
||||
true,
|
||||
safeMode,
|
||||
safePrompt,
|
||||
toolChoice,
|
||||
responseFormat
|
||||
)
|
||||
const response = await this._request('post', 'v1/chat/completions', request)
|
||||
|
||||
let buffer = ''
|
||||
const decoder = new TextDecoder()
|
||||
for await (const chunk of response) {
|
||||
buffer += decoder.decode(chunk, { stream: true })
|
||||
let firstNewline
|
||||
while ((firstNewline = buffer.indexOf('\n')) !== -1) {
|
||||
const chunkLine = buffer.substring(0, firstNewline)
|
||||
buffer = buffer.substring(firstNewline + 1)
|
||||
if (chunkLine.startsWith('data:')) {
|
||||
const json = chunkLine.substring(6).trim()
|
||||
if (json !== '[DONE]') {
|
||||
yield JSON.parse(json)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An embeddings endpoint that returns embeddings for a single,
|
||||
* or batch of inputs
|
||||
* @param {*} model The embedding model to use, e.g. mistral-embed
|
||||
* @param {*} input The input to embed,
|
||||
* e.g. ['What is the best French cheese?']
|
||||
* @return {Promise<Object>}
|
||||
*/
|
||||
embeddings = async function ({ model, input }) {
|
||||
const request = {
|
||||
model: model,
|
||||
input: input,
|
||||
}
|
||||
const response = await this._request('post', 'v1/embeddings', request)
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
export default MistralClient
|
@ -2,6 +2,7 @@ import { options as createChatCompletionOption } from '../actions/createChatComp
|
||||
import { VariableStore } from '@typebot.io/forge'
|
||||
import { isDefined, isNotEmpty } from '@typebot.io/lib'
|
||||
import { z } from '@typebot.io/forge/zod'
|
||||
import { CoreMessage } from 'ai'
|
||||
|
||||
export const parseMessages = ({
|
||||
options: { messages },
|
||||
@ -11,7 +12,7 @@ export const parseMessages = ({
|
||||
variables: VariableStore
|
||||
}) =>
|
||||
messages
|
||||
?.flatMap((message) => {
|
||||
?.flatMap<CoreMessage | undefined>((message) => {
|
||||
if (!message.role) return
|
||||
|
||||
if (message.role === 'Dialogue') {
|
||||
|
@ -9,11 +9,13 @@
|
||||
"@typebot.io/forge": "workspace:*",
|
||||
"@typebot.io/lib": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@types/node": "^20.12.4",
|
||||
"@types/node": "20.4.2",
|
||||
"@types/react": "18.2.15",
|
||||
"typescript": "5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "3.0.31"
|
||||
"@ai-sdk/mistral": "0.0.11",
|
||||
"ai": "3.1.12",
|
||||
"ky": "1.2.4"
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ export const askAssistant = createAction({
|
||||
{
|
||||
id: 'fetchAssistants',
|
||||
fetch: async ({ options, credentials }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const config = {
|
||||
apiKey: credentials.apiKey,
|
||||
baseURL: options.baseUrl,
|
||||
@ -100,7 +102,8 @@ export const askAssistant = createAction({
|
||||
{
|
||||
id: 'fetchAssistantFunctions',
|
||||
fetch: async ({ options, credentials }) => {
|
||||
if (!options.assistantId) return []
|
||||
if (!options.assistantId || !credentials?.apiKey) return []
|
||||
|
||||
const config = {
|
||||
apiKey: credentials.apiKey,
|
||||
baseURL: options.baseUrl,
|
||||
|
@ -46,6 +46,8 @@ export const createChatCompletion = createAction({
|
||||
id: 'fetchModels',
|
||||
dependencies: ['baseUrl', 'apiVersion'],
|
||||
fetch: async ({ credentials, options }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const baseUrl = options?.baseUrl ?? defaultOpenAIOptions.baseUrl
|
||||
const config = {
|
||||
apiKey: credentials.apiKey,
|
||||
|
@ -37,6 +37,8 @@ export const createSpeech = createAction({
|
||||
id: 'fetchSpeechModels',
|
||||
dependencies: ['baseUrl', 'apiVersion'],
|
||||
fetch: async ({ credentials, options }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const baseUrl = options?.baseUrl ?? defaultOpenAIOptions.baseUrl
|
||||
const config = {
|
||||
apiKey: credentials.apiKey,
|
||||
|
@ -7,8 +7,8 @@
|
||||
"author": "Baptiste Arnaud",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"ai": "3.0.31",
|
||||
"openai": "4.38.3"
|
||||
"ai": "3.1.12",
|
||||
"openai": "4.47.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typebot.io/forge": "workspace:*",
|
||||
|
@ -16,13 +16,15 @@ export const zemanticAiBlock = createBlock({
|
||||
{
|
||||
id: 'fetchProjects',
|
||||
dependencies: [],
|
||||
fetch: async ({ credentials: { apiKey } }) => {
|
||||
fetch: async ({ credentials }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const url = 'https://api.zemantic.ai/v1/projects'
|
||||
|
||||
const response = await ky
|
||||
.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
Authorization: `Bearer ${credentials.apiKey}`,
|
||||
},
|
||||
})
|
||||
.json()
|
||||
|
@ -12,7 +12,7 @@
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "^0.7.0",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@types/node": "^20.10.1",
|
||||
"@types/node": "20.4.2",
|
||||
"tsx": "^4.6.1",
|
||||
"prettier": "3.0.0"
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ export type FetcherDefinition<A extends AuthDefinition, T = {}> = {
|
||||
*/
|
||||
dependencies: (keyof T)[]
|
||||
fetch: (params: {
|
||||
credentials: CredentialsFromAuthDef<A>
|
||||
credentials: CredentialsFromAuthDef<A> | undefined
|
||||
options: T
|
||||
}) => Promise<(string | { label: string; value: string })[]>
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
"@typebot.io/prisma": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@types/escape-html": "^1.0.4",
|
||||
"@types/nodemailer": "6.4.8",
|
||||
"@types/nodemailer": "6.4.14",
|
||||
"@types/validator": "13.11.9",
|
||||
"next": "14.1.0",
|
||||
"nodemailer": "6.9.8",
|
||||
|
@ -13,7 +13,7 @@
|
||||
"@typebot.io/schemas": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.26",
|
||||
"@types/node": "20.4.2",
|
||||
"@typebot.io/tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.4.2",
|
||||
"dotenv-cli": "7.2.1",
|
||||
"dotenv-cli": "7.4.1",
|
||||
"prisma": "5.12.1",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"tsx": "3.12.7",
|
||||
|
@ -14,6 +14,6 @@
|
||||
"@typebot.io/env": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv-cli": "7.2.1"
|
||||
"dotenv-cli": "7.4.1"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user