@pulsefunctions/client v0.7.9
Pulse
Initializing
npm add @instantlycreative/pulseImporting in browser
import { PulseClient } from '@instantlycreative/pulse'
const client = new PulseClient()Importing in node
import { PulseClient } from '@instantlycreative/pulse'
import crossFetch from 'cross-fetch'
import WebSocket from 'ws'
const client = new PulseClient({
fetch: crossFetch,
ws: WebSocket,
})Usage
Before running any command, you must login:
const { token } = await client.login({ email: 'user@example.com', password: 'mypasswd' })
if (token) {
fs.writeFileSync('~/.pulse.token', token)
}Alternatively, you can just pass a saved token.
const token = fs.readFileSync('~/.pulse.token', 'utf8')
await client.login({ token })API
Runtime:
dockernode14.xnode16.xnode18.xnode20.xpython3.8python3.9python3.10python3.11python3.12ruby3.2ruby3.3
login
async login({
email: string,
password: string
}): Promise<{
success: boolean;
token?: string;
error?: string
}>
async login({
token: string
}): Promise<{
success: boolean;
token?: string;
error?: string
}>get
async get({
pulseId
}: {
pulseId: string
}): Promise<{
success: boolean
team?: Team
pulse?: Pulse
statuses?: Status[]
error?: string
}>interface Team {
id: string
name: string
createdByUser: string
createdAt: Date
updatedAt: Date
}interface Pulse {
id: string
name: string
teamId: string
controllerId: string
createdAt: Date
updatedAt: Date
deletedAt: Date | null
}interface Status {
id: string
pulseId: string
sequence: number
status: PulseStatus
isPaused: boolean
data: any
createdAt: Date
updatedAt: Date
}export enum PulseStatus {
CREATED = 'created',
INITIALIZING = 'initializing',
INITIALIZED = 'initialized',
UPDATING = 'updating',
UPDATED = 'updated',
WARMING = 'warming',
READY = 'ready',
EXECUTING = 'executing',
STOPPING = 'stopping',
STOPPED = 'stopped',
DELETED = 'deleted',
}create
async create({
pulseId, // if not provided, a random id will be generated
name,
teamId,
runtime,
}: {
pulseId?: string
name?: string
teamId: string
runtime: string
}): Promise<{
success: boolean;
pulseId?: string;
error?: string
}>fork
async fork({
pulseId,
newPulseId, // if not provided, a random id will be generated
}: {
pulseId: string
newPulseId?: string
}): Promise<{
success: boolean;
pulseId?: string
error?: string;
}>update
async update({
pulseId,
name,
buildOptions, // if runtime supports it, i.e, docker build step args
execOptions, // runtime exec options, e.g., "--param" in "node --param /app/script.js"
execPath, // entry point, e.g., "/script.js" in "node /script.js", or "/Dockerfile" for "docker" runtime.
files, // files to be uploaded to the app directory. cannot be used with "zipFile"
zipFile, // zip with the app. will be extracted to /app/ directory. cannot be used with "files"
initFile, // initialization script
envFile, // .env file
stdinFile, // a file that will be used as stdin for the app
vcpu, // number of virtual CPUs
memory, // memory in MB
balloon, // initial balloon size in MB
autoPause, // pause the app after it's done executing the user app
autoShutdown, // shutdown the app after it's done executing the user app
autoDelete, // delete the app on shutdown
}: {
pulseId: string
name?: string
buildOptions?: string
execOptions?: string
execPath: string
files?: { [path: string]: string | Buffer | File }
zipFile?: string | Buffer | File
initFile?: string | Buffer | File
envFile?: string | Buffer | File
stdinFile?: string | Buffer | File
vcpu?: string
memory?: string
balloon?: string
autoPause?: boolean
autoShutdown?: boolean
autoDelete?: boolean
}): Promise<{
success: boolean;
accessToken?: string;
error?: string
}>export interface File {
source?: string // path on disk
content?: string | Buffer
mode?: number // like 0o755
}Use accessToken to stream the output using client.stream().
Notes on build and exec options:
buildOptionsis only used for thedockerruntime.execOptionsis used for all runtimes.
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
files: {
'/script.js': 'console.log("Hello, world!")',
},
execOptions: '--max-old-space-size=4096', // node param to set memory to 4GB
})This is will result in executing "node --max-old-space-size=4096 /script.js".
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
files: {
'/script.js': 'console.log("Hello, world!")',
},
buildOptions: '--build-arg=HELLO=WORLD --build-arg=ANOTHER=ARG', // docker build arg
})This is will result in adding "--build-arg=HELLO=WORLD" and "--build-arg=ANOTHER=ARG" params to the "docker build" command.
Notes on files:
filesis an object where the key is the path and the value is the content. The path must start with a slash, but the resulting file will be created in the app directory, which is /run/app.zipFileis a zip file that will be extracted to the app directory (/run/app).initFileis a script that will be executed before the user script.envFileis a.envfile that will be used to set environment variables.stdinFileis a file that will be used as stdin for the app.
When any file is a string, it will be treated as utf-8 encoded content:
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
files: {
'/script.js': 'console.log("Hello, world!")',
},
})When any file is a buffer, it will be treated as binary content:
import fs from 'fs'
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
zipFile: fs.readFileSync('/some/path/to/local/script.zip'), // returns Buffer
})Otherwise, you can use the File interface:
Note:
- "source" is the path to the file on disk.
- "content" is the content of the file.
- "mode" is the file mode.
- "source" and "content" are mutually exclusive.
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
files: {
'/script.js': {
source: '/some/path/to/local/script.js',
mode: 0o755,
},
'/other/script.js': {
content: 'console.log("Hello, world!")',
mode: 0o644,
},
'/another/script.js': {
content: Buffer.from('console.log("Hello, world!")'),
mode: 0o644,
},
},
})Optional initFile is a bash script that will be executed before the user script:
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
zipFile: fs.readFileSync('/some/path/to/local/script.zip'),
initFile: `#!/bin/bash
echo "Hello, world!"
echo "Goodbye, world!"
`,
})Optional envFile is a .env file that will be used to set environment variables:
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
zipFile: fs.readFileSync('/some/path/to/local/script.zip'),
envFile: `VAR1="value 1"
VAR2="value 2"
ANOTHER_VAR="another value"
# ... you get the idea
`,
})Optional stdinFile is a file that will be used as stdin for the app:
const { accessToken } = await client.update({
pulseId,
execPath: '/script.js',
zipFile: fs.readFileSync('/some/path/to/local/script.zip'),
stdinFile: fs.readFileSync('/some/path/to/local/stdin.txt'),
})If the app reads STDIN, it will read from that file.
warmUp
async warmUp({ pulseId }: { pulseId: string }): Promise<{ success: boolean; error?: string }>run
async run({ pulseId }: { pulseId: string }): Promise<{ success: boolean; accessToken?: string; error?: string }>pause
async pause({ pulseId }: { pulseId: string }): Promise<{ success: boolean; error?: string }>resume
async resume({ pulseId }: { pulseId: string }): Promise<{ success: boolean; error?: string }>shutdown
async shutdown({ pulseId }: { pulseId: string }): Promise<{ success: boolean; error?: string }>delete
async delete({ pulseId }: { pulseId: string }): Promise<{ success: boolean; error?: string }>balloon
async balloon({
pulseId,
balloon, // change balloon size to this (in MB)
}: {
pulseId: string
balloon: number
}): Promise<{
success: boolean;
error?: string
}>history
async history({
pulseId,
}: {
pulseId: string
}): Promise<{
success: boolean;
outputs?: Output[];
problems?: Problem[];
code?: number | null;
error?: string
}>interface Output {
pulseId: string
time: Date
source: string // "manager", "controller", "vm", "agent", "app"
stream: string // "stdout" or "stderr"
data: string
}interface Problem {
pulseId: string
time: Date
source: string // "manager", "controller", "vm", "agent", "app"
message: string
stack?: string
}stats
async stats({
pulseId,
}: {
pulseId: string
}): Promise<{
success: boolean;
stats?: AgentStats | null;
error?: string
}>interface AgentStats {
time: number
cpuAverage: number
memAverage: number
memTotal: number
memFree: number
memAvailable: number
vsz: number
rss: number
user: number
system: number
guest: number
}teamList
async teamList(): Promise<{ success: boolean; teams?: Team[]; error?: string }>interface Team {
id: string
name: string
createdByUser: string
createdAt: number
updatedAt: number
}teamGet
async teamGet({ teamId }: { teamId: string }): Promise<{ success: boolean; team?: Team; error?: string }>interface Team {
id: string
name: string
createdByUser: string
createdAt: number
updatedAt: number
}teamCreate
async teamCreate({ name }: { name: string }): Promise<{ success: boolean; team?: Team; error?: string }>interface Team {
id: string
name: string
createdByUser: string
createdAt: number
updatedAt: number
}teamUpdate
async teamUpdate({ teamId, name }: { teamId: string; name: string }): Promise<{ success: boolean; team?: Team; error?: string }>interface Team {
id: string
name: string
createdByUser: string
createdAt: number
updatedAt: number
}teamDelete
async teamDelete({ teamId }: { teamId: string }): Promise<{ success: boolean; team?: Team; error?: string }>interface Team {
id: string
name: string
createdByUser: string
createdAt: number
updatedAt: number
}teamUserList
async teamUserList({ teamId }: { teamId: string }): Promise<{ success: boolean; users?: User[]; error?: string }>interface User {
id: string
email: string
name: string
createdAt: number
updatedAt: number
}teamUserAdd
async teamUserAdd({ teamId, userId }: { teamId: string; userId: string }): Promise<{ success: boolean; error?: string }>interface User {
id: string
email: string
name: string
createdAt: number
updatedAt: number
}teamUserRemove
async teamUserRemove({ teamId, userId }: { teamId: string; userId: string }): Promise<{ success: boolean; error?: string }>run
This is a do-all method that will:
createupdatewarmUprundelete
async run(({
pulseId,
name,
buildOptions, // if runtime supports it, i.e, docker build step args
execOptions, // runtime exec options, e.g., "--param" in "node --param /app/script.js"
execPath, // entry point, e.g., "/script.js" in "node /script.js", or "/Dockerfile" for "docker" runtime.
files, // files to be uploaded to the app directory. cannot be used with "zipFile"
zipFile, // zip with the app. will be extracted to /app/ directory. cannot be used with "files"
initFile, // initialization script
envFile, // .env file
stdinFile, // a file that will be used as stdin for the app
vcpu, // number of virtual CPUs
memory, // memory in MB
balloon, // initial balloon size in MB
autoPause, // pause the app after it's done executing the user app
autoShutdown, // shutdown the app after it's done executing the user app
autoDelete, // delete the app on shutdown
}: {
pulseId: string
name?: string
buildOptions?: string
execOptions?: string
execPath: string
files?: { [path: string]: string | Buffer | File }
zipFile?: string | Buffer | File
initFile?: string | Buffer | File
envFile?: string | Buffer | File
stdinFile?: string | Buffer | File
vcpu?: string
memory?: string
balloon?: string
autoPause?: boolean
autoShutdown?: boolean
autoDelete?: boolean
}): Promise<{
success: boolean;
accessToken?: string;
error?: string
}>Use accessToken to stream the output using client.stream().
stream
async stream({
accessToken,
onOutput,
onProblem,
onFinish,
}: {
accessToken: string
onOutput?: (data: Output) => void
onProblem?: (data: Problem) => void
onFinish?: (data: Finished) => void
}): Promise<void>type ManagerMsgOutput = {
type: 'OUTPUT'
pulseId: string
output: Output
}interface Output {
pulseId: string
time: Date
source: string // "manager", "controller", "vm", "agent", "app"
stream: string // "stdout" or "stderr"
data: string
}interface Problem {
pulseId: string
time: Date
source: string // "manager", "controller", "vm", "agent", "app"
message: string
stack?: string
}export interface Finished {
pulseId: string
code: number | null
stats: AgentStats | null
}interface AgentStats {
time: number
cpuAverage: number
memAverage: number
memTotal: number
memFree: number
memAvailable: number
vsz: number
rss: number
user: number
system: number
guest: number
}An example:
await manager.stream({
accessToken,
onOutput: (data) => {
process.stdout.write(data.output.data)
},
onProblem: (data) => {
console.error(data.error.message)
},
onFinish: (data) => {
console.log('--------------------')
console.log(`Exit code: ${data.code}`)
if (data.stats) {
console.log(`Time: ${stats.time}ms`)
console.log(`CPU average: ${stats.cpuAverage.toFixed(2)}%`)
console.log(`Memory average: ${stats.memAverage.toFixed(2)}%`)
console.log(`Memory total: ${(stats.memTotal / 1024).toFixed(2)}MB`)
console.log(`Memory free: ${(stats.memFree / 1024).toFixed(2)}MB`)
console.log(`Memory available: ${(stats.memAvailable / 1024).toFixed(2)}MB`)
console.log(`VSZ: ${stats.vsz}`)
console.log(`RSS: ${stats.rss}`)
console.log(`User: ${stats.user.toFixed(2)}%`)
console.log(`System: ${stats.system.toFixed(2)}%`)
console.log(`Guest: ${stats.guest.toFixed(2)}%`)
}
},
})11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
10 months ago
11 months ago
10 months ago
11 months ago
9 months ago
11 months ago
10 months ago
11 months ago
11 months ago
10 months ago
11 months ago
11 months ago
9 months ago
9 months ago
11 months ago
9 months ago
11 months ago
9 months ago
9 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago