Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@singlestore/client
Advanced tools
The SingleStore Client is a package designed for interacting with the SingleStore API in Node.js environments.
The SingleStore Client is a package designed for interacting with the SingleStore API in Node.js environments.
npm install @singlestore/client
The SingleStoreClient can be initialized in multiple ways, depending on your needs. Below are examples of how to initialize the client in various scenarios.
Use this method if you don’t need Management API access or AI integration.
import { SingleStoreClient } from "@singlestore/client";
const client = new SingleStoreClient();
This method is used when you need to access SingleStore's management API.
import { SingleStoreClient } from "@singlestore/client";
const client = new SingleStoreClient({ apiKey: "<SINGLESTORE_API_KEY>" });
If you want to integrate AI features, use this method. You need to pass an AI instance with the required API key.
npm install @singlestore/ai
import { AI } from "@singlestore/ai";
import { SingleStoreClient } from "@singlestore/client";
const ai = new AI({ openAIApiKey: "<OPENAI_API_KEY>" });
const client = new SingleStoreClient({ ai });
@singlestore/ai
package documentation.Returns the current organization if an API key was provided during initialization.
const organization = await client.organization.get();
const workspaceGroups = await client.workspaceGroup.get();
const workspaceGroup = await client.workspaceGroup.get({
where: { id: "<WORKSPACE_GROUP_ID>" },
});
const workspaceGroup = await client.workspaceGroup.get({
where: { name: "<WORKSPACE_GROUP_NAME>" },
});
includeTerminated: true
parameter to the workspaceGroup.get
options object.select: ['<FIELD_NAME_TO_SELECT>']
parameter to the workspaceGroup.get
options object.const { workspaceGroup, adminPassword } = await client.workspaceGroup.create({
name: "<WORKSPACE_GROUP_NAME>",
regionName: "US West 2 (Oregon)",
adminPassword: "<WORKSPACE_GROUP_PASSWORD>",
allowAllTraffic: false,
firewallRanges: ["IP_ADDRESS"],
dataBucketKMSKeyID: "<ID>",
backupBucketKMSKeyID: "<ID>",
updateWindow: { day: "mo", hour: 12 },
expiresAt: new Date("2025-01-01"),
});
name
and regionName
fields are required to create a workspace group. All other fields are optional.adminPassword
value is not provided, a generated password is returned.regionName
values, refer to this link.You can update a workspace group by specifying the workspace group ID or by calling the update
method on a selected Workspace Group instance.
await client.workspaceGroup.update("<WORKSPACE_GROUP_ID>", {
name: "<NEW_WORKSPACE_GROUP_NAME>",
adminPassword: "<NEW_WORKSPACE_GROUP_PASSWORD>",
allowAllTraffic: true,
firewallRanges: ["<NEW_IP_ADDRESS>"],
updateWindow: { day: "mo", hour: 12 },
expiresAt: new Date("2025-01-01"),
});
Updates the currently selected workspace group.
await workspaceGroup.update({
name: "<NEW_WORKSPACE_GROUP_NAME>",
adminPassword: "<NEW_WORKSPACE_GROUP_PASSWORD>",
allowAllTraffic: true,
firewallRanges: ["<NEW_IP_ADDRESS>"],
updateWindow: { day: "mo", hour: 12 },
expiresAt: new Date("2025-01-01"),
});
You can delete a workspace group by specifying the workspace group ID or by calling the delete
method on a selected Workspace Group instance.
await client.workspaceGroup.delete("<WORKSPACE_GROUP_ID>", false);
Deletes the currently selected workspace group.
await workspaceGroup.delete(false);
force
argument to true
.const metrics = await workspaceGroup.getMetrics();
const privateConnections = await workspaceGroup.getPrivateConnections();
const connection = client.connect({
host: "<WORKSPACE_HOST>",
user: "<WORKSPACE_USER>",
password: "<WORKSPACE_PASSWORD>",
port: <WORKSPACE_PORT>
});
const workspace = await workspaceGroup.workspace.get({
where: { id: "<WORKSPACE_ID>" },
});
if (workspace) {
const connection = workspace.connect({
user: "<WORKSPACE_USER>",
password: "<WORKSPACE_PASSWORD>",
port: <WORKSPACE_PORT>,
});
}
To connect to a free tier workspace, download the SSL certificate from this link, set the port
and database
, and place the SSL certificate in the root directory of your project.
const connection = client.connect({
host: "<WORKSPACE_HOST>",
user: "<WORKSPACE_USER>",
password: "<WORKSPACE_PASSWORD>",
port: <WORKSPACE_PORT>
database: "<DATABASE_NAME>",
ssl: { ca: readFileSync(resolve(process.cwd(), "singlestore_bundle.pem")) },
});
const workspace = await workspaceGroup.workspace.get();
const workspace = await workspaceGroup.workspace.get({
where: { id: "<WORKSPACE_ID>" },
});
const workspace = await workspaceGroup.workspace.get({
where: { name: "<WORKSPACE_NAME>" },
});
includeTerminated: true
parameter to the workspaceGroup.workspace.get
options object.select: ['<FIELD_NAME_TO_SELECT>']
parameter to the workspaceGroup.workspace.get
options object.const workspace = await workspaceGroup.workspace.create({
name: "WORKSPACE_NAME",
size: "S-00",
enableKai: true,
cacheConfig: 1,
scaleFactor: 1,
autoSuspend: {
suspendType: "SCHEDULED",
suspendAfterSeconds: 1200,
},
});
name
field is required to create a workspace. All other fields are optional.size
values, refer to the SingleStore Helios Pricing page.await workspaceGroup.workspace.update("<WORKSPACE_ID>", {
size: "S-00",
enableKai: true,
cacheConfig: 1,
scaleFactor: 1,
deploymentType: "PRODUCTION",
autoSuspend: {
suspendType: "SCHEDULED",
suspendAfterSeconds: 1200,
},
});
await workspace.update({
size: "S-00",
enableKai: true,
cacheConfig: 1,
scaleFactor: 1,
deploymentType: "PRODUCTION",
autoSuspend: {
suspendType: "SCHEDULED",
suspendAfterSeconds: 1200,
},
});
await workspaceGroup.workspace.delete("<WORKSPACE_ID>");
await workspace.delete();
const state = await workspaceGroup.workspace.getState("<WORKSPACE_ID>");
const state = await workspace.getState();
await workspaceGroup.workspace.resume("<WORKSPACE_ID>", { disableAutoSuspend: false });
await workspace.resume({ disableAutoSuspend: false });
disableAutoSuspend
parameter is optional.await workspaceGroup.workspace.suspend("<WORKSPACE_ID>");
await workspace.suspend();
The use
method allows you to interact with a specific database within the connection. You can optionally provide a generic DatabaseSchema
to describe the database schema and its tables.
interface DatabaseSchema extends DatabaseType {
name: "<DATABASE_NAME>";
tables: {
users: {
id: number;
};
};
}
const database = connection.database.use<DatabaseSchema>("<DATABASE_NAME>");
The create
method allows you to create a database within the connection. You can optionally provide a generic DatabaseSchema
to describe the database schema and its tables.
interface DatabaseSchema extends DatabaseType {
name: "<DATABASE_NAME>";
tables: {
users: {
id: number;
};
};
}
const database = await connection.database.create<DatabaseSchema>({
name: "<DATABASE_NAME>",
tables: {
users: {
columns: {
id: {
type: "BIGINT",
autoIncrement: true, // Optional
primaryKey: true, // Optional
nullable: false, // Optional
default: 0, // Optional
clauses: ["<CUSTOM_CLAUSE>"], // Optional
},
},
clauses: ["<CUSTOM_CLAUSE>"], // Optional
fulltextKeys: ["<COLUMN_NAME>"], // Optional
primaryKeys: ["<COLUMN_NAME>"], // Optional
},
},
});
await connection.database.drop("<DATABASE_NAME>");
await database.drop();
The query
method allows you to execute a MySQL query on the database and retrieve the result. The query result is returned as an array of rows, where each row is represented as an object with column names as keys and the corresponding values.
type RowType = { [K: string]: any }[];
const [rows] = await database.query<RowType>("<MYSQL_QUERY>");
RowType
is a flexible type that can accommodate various column structures in the query result.const info = await database.describe();
The showInfo
method allows you to retrieve information about the database. You can optionally request extended information by setting the isExtended
argument to true
.
const info = await database.showInfo(true);
The showTablesInfo
method allows you to retrieve information about the database tables. You can optionally request extended information by setting the isExtended
argument to true
.
const tablesInfo = await database.showTablesInfo(true);
The use
method allows you to access a specific table within the database. It optionally accepts a table name and schema, providing an interface to interact with the table for querying and manipulation.
type TableName = "<TABLE_NAME>";
type TableSchema = { [K: string]: any };
const table = database.table.use<TableName, TableSchema>("<TABLE_NAME>");
The create
method allows you to create a new table in the database. You can define the table name and schema, specifying columns and their properties such as data types, constraints, and default values.
type TableName = "<TABLE_NAME>";
type TableSchema = { id: number };
const table = await database.table.create<TableName, TableSchema>({
name: "<TABLE_NAME>",
columns: {
id: {
type: "BIGINT",
autoIncrement: true, // Optional
primaryKey: true, // Optional
nullable: false, // Optional
default: 0, // Optional
clauses: ["<CUSTOM_CLAUSE>"], // Optional
},
},
});
await database.table.drop("<TABLE_NAME>");
await table.drop();
await database.table.truncate("<TABLE_NAME>");
await table.truncate();
await database.table.rename("<TABLE_NAME>", "<TABLE_NEW_NAME>");
await table.rename("<TABLE_NEW_NAME>");
The showInfo
method allows you to retrieve information about the table. You can optionally request extended information by setting the isExtended
argument to true
.
const tableInfo = await table.showInfo(true);
The showInfo
method allows you to retrieve information about the table columns.
const tableColumnsInfo = await table.showColumnsInfo();
The insert
method allows you to insert data into a table. You can insert a single value or multiple values at once by providing an object or an array of objects that map column names to values.
await table.insert({columnName: <VALUE>})
await table.insert([{columnName: <VALUE>}, {columnName: <VALUE_2>}])
The find
method allows you to retrieve values from a table, with optional support for conditions, joins, grouping, ordering, and pagination. You can either fetch all values from a table or apply conditions to narrow down th
Retrieves all values from the table without any conditions.
const values = await table.find();
Retrieves values from the table based on the specified conditions. You can customize the query with select, join, where, groupBy, orderBy, limit, and offset options.
const values = await table.find({
select: ["<COLUMN_NAME>", "COUNT(*) AS count"], // Optional
join: [
{
type: "FULL", // Supported values: "INNER" | "LEFT" | "RIGHT" | "FULL"
table: "<JOIN_TABLE_NAME>",
as: "<JOIN_TABLE_AS>",
on: [
"<COLUMN_NAME>",
"=", // Supported values: "=" | "<" | ">" | "<=" | ">=" | "!="
"<JOIN_COLUMN_NAME>",
],
},
], // Optional
where: { columnName: "<COLUMN_VALUE>" }, // Optional
groupBy: ["<COLUMN_NAME>"], // Optional
orderBy: {
columnName: "asc", // Supported values: "asc" | "desc"
}, // Optional
limit: 10, // Optional
offset: 10, // Optional
});
COUNT(*) AS count
pattern follows the clause AS alias
structure, where COUNT(*)
is the clause
and count
is the alias
.The update
method allows you to modify existing values in the table. You provide the new values to update, along with a condition to specify which rows should be updated.
await table.update(
{ columnName: "<NEW_COLUMN_VALUE>" }, // New value
{ columnName: "<COLUMN_VALUE>" }, // Where condition
);
The delete
method allows you to remove rows from the table that match a specified condition.
await table.delete({ columnName: "<COLUMN_VALUE>" });
delete
method, especially if the where condition is broad, as it could result in the removal of multiple rows.The vectorSearch
method allows you to perform searches using vector-based embeddings in a specified column. This is particularly useful for tasks such as semantic search, where results are based on the similarity of vector representations of text or data.
Performs a vector search based on a prompt, returning rows from the table that match the vector similarity.
const rows = await table.vectorSearch({
prompt: "<PROMPT>",
vectorColumn: "<VECTOR_COLUMN_NAME>",
embeddingParams: {
model: "<MODEL_NAME>", // Optional
dimensions: "<VECTOR_DIMENSTION>", // Optional
}, // Optional
});
Performs a vector search with additional conditions such as selected columns, joins, filtering, grouping, ordering, and pagination.
const rows = await table.vectorSearch(
{
prompt: "<PROMPT>",
vectorColumn: "<VECTOR_COLUMN_NAME>",
embeddingParams: {
model: "<MODEL_NAME>", // Optional
dimensions: "<VECTOR_DIMENSTION>", // Optional
},
}, // Optional
{
select: ["<COLUMN_NAME>"], // Optional
join: [
{
type: "FULL", // Supported values: "INNER" | "LEFT" | "RIGHT" | "FULL"
table: "<JOIN_TABLE_NAME>",
as: "<JOIN_TABLE_AS>",
on: [
"<COLUMN_NAME>",
"=", // Supported values: "=" | "<" | ">" | "<=" | ">=" | "!="
"<JOIN_COLUMN_NAME>",
],
},
], // Optional
where: { columnName: "<COLUMN_VALUE>" }, // Optional
groupBy: ["<COLUMN_NAME>"], // Optional
orderBy: {
columnName: "asc", // Supported values: "asc" | "desc"
}, // Optional
limit: 10, // Optional
offset: 10, // Optional
}, // Optional
);
vectorSearch
method returns both the table rows and a v_score
field, which reflects the similarity score of each row to the search prompt.select
, join
, where
, and others can be used to refine the results further, similar to standard SQL queries.The createChatCompletion
method allows you to generate chat completions based on a vector search within a table. Depending on the stream
option, you can retrieve the results either as a complete string or in a streamed fashion, with optional custom tools for enhancing functionality.
Performs a chat completion based on a vector search and returns the result as a complete string.
const chatCompletion = await table.createChatCompletion(
{
model: "<MODEL_NAME>", // Optional
prompt: "<PROMPT>",
systemRole: "<SYSTEM_ROLE>", // Optional
vectorColumn: "<VECTOR_COLUMN_NAME>",
stream: false,
temperature: 0, // Optional
embeddingParams: {
model: "<MODEL_NAME>", // Optional
dimensions: "<VECTOR_DIMENSTION>", // Optional
}, // Optional
},
{
select: ["<COLUMN_NAME>"], // Optional
where: { columnName: "<COLUMN_VALUE>" }, // Optional
limit: 1, // Optional
}, // Optional
);
Performs a chat completion and returns the result as a stream of data chunks.
const stream = await table.createChatCompletion(
{
stream: true,
...
},
);
const chatCompletion = await ai.chatCompletions.handleStream(stream, (chunk) => {
console.log(chunk);
});
You can also integrate custom tools to extend the functionality of the chat completion.
import { ChatCompletionTool } from "@singlestore/ai/chat-completions";
import { z } from "zod";
const customTool = new ChatCompletionTool({
name: "<TOOL_NAME>",
description: "<TOOL_DESCRIPTION>",
params: z.object({ paramName: z.string().describe("<PARAM_DESCRIPTION>") }),
call: async (params) => {
const value = await anyFnCall(params);
return { name: "<TOOL_NAME>", params, value: JSON.stringify(value) };
},
});
await table.createChatCompletion({
tools: [customTool],
...
});
createChatCompletion
method accepts the same options as the second argument of the vectorSearch
method, such as select
, where
, and limit
.stream: true
, the handleStream
function is used to process the stream. It accepts a callback as the second argument, which handles each new chunk of data as it arrives.const column = table.column.use("<COLUMN_NAME>");
const column = await table.column.add({
name: "<NEW_COLUMN_NAME>",
type: "BIGINT",
autoIncrement: false, // Optional
primaryKey: false, // Optional
nullable: true, // Optional
default: 0, // Optional
clauses: ["<CUSTOM_CLAUSE>"], // Optional
});
await table.column.modify("<COLUMN_NAME>", {
type: "BIGINT",
autoIncrement: false, // Optional
primaryKey: false, // Optional
nullable: true, // Optional
default: 0, // Optional
clauses: ["<CUSTOM_CLAUSE>"], // Optional
});
await column.modify(...)
await table.column.rename("<COLUMN_NAME>", "<NEW_COLUMN_NAME>");
await column.modify("<NEW_COLUMN_NAME>");
await table.column.drop("<COLUMN_NAME>");
await column.drop();
await table.column.showInfo("<COLUMN_NAME>");
await column.showInfo();
const billing = await client.billing.get({
metric: "ComputeCredit", // Supported values: "ComputeCredit" | "StorageAvgByte"
startTime: new Date("2024-01-01"),
endTime: new Date("2024-01-09"),
aggregateBy: "month", // Supported values: "hour", "day", "month"; Optional
});
const regions = await client.region.get();
const region = await client.region.get({ id: "<REGION_ID>" });
const region = await client.region.get({ name: "<REGION_NAME>" });
const teams = await client.team.get();
const team = await client.team.get({ id: "<TEAM_ID>" });
const team = await client.team.get({ name: "<TEAM_NAME>" });
const team = await client.team.get({ description: "<TEAM_DESCRIPTION>" });
const team = await client.team.create({
name: "<TEAM_NAME>",
description: "<TEAM_DESCRIPTION>", // Optional
memberTeams: ["<TEAM_ID>"], // Optional
memberUsers: ["<USER_ID>"], // Optional
});
await client.team.update("<TEAM_ID>", {
name: "<NEW_TEAM_NAME>", // Optional
description: "<NEW_TEAM_DESCRIPTION>", // Optional
});
await team.update(...);
await client.team.delete("<TEAM_ID>");
await team.delete();
await client.team.addMemberTeams("<TEAM_ID>", ["<ADD_TEAM_ID>"]);
await team.addMemberTeams(["<ADD_TEAM_ID>"]);
await client.team.addMemberUsers("<TEAM_ID>", ["<ADD_USER_ID>"]);
await team.addMemberUsers(["<ADD_USER_ID>"]);
await client.team.removeMemberTeams("<TEAM_ID>", ["<REMOVE_TEAM_ID>"]);
await team.removeMemberTeams(["<REMOVE_TEAM_ID>"]);
await client.team.removeMemberUsers("<TEAM_ID>", ["<REMOVE_USER_ID>"]);
await team.removeMemberUsers(["<REMOVE_USER_ID>"]);
const job = client.job.get("<JOB_ID>");
const job = await client.job.create({
name: "<JOB_NAME>", // Optional
description: "<JOB_DESCRIPTION>", // Optional
executionConfig: {
notebookPath: "<NOTEBOOK_NAME.ipynb>",
createSnapshot: true,
runtimeName: "notebooks-cpu-small",
},
schedule: {
mode: "Recurring", // Supported values: "Once" | "Recurring"
executionIntervalInMinutes: 60,
startAt: new Date("2025-01-01"),
},
targetConfig: {
databaseName: "<DATABASE_NAME>",
resumeTarget: true,
targetID: "<TARGET_ID>",
targetType: "Workspace", // Supported values: "Workspace" | "Cluster" | "VirtualWorkspace"
}, // Optional
});
await client.job.delete("<JOB_ID>");
await job.delete();
const executions = await client.job.getExecutions("<JOB_ID>", 1, 10);
const executions = await job.getExecutions(1, 10);
const parameters = await client.job.getParameters("<JOB_ID>");
const parameters = await job.getParameters();
const runtimes = await client.job.getRuntimes();
const secrets = await client.secret.get();
const secret = await client.secret.get({ id: "<SECRET_ID>" });
const secret = await client.secret.get({ name: "<SECRET_NAME>" });
const secret = await client.secret.create({
name: "<SECRET_NAME>",
value: "<SECRET_VALUE>",
});
const secret = await client.secret.update("<SECRET_ID>", "<NEW_SECRET_VALUE>");
const secret = await secret.update("<NEW_SECRET_VALUE>");
await client.secret.delete("<SECRET_ID>");
await secret.delete();
folderName/
folderName/fileName.json
const stage = await workspaceGroup.stage.get();
const stage = await workspaceGroup.stage.get("<STAGE_PATH>/");
const nextStage = await stage.get("<STAGE_PATH>/");
const stage = await workspaceGroup.stage.get("<STAGE_PATH>");
const nextStage = await stage.get("<STAGE_PATH>");
await workspaceGroup.stage.update("<STAGE_PATH>", { newPath: "<NEW_STAGE_PATH>" });
await stage.update({ newPath: "<NEW_STAGE_PATH>" });
const newStage = await workspaceGroup.stage.createFolder("<NEW_STAGE_PATH>", "NEW_STAGE_NAME");
const newStage = stage.createFolder(
"<NEW_STAGE_NAME>",
"<NEW_STAGE_PATH>", // Optional
);
await workspaceGroup.stage.delete("<STAGE_PATH>");
await stage.delete();
const regions = await workspaceGroup.storage.getRegions();
const status = await workspaceGroup.storage.getStatus();
const result = await connection.client.execute("<SQL_QUERY>");
FAQs
The SingleStore Client is a package designed for interacting with the SingleStore API in Node.js environments.
The npm package @singlestore/client receives a total of 6 weekly downloads. As such, @singlestore/client popularity was classified as not popular.
We found that @singlestore/client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.