shapelessai-ai-sdk 0.1.0 → 0.1.1
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/dist/index.d.ts +1 -1
- package/dist/index.js +26 -19
- package/package.json +8 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type ShapelessAIOptions = {
|
|
2
|
-
/** An slk_ API key from https://shapelessai.com/
|
|
2
|
+
/** An slk_ API key from https://shapelessai.com/studio/api-keys. Defaults to process.env.SHAPELESSAI_API_KEY. */
|
|
3
3
|
apiKey?: string;
|
|
4
4
|
baseURL?: string;
|
|
5
5
|
/** Ask the user before a post is created. On by default: a post is visible to the account's audience. */
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { tool } from
|
|
2
|
-
import { z } from
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
3
|
function client(opts = {}) {
|
|
4
|
-
const base = (opts.baseURL ??
|
|
4
|
+
const base = (opts.baseURL ?? "https://shapelessai.com").replace(/\/$/, "");
|
|
5
5
|
return async function call(path, init = {}) {
|
|
6
6
|
const key = opts.apiKey ?? process.env.SHAPELESSAI_API_KEY;
|
|
7
7
|
if (!key)
|
|
8
|
-
throw new Error(
|
|
8
|
+
throw new Error("Set SHAPELESSAI_API_KEY (make one at https://shapelessai.com/studio/api-keys).");
|
|
9
9
|
const res = await fetch(`${base}${path}`, {
|
|
10
10
|
...init,
|
|
11
|
-
headers: { Authorization: `Bearer ${key}`,
|
|
11
|
+
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", ...init.headers },
|
|
12
12
|
});
|
|
13
13
|
if (res.status === 401)
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error("ShapelessAI refused the API key. Make a new one at https://shapelessai.com/studio/api-keys.");
|
|
15
15
|
const body = (await res.json().catch(() => ({})));
|
|
16
16
|
if (!res.ok)
|
|
17
17
|
throw new Error(body.error || `ShapelessAI answered ${res.status}`);
|
|
@@ -19,19 +19,26 @@ function client(opts = {}) {
|
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
const slim = (p) => ({
|
|
22
|
-
id: p.id,
|
|
23
|
-
|
|
22
|
+
id: p.id,
|
|
23
|
+
connectionId: p.connectionId,
|
|
24
|
+
platform: p.platform,
|
|
25
|
+
status: p.status,
|
|
26
|
+
text: p.postText,
|
|
27
|
+
scheduledAt: p.scheduledAt ?? null,
|
|
28
|
+
publishedAt: p.publishedAt ?? null,
|
|
29
|
+
url: p.publishedLocation ?? null,
|
|
30
|
+
error: p.error ?? null,
|
|
24
31
|
});
|
|
25
32
|
/** The social accounts the key's owner connected, the ones a post can go to. */
|
|
26
33
|
export function listAccounts(opts = {}) {
|
|
27
34
|
const call = client(opts);
|
|
28
35
|
return tool({
|
|
29
|
-
description:
|
|
36
|
+
description: "List the social media accounts connected to ShapelessAI that can be posted to (X, LinkedIn, Instagram, TikTok, YouTube, Threads, Bluesky, Facebook and more). Call this first to get a connectionId.",
|
|
30
37
|
inputSchema: z.object({ platform: z.string().optional().describe('Only accounts on this platform, e.g. "linkedin".') }),
|
|
31
38
|
execute: async ({ platform }) => {
|
|
32
|
-
const { connections } = await call(
|
|
39
|
+
const { connections } = await call("/api/connections");
|
|
33
40
|
return connections
|
|
34
|
-
.filter((c) => c.mode ===
|
|
41
|
+
.filter((c) => c.mode === "oauth" && c.status === "active" && (!platform || c.platform === platform.toLowerCase()))
|
|
35
42
|
.map((c) => ({ connectionId: c.id, platform: c.platform, handle: c.handle, name: c.displayName ?? c.handle }));
|
|
36
43
|
},
|
|
37
44
|
});
|
|
@@ -40,12 +47,12 @@ export function listAccounts(opts = {}) {
|
|
|
40
47
|
export function createPost(opts = {}) {
|
|
41
48
|
const call = client(opts);
|
|
42
49
|
return tool({
|
|
43
|
-
description:
|
|
50
|
+
description: "Create a social media post on one connected account through ShapelessAI. With no time it goes to the account's next free queue slot; set scheduledAt for a time, or publishNow only when the user asked to post right now.",
|
|
44
51
|
inputSchema: z.object({
|
|
45
|
-
connectionId: z.string().describe(
|
|
46
|
-
text: z.string().min(1).describe(
|
|
47
|
-
scheduledAt: z.string().optional().describe(
|
|
48
|
-
publishNow: z.boolean().optional().describe(
|
|
52
|
+
connectionId: z.string().describe("From listAccounts."),
|
|
53
|
+
text: z.string().min(1).describe("The post text, exactly as it should appear."),
|
|
54
|
+
scheduledAt: z.string().optional().describe("ISO 8601 time to publish at."),
|
|
55
|
+
publishNow: z.boolean().optional().describe("True only when the user asked to post right now."),
|
|
49
56
|
}),
|
|
50
57
|
needsApproval: opts.needsApproval ?? true,
|
|
51
58
|
execute: async ({ connectionId, text, scheduledAt, publishNow }) => {
|
|
@@ -56,7 +63,7 @@ export function createPost(opts = {}) {
|
|
|
56
63
|
else if (!publishNow)
|
|
57
64
|
body.queue = true;
|
|
58
65
|
// The answer is { id, status, scheduledAt } when queued, { id, status, publishedLocation, error } when posted now.
|
|
59
|
-
const res = await call(
|
|
66
|
+
const res = await call("/api/posts", { method: "POST", body: JSON.stringify(body) });
|
|
60
67
|
return { id: res.id, status: res.status, scheduledAt: res.scheduledAt ?? null, url: res.publishedLocation ?? null, error: res.error ?? null };
|
|
61
68
|
},
|
|
62
69
|
});
|
|
@@ -65,9 +72,9 @@ export function createPost(opts = {}) {
|
|
|
65
72
|
export function listPosts(opts = {}) {
|
|
66
73
|
const call = client(opts);
|
|
67
74
|
return tool({
|
|
68
|
-
description:
|
|
75
|
+
description: "List recent ShapelessAI posts with their status, scheduled time, live URL once published, and the error if one failed.",
|
|
69
76
|
inputSchema: z.object({
|
|
70
|
-
status: z.enum([
|
|
77
|
+
status: z.enum(["proposed", "scheduled", "publishing", "published", "handoff", "failed", "canceled"]).optional(),
|
|
71
78
|
limit: z.number().int().min(1).max(50).optional(),
|
|
72
79
|
}),
|
|
73
80
|
execute: async ({ status, limit }) => {
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shapelessai-ai-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "ShapelessAI tools for the Vercel AI SDK: list connected social accounts, schedule or publish posts, read post status.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ShapelessAI <hello@shapelessai.com> (https://shapelessai.com)",
|
|
7
|
-
"homepage": "https://shapelessai.com",
|
|
7
|
+
"homepage": "https://shapelessai.com/docs/ai-sdk",
|
|
8
8
|
"repository": { "type": "git", "url": "git+https://github.com/FirstClassTree/shapelessai.git", "directory": "integrations/ai-sdk" },
|
|
9
|
+
"bugs": "https://github.com/FirstClassTree/shapelessai/issues",
|
|
9
10
|
"keywords": ["ai-sdk", "vercel-ai", "tools", "social-media", "scheduler", "shapelessai", "agents"],
|
|
10
11
|
"type": "module",
|
|
11
12
|
"main": "./dist/index.js",
|
|
@@ -13,7 +14,11 @@
|
|
|
13
14
|
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
|
|
14
15
|
"files": ["dist", "README.md", "LICENSE"],
|
|
15
16
|
"engines": { "node": ">=18" },
|
|
16
|
-
"scripts": {
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p .",
|
|
19
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
20
|
+
"prepublishOnly": "npm test"
|
|
21
|
+
},
|
|
17
22
|
"peerDependencies": { "ai": ">=6", "zod": "^3.25.0 || ^4" },
|
|
18
23
|
"devDependencies": { "ai": "^7.0.140", "zod": "^4.6.7", "typescript": "^5.9.0", "@types/node": "^22" }
|
|
19
24
|
}
|