mindsim 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +32 -0
- package/.github/workflows/test.yml +28 -0
- package/.github/workflows/type-checks.yml +29 -0
- package/LICENSE +21 -0
- package/README.md +748 -0
- package/assets/mindsim-logo.svg +15 -0
- package/biome.jsonc +43 -0
- package/dist/auth.d.ts +5 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +115 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +36 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/artifacts.d.ts +8 -0
- package/dist/resources/artifacts.d.ts.map +1 -0
- package/dist/resources/artifacts.js +17 -0
- package/dist/resources/artifacts.js.map +1 -0
- package/dist/resources/minds.d.ts +39 -0
- package/dist/resources/minds.d.ts.map +1 -0
- package/dist/resources/minds.js +85 -0
- package/dist/resources/minds.js.map +1 -0
- package/dist/resources/psychometrics.d.ts +11 -0
- package/dist/resources/psychometrics.d.ts.map +1 -0
- package/dist/resources/psychometrics.js +18 -0
- package/dist/resources/psychometrics.js.map +1 -0
- package/dist/resources/simulations.d.ts +26 -0
- package/dist/resources/simulations.d.ts.map +1 -0
- package/dist/resources/simulations.js +41 -0
- package/dist/resources/simulations.js.map +1 -0
- package/dist/resources/snapshots.d.ts +27 -0
- package/dist/resources/snapshots.d.ts.map +1 -0
- package/dist/resources/snapshots.js +101 -0
- package/dist/resources/snapshots.js.map +1 -0
- package/dist/resources/tags.d.ts +23 -0
- package/dist/resources/tags.d.ts.map +1 -0
- package/dist/resources/tags.js +32 -0
- package/dist/resources/tags.js.map +1 -0
- package/dist/types.d.ts +161 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +15 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +105 -0
- package/dist/version.js.map +1 -0
- package/package.json +55 -0
- package/src/auth.ts +131 -0
- package/src/cli.ts +41 -0
- package/src/config.ts +60 -0
- package/src/index.ts +59 -0
- package/src/resources/artifacts.ts +13 -0
- package/src/resources/minds.ts +98 -0
- package/src/resources/psychometrics.ts +16 -0
- package/src/resources/simulations.ts +49 -0
- package/src/resources/snapshots.ts +126 -0
- package/src/resources/tags.ts +30 -0
- package/src/types.ts +185 -0
- package/src/version.ts +111 -0
- package/tests/auth.test.ts +41 -0
- package/tests/config.test.ts +129 -0
- package/tests/resources/minds.test.ts +119 -0
- package/tests/resources/psychometrics.test.ts +38 -0
- package/tests/resources/simulation.test.ts +94 -0
- package/tests/resources/snapshots.test.ts +135 -0
- package/tests/resources/tags.test.ts +87 -0
- package/tests/use-cases/quickstart.test.ts +84 -0
- package/tests/version.test.ts +221 -0
- package/tsconfig.json +29 -0
- package/vitest.config.ts +12 -0
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mindsim",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The official MindSim typescript SDK allows you to programmatically create digital minds, populate them with conversational data, and run powerful simulations to get an accurate preview of how the person will think, feel, say, and act in any scenario.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mindsim": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node ./dist/cli.js",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"watch": "tsc --watch",
|
|
14
|
+
"prepare": "npm run build",
|
|
15
|
+
"lint": "biome check --write .",
|
|
16
|
+
"lint:check": "biome check .",
|
|
17
|
+
"format": "biome format --write .",
|
|
18
|
+
"format:check": "biome format .",
|
|
19
|
+
"type-check": "tsc --noEmit",
|
|
20
|
+
"test": "npm run test:unit",
|
|
21
|
+
"test:unit": "vitest run",
|
|
22
|
+
"test:unit:watch": "vitest --watch"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/mindsimulator/mindsim-sdk-typescript.git"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mindsim",
|
|
30
|
+
"digital mind",
|
|
31
|
+
"simulation",
|
|
32
|
+
"psychometrics",
|
|
33
|
+
"sdk",
|
|
34
|
+
"typescript"
|
|
35
|
+
],
|
|
36
|
+
"author": "reasoner-developer",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/mindsimulator/mindsim-sdk-typescript/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/mindsimulator/mindsim-sdk-typescript#readme",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@biomejs/biome": "2.3.6",
|
|
44
|
+
"@types/node": "^24.10.1",
|
|
45
|
+
"@types/semver": "^7.5.8",
|
|
46
|
+
"typescript": "^5.9.3",
|
|
47
|
+
"vitest": "^3.2.4"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"axios": "^1.13.2",
|
|
51
|
+
"commander": "^14.0.2",
|
|
52
|
+
"open": "^11.0.0",
|
|
53
|
+
"semver": "^7.6.0"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/auth.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import url from "node:url";
|
|
3
|
+
import open from "open";
|
|
4
|
+
import { getAuthConfig, saveApiKey } from "./config";
|
|
5
|
+
import type { AuthResponse } from "./types";
|
|
6
|
+
|
|
7
|
+
// CONFIGURATION
|
|
8
|
+
const authConfig = getAuthConfig();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Starts the login flow
|
|
12
|
+
*/
|
|
13
|
+
export async function login(): Promise<void> {
|
|
14
|
+
console.log("Initiating authentication...");
|
|
15
|
+
|
|
16
|
+
// 1. Create a Promise that resolves when the local server receives the code
|
|
17
|
+
const apiKey = await listenForCallback();
|
|
18
|
+
|
|
19
|
+
console.log("Authorization succeeded.");
|
|
20
|
+
|
|
21
|
+
// 2. Exchange authorization code for access token
|
|
22
|
+
try {
|
|
23
|
+
// 3. Save credentials to disk
|
|
24
|
+
saveApiKey(apiKey);
|
|
25
|
+
|
|
26
|
+
console.log("✅ Successfully logged in! Credentials saved.");
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error("❌ Authentication failed:", error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Spins up a temporary local server to catch the redirect
|
|
35
|
+
*/
|
|
36
|
+
function listenForCallback(): Promise<string> {
|
|
37
|
+
const callbackPath = new URL(authConfig.authRedirectPath).pathname;
|
|
38
|
+
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const server = http.createServer(async (req, res) => {
|
|
41
|
+
if (!req.url) return;
|
|
42
|
+
|
|
43
|
+
const parsedUrl = url.parse(req.url, true);
|
|
44
|
+
|
|
45
|
+
const headers = {
|
|
46
|
+
"Access-Control-Allow-Origin": new URL(authConfig.authServerUrl).origin,
|
|
47
|
+
"Access-Control-Allow-Methods": "OPTIONS, POST, GET",
|
|
48
|
+
"Access-Control-Max-Age": 2592000, // 30 days
|
|
49
|
+
"Access-Control-Allow-Headers": "Content-Type,Authorization",
|
|
50
|
+
"Access-Control-Allow-Credentials": "true",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Check if the request is for the callback path
|
|
54
|
+
if (parsedUrl.pathname === callbackPath) {
|
|
55
|
+
if (req.method === "OPTIONS") {
|
|
56
|
+
res.writeHead(204, headers);
|
|
57
|
+
res.end();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (req.method === "POST") {
|
|
62
|
+
let body = "";
|
|
63
|
+
|
|
64
|
+
req.on("data", (chunk) => {
|
|
65
|
+
body += chunk.toString(); // Collect data chunks
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
req.on("end", () => {
|
|
69
|
+
let authResponseData: AuthResponse | null = null;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
authResponseData = JSON.parse(body);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error(`Got an invalid response: ${body}. Reason: ${err}`);
|
|
75
|
+
reject(err);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!authResponseData) {
|
|
79
|
+
res.end("No api key found");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const apiKey = authResponseData?.apiKey?.key;
|
|
84
|
+
|
|
85
|
+
if (!apiKey) {
|
|
86
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
87
|
+
res.end(`<h1>Authentication Error</h1><p>API Key Not Found</p>`);
|
|
88
|
+
server.close();
|
|
89
|
+
reject(new Error("API Key Not Found"));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (apiKey) {
|
|
94
|
+
// Send a nice "Close this window" message to the user
|
|
95
|
+
res.writeHead(200, { "Content-Type": "text/html", ...headers });
|
|
96
|
+
res.end(`
|
|
97
|
+
<h1>Authentication Successful</h1>
|
|
98
|
+
<p>You can close this window and return to your terminal.</p>
|
|
99
|
+
<script>window.close()</script>
|
|
100
|
+
`);
|
|
101
|
+
|
|
102
|
+
server.close();
|
|
103
|
+
resolve(apiKey);
|
|
104
|
+
} else {
|
|
105
|
+
res.end("No code found");
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
server.listen(authConfig.listenPort, async () => {
|
|
113
|
+
const state = JSON.stringify({
|
|
114
|
+
redirect: `${authConfig.authServerLandingPath}?initCallbackUrl=${encodeURIComponent(authConfig.authRedirectPath)}`,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const encodedState = btoa(state);
|
|
118
|
+
|
|
119
|
+
const loginUrl = `${authConfig.authServerUrl}?state=${encodedState}`;
|
|
120
|
+
|
|
121
|
+
console.log(`Listening on port ${authConfig.listenPort}...`);
|
|
122
|
+
console.log(`Opening browser to: ${loginUrl}`);
|
|
123
|
+
|
|
124
|
+
await open(loginUrl);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
server.on("error", (err) => {
|
|
128
|
+
reject(err);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { login } from "./auth";
|
|
5
|
+
import { checkForUpdates, getPackageVersion, updateSdk } from "./version";
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
const main = async () => {
|
|
10
|
+
program.name("mindsim").description("CLI for Mindsim SDK").version(getPackageVersion()); // Use the reusable extractor
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.command("version")
|
|
14
|
+
.description("Output your current MindSim CLI version and check for updates")
|
|
15
|
+
.action(async () => {
|
|
16
|
+
// When explicitly asking for version, be verbose about update status
|
|
17
|
+
console.log(getPackageVersion());
|
|
18
|
+
await checkForUpdates(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// The Auth Command
|
|
22
|
+
program
|
|
23
|
+
.command("auth")
|
|
24
|
+
.description("Login to Mindsim via browser")
|
|
25
|
+
.action(async () => {
|
|
26
|
+
await checkForUpdates(false);
|
|
27
|
+
await login();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// NEW: The Update Command
|
|
31
|
+
program
|
|
32
|
+
.command("update")
|
|
33
|
+
.description("Auto-update the MindSim SDK to the latest version")
|
|
34
|
+
.action(async () => {
|
|
35
|
+
await updateSdk();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
program.parse(process.argv);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
main();
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import type { AuthConfig } from "./types";
|
|
5
|
+
|
|
6
|
+
const API_BASE_URL = "https://app.mindsim.com/api/public/v1";
|
|
7
|
+
const AUTH_SERVER_URL = "https://app.mindsim.com/sdk/authorize";
|
|
8
|
+
const AUTH_SERVER_LANDING_PATH = "/sdk-success";
|
|
9
|
+
const AUTH_REDIRECT_URI = "http://localhost:4242/callback";
|
|
10
|
+
const AUTH_PORT = "4242";
|
|
11
|
+
|
|
12
|
+
export function getConfigDir() {
|
|
13
|
+
return path.join(os.homedir(), ".mindsim");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getConfigFile() {
|
|
17
|
+
return path.join(getConfigDir(), "config");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const loadApiKey = (): string | null => {
|
|
21
|
+
try {
|
|
22
|
+
if (process.env.MINDSIM_API_KEY) {
|
|
23
|
+
return process.env.MINDSIM_API_KEY;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const configFile = getConfigFile();
|
|
27
|
+
|
|
28
|
+
if (fs.existsSync(configFile)) {
|
|
29
|
+
const config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
|
|
30
|
+
return config.apiKey || null;
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// TODO: define logging interface so users can control where they are written to
|
|
34
|
+
console.error(error);
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const saveApiKey = (apiKey: string): void => {
|
|
40
|
+
const configDir = getConfigDir();
|
|
41
|
+
const configFile = getConfigFile();
|
|
42
|
+
|
|
43
|
+
if (!fs.existsSync(configDir)) {
|
|
44
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
fs.writeFileSync(configFile, JSON.stringify({ apiKey }, null, 2));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getAuthConfig = (): AuthConfig => {
|
|
50
|
+
return {
|
|
51
|
+
authServerUrl: process.env.MINDSIM_AUTH_SERVER_URL || AUTH_SERVER_URL,
|
|
52
|
+
authServerLandingPath: AUTH_SERVER_LANDING_PATH,
|
|
53
|
+
authRedirectPath: process.env.MINDSIM_AUTH_REDIRECT_URI || AUTH_REDIRECT_URI,
|
|
54
|
+
listenPort: process.env.MINDSIM_AUTH_PORT || AUTH_PORT,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const getApiBaseUrl = () => {
|
|
59
|
+
return process.env.MIND_SIM_API_BASE_URL || API_BASE_URL;
|
|
60
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import axios, { type AxiosInstance } from "axios";
|
|
2
|
+
import { getApiBaseUrl, loadApiKey } from "./config";
|
|
3
|
+
import { ArtifactsResource } from "./resources/artifacts";
|
|
4
|
+
import { MindsResource } from "./resources/minds";
|
|
5
|
+
import { PsychometricsResource } from "./resources/psychometrics";
|
|
6
|
+
import { SimulationsResource } from "./resources/simulations";
|
|
7
|
+
import { SnapshotsResource } from "./resources/snapshots";
|
|
8
|
+
import { TagsResource } from "./resources/tags";
|
|
9
|
+
import { checkForUpdates, getPackageVersion } from "./version";
|
|
10
|
+
|
|
11
|
+
export class MindSim {
|
|
12
|
+
private client: AxiosInstance;
|
|
13
|
+
|
|
14
|
+
public artifacts: ArtifactsResource;
|
|
15
|
+
public minds: MindsResource;
|
|
16
|
+
public psychometrics: PsychometricsResource;
|
|
17
|
+
public snapshots: SnapshotsResource;
|
|
18
|
+
public simulations: SimulationsResource;
|
|
19
|
+
public tags: TagsResource;
|
|
20
|
+
|
|
21
|
+
constructor(apiKey?: string, options?: { apiBaseUrl?: string }) {
|
|
22
|
+
// 1. Trigger the auto-update check (Fire and forget, do not await)
|
|
23
|
+
checkForUpdates().catch(() => {
|
|
24
|
+
// Catching here ensures no unhandled promise rejections in the user's console
|
|
25
|
+
// if the check fails completely.
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const token = apiKey || loadApiKey();
|
|
29
|
+
const sdkVersion = getPackageVersion();
|
|
30
|
+
const apiBaseUrl = options?.apiBaseUrl || getApiBaseUrl();
|
|
31
|
+
|
|
32
|
+
if (!token) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"API Key not found. Please run `mindsim auth` or pass the key to the constructor.",
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.client = axios.create({
|
|
39
|
+
baseURL: apiBaseUrl,
|
|
40
|
+
headers: {
|
|
41
|
+
Authorization: `Bearer ${token}`,
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
"x-reasoner-source": "sdk",
|
|
44
|
+
"x-reasoner-sdk": "mindsim/mindsim-sdk-typescript",
|
|
45
|
+
"x-reasoner-sdk-version": sdkVersion,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this.artifacts = new ArtifactsResource(this.client);
|
|
50
|
+
this.minds = new MindsResource(this.client);
|
|
51
|
+
this.psychometrics = new PsychometricsResource(this.client);
|
|
52
|
+
this.snapshots = new SnapshotsResource(this.client);
|
|
53
|
+
this.simulations = new SimulationsResource(this.client);
|
|
54
|
+
this.tags = new TagsResource(this.client);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Export types for consumer use
|
|
59
|
+
export * from "./types";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { GetSignedUrlParams, GetSignedUrlResponse } from "../types";
|
|
3
|
+
|
|
4
|
+
export class ArtifactsResource {
|
|
5
|
+
constructor(private client: AxiosInstance) {}
|
|
6
|
+
|
|
7
|
+
async getSignedUrl(mindId: string, params?: GetSignedUrlParams): Promise<GetSignedUrlResponse> {
|
|
8
|
+
const response = await this.client.get<GetSignedUrlResponse>(`/minds/${mindId}/signed-url`, {
|
|
9
|
+
params,
|
|
10
|
+
});
|
|
11
|
+
return response.data;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type {
|
|
3
|
+
CreateMindRequest,
|
|
4
|
+
ListMindsParams,
|
|
5
|
+
Mind,
|
|
6
|
+
SearchMindsParams,
|
|
7
|
+
UpdateMindRequest,
|
|
8
|
+
} from "../types";
|
|
9
|
+
|
|
10
|
+
export class MindsResource {
|
|
11
|
+
constructor(private client: AxiosInstance) {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* List all minds
|
|
15
|
+
*/
|
|
16
|
+
async list(params: ListMindsParams): Promise<Mind[]> {
|
|
17
|
+
const query: { [key: string]: string } = {};
|
|
18
|
+
|
|
19
|
+
if (params?.tags && params.tags?.length > 0) {
|
|
20
|
+
query.tagNames = params.tags.join(",");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const response = await this.client.get<{ minds: Mind[] }>("/minds", {
|
|
24
|
+
params: query,
|
|
25
|
+
});
|
|
26
|
+
return response.data.minds;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a new mind
|
|
31
|
+
*/
|
|
32
|
+
async create(data: CreateMindRequest): Promise<Mind> {
|
|
33
|
+
let createTags: string | undefined;
|
|
34
|
+
|
|
35
|
+
if (data?.tags && data?.tags?.length > 0) {
|
|
36
|
+
createTags = data.tags.join(",");
|
|
37
|
+
}
|
|
38
|
+
const response = await this.client.post<{ mind: Mind }>("/minds", {
|
|
39
|
+
...data,
|
|
40
|
+
tags: createTags,
|
|
41
|
+
});
|
|
42
|
+
return response.data.mind;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get a specific mind by ID
|
|
47
|
+
*/
|
|
48
|
+
async get(mindId: string): Promise<Mind> {
|
|
49
|
+
const response = await this.client.get<{ id: string } & Mind>(`/minds/${mindId}`);
|
|
50
|
+
return response.data;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Update a specific mind by ID
|
|
55
|
+
*/
|
|
56
|
+
async update(mindId: string, data: UpdateMindRequest): Promise<Mind> {
|
|
57
|
+
let updateTags: string | undefined;
|
|
58
|
+
|
|
59
|
+
// The API expects tags as a comma-separated string
|
|
60
|
+
if (data?.tags) {
|
|
61
|
+
updateTags = data.tags.join(",");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const response = await this.client.put<{ mind: Mind }>(`/minds/${mindId}`, {
|
|
65
|
+
...data,
|
|
66
|
+
tags: updateTags,
|
|
67
|
+
});
|
|
68
|
+
return response.data.mind;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Delete a mind by ID
|
|
73
|
+
*/
|
|
74
|
+
async delete(mindId: string): Promise<{ success: boolean }> {
|
|
75
|
+
const response = await this.client.delete<{ success: boolean }>(`/minds/${mindId}`);
|
|
76
|
+
return response.data;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Search minds
|
|
81
|
+
*/
|
|
82
|
+
async search(params: SearchMindsParams): Promise<Mind[]> {
|
|
83
|
+
const response = await this.client.get<{ minds: Mind[] }>("/minds/search", {
|
|
84
|
+
params,
|
|
85
|
+
});
|
|
86
|
+
return response.data.minds;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Set tags for a mind (Replace existing)
|
|
91
|
+
*/
|
|
92
|
+
async setTags(mindId: string, data: { tags: string[] }): Promise<Mind> {
|
|
93
|
+
const response = await this.client.put<{ mind: Mind }>(`/minds/${mindId}/tags`, {
|
|
94
|
+
tagNames: data.tags,
|
|
95
|
+
});
|
|
96
|
+
return response.data.mind;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { GetPsychometricsResponse } from "../types";
|
|
3
|
+
|
|
4
|
+
export class PsychometricsResource {
|
|
5
|
+
constructor(private client: AxiosInstance) {}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get psychometrics for a specific snapshot
|
|
9
|
+
*/
|
|
10
|
+
async get(snapshotId: string): Promise<GetPsychometricsResponse> {
|
|
11
|
+
const response = await this.client.get<GetPsychometricsResponse>(
|
|
12
|
+
`/snapshots/${snapshotId}/psychometrics`,
|
|
13
|
+
);
|
|
14
|
+
return response.data;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type {
|
|
3
|
+
GetSimulationResponse,
|
|
4
|
+
ListSimulationsParams,
|
|
5
|
+
ListSimulationsResponse,
|
|
6
|
+
RunSimulationRequest,
|
|
7
|
+
SimulationResponse,
|
|
8
|
+
} from "../types";
|
|
9
|
+
|
|
10
|
+
export class SimulationsResource {
|
|
11
|
+
constructor(private client: AxiosInstance) {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Run simulation
|
|
15
|
+
*/
|
|
16
|
+
async run(data: RunSimulationRequest): Promise<SimulationResponse> {
|
|
17
|
+
const response = await this.client.post<SimulationResponse>("/simulate", data);
|
|
18
|
+
return response.data;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* List historical simulations
|
|
23
|
+
*/
|
|
24
|
+
async list(params?: ListSimulationsParams): Promise<ListSimulationsResponse> {
|
|
25
|
+
const response = await this.client.get<ListSimulationsResponse>("/simulations", {
|
|
26
|
+
params,
|
|
27
|
+
});
|
|
28
|
+
return response.data;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get a specific simulation by ID
|
|
33
|
+
*/
|
|
34
|
+
async get(simulationId: string): Promise<GetSimulationResponse> {
|
|
35
|
+
const response = await this.client.get<GetSimulationResponse>(`/simulations/${simulationId}`);
|
|
36
|
+
return response.data;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Delete a specific simulation by ID
|
|
41
|
+
*/
|
|
42
|
+
async delete(simulationId: string): Promise<{ message: string; simulationId: string }> {
|
|
43
|
+
const response = await this.client.delete<{
|
|
44
|
+
message: string;
|
|
45
|
+
simulationId: string;
|
|
46
|
+
}>(`/simulations/${simulationId}`);
|
|
47
|
+
return response.data;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import path from "node:path"; // Import path
|
|
2
|
+
import axios, { type AxiosInstance } from "axios";
|
|
3
|
+
import FormData from "form-data";
|
|
4
|
+
import type {
|
|
5
|
+
CreateSnapshotFromFileParams,
|
|
6
|
+
CreateSnapshotParams,
|
|
7
|
+
CreateSnapshotResponse,
|
|
8
|
+
GetSignedUrlResponse,
|
|
9
|
+
ListSnapshotsResponse,
|
|
10
|
+
SnapshotStatus,
|
|
11
|
+
} from "../types";
|
|
12
|
+
|
|
13
|
+
export class SnapshotsResource {
|
|
14
|
+
constructor(private client: AxiosInstance) {}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Helper to infer content type from file extension
|
|
18
|
+
*/
|
|
19
|
+
private getContentType(fileName: string): string {
|
|
20
|
+
const ext = path.extname(fileName).toLowerCase();
|
|
21
|
+
const mimeTypes: Record<string, string> = {
|
|
22
|
+
".html": "text/html",
|
|
23
|
+
".js": "text/javascript",
|
|
24
|
+
".css": "text/css",
|
|
25
|
+
".json": "application/json",
|
|
26
|
+
".pdf": "application/pdf",
|
|
27
|
+
".txt": "text/plain",
|
|
28
|
+
".vtt": "text/vtt",
|
|
29
|
+
".md": "text/markdown",
|
|
30
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return mimeTypes[ext] || "application/octet-stream";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* List all snapshots for a mind
|
|
38
|
+
*/
|
|
39
|
+
async list(mindId: string): Promise<ListSnapshotsResponse> {
|
|
40
|
+
const response = await this.client.get<ListSnapshotsResponse>(`/minds/${mindId}/snapshots`);
|
|
41
|
+
return response.data;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create a snapshot via a signed url. Recommended for large files.
|
|
46
|
+
*/
|
|
47
|
+
async create(mindId: string, params: CreateSnapshotParams): Promise<CreateSnapshotResponse> {
|
|
48
|
+
const finalContentType = params.contentType || this.getContentType(params.fileName);
|
|
49
|
+
|
|
50
|
+
const signedUrlRes = await this.client.get<GetSignedUrlResponse>(
|
|
51
|
+
`/minds/${mindId}/signed-url`,
|
|
52
|
+
{
|
|
53
|
+
params: {
|
|
54
|
+
fileName: params.fileName,
|
|
55
|
+
contentType: finalContentType,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const { signedUrl, artifactId } = signedUrlRes.data;
|
|
61
|
+
|
|
62
|
+
await axios.put(signedUrl, params.file, {
|
|
63
|
+
headers: {
|
|
64
|
+
"Content-Type": finalContentType,
|
|
65
|
+
},
|
|
66
|
+
maxBodyLength: Infinity,
|
|
67
|
+
maxContentLength: Infinity,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const form = new FormData();
|
|
71
|
+
form.append("artifactId", artifactId);
|
|
72
|
+
|
|
73
|
+
if (params.mindsetDate) {
|
|
74
|
+
form.append("mindsetDate", params.mindsetDate);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const snapshotRes = await this.client.post<CreateSnapshotResponse>(
|
|
78
|
+
`/minds/${mindId}/snapshots`,
|
|
79
|
+
form,
|
|
80
|
+
{
|
|
81
|
+
headers: {
|
|
82
|
+
...form.getHeaders(),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return snapshotRes.data;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create snapshot from uploaded file
|
|
92
|
+
*/
|
|
93
|
+
async createFromFile(mindId: string, params: CreateSnapshotFromFileParams) {
|
|
94
|
+
const form = new FormData();
|
|
95
|
+
|
|
96
|
+
if (params.file) {
|
|
97
|
+
form.append("file", params.file, params.fileName || "upload.txt");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (params.artifactId) {
|
|
101
|
+
form.append("artifactId", params.artifactId);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (params.mindsetDate) {
|
|
105
|
+
form.append("mindsetDate", params.mindsetDate);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const response = await this.client.post(`/minds/${mindId}/snapshots`, form, {
|
|
109
|
+
headers: {
|
|
110
|
+
...form.getHeaders(), // Crucial for multipart/form-data in Node
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return response.data;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check snapshot status
|
|
119
|
+
*/
|
|
120
|
+
async getStatus(mindId: string, snapshotId: string): Promise<SnapshotStatus> {
|
|
121
|
+
const response = await this.client.get<SnapshotStatus>(
|
|
122
|
+
`/minds/${mindId}/snapshots/${snapshotId}/status`,
|
|
123
|
+
);
|
|
124
|
+
return response.data;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { Tag } from "../types";
|
|
3
|
+
|
|
4
|
+
export class TagsResource {
|
|
5
|
+
constructor(private client: AxiosInstance) {}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* List all tags
|
|
9
|
+
*/
|
|
10
|
+
async list(): Promise<Tag[]> {
|
|
11
|
+
const response = await this.client.get<{ tags: Tag[] }>("/tags");
|
|
12
|
+
return response.data.tags;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Update tag
|
|
17
|
+
*/
|
|
18
|
+
async update(tagId: string, data: { name: string }): Promise<Tag> {
|
|
19
|
+
const response = await this.client.put<{ tag: Tag }>(`/tags/${tagId}`, data);
|
|
20
|
+
return response.data.tag;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Delete tag
|
|
25
|
+
*/
|
|
26
|
+
async delete(tagId: string): Promise<{ deleted: boolean }> {
|
|
27
|
+
const response = await this.client.delete<{ deleted: boolean }>(`/tags/${tagId}`);
|
|
28
|
+
return response.data;
|
|
29
|
+
}
|
|
30
|
+
}
|