@talesofai/neta-skills 0.13.0 → 0.14.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/CHANGELOG.md +10 -0
- package/README.md +18 -10
- package/README.zh_cn.md +6 -6
- package/bin/apis/commerce.js +41 -0
- package/bin/apis/index.js +4 -0
- package/bin/commands/adventure_campaign/request_adventure_campaign.cmd.en_us.yml +1 -1
- package/bin/commands/load.js +15 -3
- package/bin/commands/premium/create_premium_order.cmd.en_us.yml +5 -0
- package/bin/commands/premium/create_premium_order.cmd.js +46 -0
- package/bin/commands/premium/create_premium_order.cmd.zh_cn.yml +5 -0
- package/bin/commands/premium/get_current_premium_plan.cmd.en_us.yml +3 -0
- package/bin/commands/premium/get_current_premium_plan.cmd.js +32 -0
- package/bin/commands/premium/get_current_premium_plan.cmd.zh_cn.yml +3 -0
- package/bin/commands/premium/get_premium_order.cmd.en_us.yml +5 -0
- package/bin/commands/premium/get_premium_order.cmd.js +44 -0
- package/bin/commands/premium/get_premium_order.cmd.zh_cn.yml +5 -0
- package/bin/commands/premium/list_premium_orders.cmd.en_us.yml +6 -0
- package/bin/commands/premium/list_premium_orders.cmd.js +59 -0
- package/bin/commands/premium/list_premium_orders.cmd.zh_cn.yml +6 -0
- package/bin/commands/premium/list_premium_plans.cmd.en_us.yml +3 -0
- package/bin/commands/premium/list_premium_plans.cmd.js +67 -0
- package/bin/commands/premium/list_premium_plans.cmd.zh_cn.yml +3 -0
- package/bin/commands/premium/pay_premium_order.cmd.en_us.yml +6 -0
- package/bin/commands/premium/pay_premium_order.cmd.js +44 -0
- package/bin/commands/premium/pay_premium_order.cmd.zh_cn.yml +6 -0
- package/bin/utils/date.js +66 -0
- package/bin/utils/parse_meta.js +1 -1
- package/package.json +2 -1
- package/skills/neta-adventure/SKILL.md +5 -5
- package/skills/neta-character/SKILL.md +8 -8
- package/skills/neta-character/references/character-creation.md +6 -6
- package/skills/neta-character/references/character-update.md +7 -7
- package/skills/neta-community/SKILL.md +8 -8
- package/skills/neta-community/references/character-search.md +20 -20
- package/skills/neta-community/references/hashtag-research.md +25 -25
- package/skills/neta-community/references/interactive-feed.md +27 -27
- package/skills/neta-community/references/social-interactive.md +10 -10
- package/skills/neta-creative/SKILL.md +53 -9
- package/skills/neta-creative/references/character-search.md +20 -20
- package/skills/neta-creative/references/collection-remix.md +1 -1
- package/skills/neta-creative/references/image-generation.md +14 -14
- package/skills/neta-creative/references/premium.md +68 -0
- package/skills/neta-creative/references/song-creation.md +4 -4
- package/skills/neta-creative/references/song-mv.md +15 -15
- package/skills/neta-creative/references/video-generation.md +5 -5
- package/skills/neta-elementum/SKILL.md +7 -7
- package/skills/neta-elementum/references/elementum-alchemy.md +8 -8
- package/skills/neta-elementum/references/elementum-update.md +8 -8
- package/skills/neta-space/SKILL.md +6 -6
- package/skills/neta-suggest/SKILL.md +34 -34
- package/skills/zh_cn/neta-adventure/SKILL.md +5 -5
- package/skills/zh_cn/neta-character/SKILL.md +8 -8
- package/skills/zh_cn/neta-character/references/character-creation.md +6 -6
- package/skills/zh_cn/neta-character/references/character-update.md +7 -7
- package/skills/zh_cn/neta-community/SKILL.md +9 -9
- package/skills/zh_cn/neta-community/references/character-search.md +20 -20
- package/skills/zh_cn/neta-community/references/hashtag-research.md +25 -25
- package/skills/zh_cn/neta-community/references/interactive-feed.md +30 -30
- package/skills/zh_cn/neta-community/references/social-interactive.md +10 -10
- package/skills/zh_cn/neta-creative/SKILL.md +8 -8
- package/skills/zh_cn/neta-creative/references/character-search.md +20 -20
- package/skills/zh_cn/neta-creative/references/collection-remix.md +1 -1
- package/skills/zh_cn/neta-creative/references/image-generation.md +14 -14
- package/skills/zh_cn/neta-creative/references/song-creation.md +4 -4
- package/skills/zh_cn/neta-creative/references/song-mv.md +15 -15
- package/skills/zh_cn/neta-creative/references/video-generation.md +5 -5
- package/skills/zh_cn/neta-elementum/SKILL.md +7 -7
- package/skills/zh_cn/neta-elementum/references/elementum-alchemy.md +8 -8
- package/skills/zh_cn/neta-elementum/references/elementum-update.md +8 -8
- package/skills/zh_cn/neta-space/SKILL.md +6 -6
- package/skills/zh_cn/neta-suggest/SKILL.md +55 -55
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @neta/skills-neta
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 54180c1: feat(premium): implement premium subscription commands and integrate dayjs for date handling
|
|
8
|
+
|
|
9
|
+
- Add premium subscription CLI commands: `create_premium_order`, `pay_premium_order`, `get_current_premium_plan`, `get_premium_order`, `list_premium_orders`, `list_premium_plans`; wire commerce APIs and command loading.
|
|
10
|
+
- Add `dayjs` and `src/utils/date.ts` for date formatting/parsing; adjust `parse_meta` as needed.
|
|
11
|
+
- Update `README.md` and `skills/neta-creative/SKILL.md`; add `skills/neta-creative/references/premium.md` for premium workflows.
|
|
12
|
+
|
|
3
13
|
## 0.13.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ You can get your access token / NETA TOKEN from the [Neta Open Portal](https://w
|
|
|
19
19
|
## ✨ Features
|
|
20
20
|
|
|
21
21
|
- 🎨 **Multimedia Creation:** Generate stunning images, videos, and songs using state-of-the-art AI models.
|
|
22
|
+
- ⭐ **Premium & Subscriptions:** List plans, create orders, start Stripe checkout, and verify the active tier via dedicated CLI commands (global API environment).
|
|
22
23
|
- 🔧 **Image & Video Processing:** Effortlessly remove backgrounds and merge video assets.
|
|
23
24
|
- 👤 **Character & Style Management:** Search, fetch details, and manage characters and stylistic elements.
|
|
24
25
|
- 🏷️ **Community Integrations:** Explore trending hashtags, popular characters, and curated collections.
|
|
@@ -46,7 +47,7 @@ You can also install the specialized skills separately if your agent prefers mor
|
|
|
46
47
|
# Community exploration (hashtags, spaces, interactive feed)
|
|
47
48
|
npx skills add talesofai/neta-skills/skills/neta-community
|
|
48
49
|
|
|
49
|
-
# Creation workflows (image / video / song)
|
|
50
|
+
# Creation workflows (image / video / song) and premium subscription flows
|
|
50
51
|
npx skills add talesofai/neta-skills/skills/neta-creative
|
|
51
52
|
|
|
52
53
|
# Discovery & suggestions (keywords, tags, categories, content)
|
|
@@ -67,7 +68,7 @@ npx skills add talesofai/neta-skills/skills/neta-adventure
|
|
|
67
68
|
|
|
68
69
|
### Available Commands
|
|
69
70
|
|
|
70
|
-
The skill includes **
|
|
71
|
+
The skill includes **42 commands** for various tasks:
|
|
71
72
|
|
|
72
73
|
| Category | Command | Description |
|
|
73
74
|
|----------|---------|-------------|
|
|
@@ -82,6 +83,12 @@ The skill includes **34 commands** for various tasks:
|
|
|
82
83
|
| | `edit_collection` | Edit an existing collection (name, description, tags, status, etc.) |
|
|
83
84
|
| | `publish_collection` | Publish or update a collection |
|
|
84
85
|
| | `search_character_or_elementum` | Search reusable TCP building blocks (characters / elements / flows) |
|
|
86
|
+
| **Premium** | `get_current_premium_plan` | Get the signed-in user’s current tier and subscription end when applicable |
|
|
87
|
+
| | `list_premium_plans` | List available premium plans and SPU UUIDs |
|
|
88
|
+
| | `create_premium_order` | Create an order for a plan (by SPU UUID) |
|
|
89
|
+
| | `get_premium_order` | Fetch details for a single premium order |
|
|
90
|
+
| | `list_premium_orders` | List premium orders (paginated) |
|
|
91
|
+
| | `pay_premium_order` | Start payment for an unpaid order (e.g. Stripe Checkout) |
|
|
85
92
|
| **VToken Management** | `create_character` | Create a character VToken (consumes credits) |
|
|
86
93
|
| | `update_character` | Update an existing character VToken |
|
|
87
94
|
| | `list_my_characters` | List all characters created by the current user |
|
|
@@ -136,14 +143,14 @@ export NETA_TOKEN=your_token_here
|
|
|
136
143
|
|
|
137
144
|
```bash
|
|
138
145
|
# Get general help or specific command help
|
|
139
|
-
npx -y @talesofai/neta-skills --help
|
|
140
|
-
npx -y @talesofai/neta-skills make_image --help
|
|
146
|
+
npx -y @talesofai/neta-skills@latest --help
|
|
147
|
+
npx -y @talesofai/neta-skills@latest make_image --help
|
|
141
148
|
|
|
142
149
|
# Example: Generate an image
|
|
143
|
-
npx -y @talesofai/neta-skills make_image --prompt "A cyberpunk cityscape at night" --aspect "16:9"
|
|
150
|
+
npx -y @talesofai/neta-skills@latest make_image --prompt "A cyberpunk cityscape at night" --aspect "16:9"
|
|
144
151
|
|
|
145
152
|
# Example: Search for characters or elementum
|
|
146
|
-
npx -y @talesofai/neta-skills search_character_or_elementum --keywords "fantasy"
|
|
153
|
+
npx -y @talesofai/neta-skills@latest search_character_or_elementum --keywords "fantasy"
|
|
147
154
|
```
|
|
148
155
|
|
|
149
156
|
---
|
|
@@ -172,8 +179,8 @@ neta-skills/
|
|
|
172
179
|
│ ├── neta-elementum/
|
|
173
180
|
│ └── neta-adventure/
|
|
174
181
|
├── src/ # TypeScript source for the CLI
|
|
175
|
-
│ ├── apis/ # Typed Neta API client helpers
|
|
176
|
-
│ ├── commands/ # CLI command
|
|
182
|
+
│ ├── apis/ # Typed Neta API client helpers (incl. commerce)
|
|
183
|
+
│ ├── commands/ # CLI command groups: creative, community, adventure, VToken, premium, …
|
|
177
184
|
│ ├── utils/ # Shared utilities
|
|
178
185
|
│ └── cli.ts # CLI entrypoint (TypeScript)
|
|
179
186
|
├── bin/ # Built JavaScript output for the CLI
|
|
@@ -203,6 +210,7 @@ Agents use these references to learn the optimal sequence of actions, parameter
|
|
|
203
210
|
- **Song & MV Creation:** Workflows for composing songs and creating music videos with synchronized visuals.
|
|
204
211
|
- **Character & Hashtag Research:** Processes for finding trending content, searching characters, and utilizing community trends.
|
|
205
212
|
- **Character & Elementum Creation:** Character creation and elementum alchemy workflows.
|
|
213
|
+
- **Premium / Subscriptions:** Plan listing, order lifecycle, checkout channels, and environment limits. See `skills/neta-creative/references/premium.md`.
|
|
206
214
|
- **Adventure Campaign Crafting & Play:** Multi-turn story creation workflow (Craft Mode), interactive session management (Play Mode), field reference, and complete genre examples. See `skills/neta-adventure/references/`.
|
|
207
215
|
|
|
208
216
|
---
|
|
@@ -231,8 +239,8 @@ In terminal environments, locale is typically controlled by:
|
|
|
231
239
|
If you want to force a specific language for a single command, you can prefix it with the desired locale, for example:
|
|
232
240
|
|
|
233
241
|
```bash
|
|
234
|
-
LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills make_image --help
|
|
235
|
-
LANG=en_US.UTF-8 npx -y @talesofai/neta-skills make_image --help
|
|
242
|
+
LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
|
|
243
|
+
LANG=en_US.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
|
|
236
244
|
```
|
|
237
245
|
|
|
238
246
|
---
|
package/README.zh_cn.md
CHANGED
|
@@ -140,16 +140,16 @@ export NETA_TOKEN=your_token_here
|
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
142
|
# 查看帮助
|
|
143
|
-
npx -y @talesofai/neta-skills --help
|
|
144
|
-
npx -y @talesofai/neta-skills make_image --help
|
|
143
|
+
npx -y @talesofai/neta-skills@latest --help
|
|
144
|
+
npx -y @talesofai/neta-skills@latest make_image --help
|
|
145
145
|
|
|
146
146
|
# 示例:生成一张图片
|
|
147
|
-
npx -y @talesofai/neta-skills make_image \
|
|
147
|
+
npx -y @talesofai/neta-skills@latest make_image \
|
|
148
148
|
--prompt "夜晚的赛博朋克城市,霓虹灯,高楼大厦,雨中街道" \
|
|
149
149
|
--aspect "16:9"
|
|
150
150
|
|
|
151
151
|
# 示例:搜索角色或元素
|
|
152
|
-
npx -y @talesofai/neta-skills search_character_or_elementum \
|
|
152
|
+
npx -y @talesofai/neta-skills@latest search_character_or_elementum \
|
|
153
153
|
--keywords "幻想" \
|
|
154
154
|
--parent_type "character"
|
|
155
155
|
```
|
|
@@ -238,8 +238,8 @@ CLI 与 Skills 会根据系统与环境变量自动选择使用的语言:
|
|
|
238
238
|
在需要强制指定语言时,推荐在运行命令前显式设置环境变量,例如:
|
|
239
239
|
|
|
240
240
|
```bash
|
|
241
|
-
LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills make_image --help
|
|
242
|
-
LANG=en_US.UTF-8 npx -y @talesofai/neta-skills make_image --help
|
|
241
|
+
LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
|
|
242
|
+
LANG=en_US.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
|
|
243
243
|
```
|
|
244
244
|
|
|
245
245
|
---
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const createCommerceApis = (client) => {
|
|
2
|
+
const listPlansConfig = async () => {
|
|
3
|
+
const res = await client.get("/v1/configs/config", {
|
|
4
|
+
params: {
|
|
5
|
+
namespace: "fe_configs",
|
|
6
|
+
key: "plans",
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
return res.data;
|
|
10
|
+
};
|
|
11
|
+
const createOrder = async (params) => {
|
|
12
|
+
const res = await client.post("/v1/commerce/orders", params);
|
|
13
|
+
return res.data;
|
|
14
|
+
};
|
|
15
|
+
const orders = async (params) => {
|
|
16
|
+
const res = await client.get("/v1/commerce/orders", {
|
|
17
|
+
params,
|
|
18
|
+
});
|
|
19
|
+
return res.data;
|
|
20
|
+
};
|
|
21
|
+
const order = async (params) => {
|
|
22
|
+
const res = await client.get(`/v1/commerce/orders/${params.order_uuid}`);
|
|
23
|
+
return res.data;
|
|
24
|
+
};
|
|
25
|
+
const pay = async (params) => {
|
|
26
|
+
const { order_uuid, channel, return_url, redirect_url } = params;
|
|
27
|
+
return client
|
|
28
|
+
.post(`/v1/commerce/orders/${order_uuid}/payment/${channel}`, {
|
|
29
|
+
redirect_url,
|
|
30
|
+
return_url,
|
|
31
|
+
})
|
|
32
|
+
.then((res) => res.data);
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
listPlansConfig,
|
|
36
|
+
createOrder,
|
|
37
|
+
orders,
|
|
38
|
+
order,
|
|
39
|
+
pay,
|
|
40
|
+
};
|
|
41
|
+
};
|
package/bin/apis/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createActivityApis } from "./activity.js";
|
|
|
4
4
|
import { createArtifactApis } from "./artifact.js";
|
|
5
5
|
import { createAudioApis } from "./audio.js";
|
|
6
6
|
import { createCollectionApis } from "./collection.js";
|
|
7
|
+
import { createCommerceApis } from "./commerce.js";
|
|
7
8
|
import { createConfigApis } from "./config.js";
|
|
8
9
|
import { createFeedsApis } from "./feeds.js";
|
|
9
10
|
import { createGptApis } from "./gpt.js";
|
|
@@ -44,7 +45,9 @@ export const createApis = (option) => {
|
|
|
44
45
|
const space = createSpaceApis(client);
|
|
45
46
|
const recsys = createRecsysApis(client);
|
|
46
47
|
const travelCampaign = createTravelCampaignApis(client);
|
|
48
|
+
const commerce = createCommerceApis(client);
|
|
47
49
|
return {
|
|
50
|
+
baseUrl,
|
|
48
51
|
tcp,
|
|
49
52
|
prompt,
|
|
50
53
|
artifact,
|
|
@@ -61,5 +64,6 @@ export const createApis = (option) => {
|
|
|
61
64
|
space,
|
|
62
65
|
recsys,
|
|
63
66
|
travelCampaign,
|
|
67
|
+
commerce,
|
|
64
68
|
};
|
|
65
69
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
name: request_adventure_campaign
|
|
2
2
|
title: Get Adventure Campaign Details
|
|
3
3
|
description: |
|
|
4
|
-
Get full details of
|
|
4
|
+
Get full details of an Adventure Campaign including mission plot, task, and AI constraints.
|
|
5
5
|
|
|
6
6
|
This is the primary command for "play mode" — load a campaign before starting a storytelling session.
|
|
7
7
|
|
package/bin/commands/load.js
CHANGED
|
@@ -11,7 +11,7 @@ import { resolve } from "node:path";
|
|
|
11
11
|
import { pathToFileURL } from "node:url";
|
|
12
12
|
import { Option, } from "@commander-js/extra-typings";
|
|
13
13
|
import { Type } from "@sinclair/typebox";
|
|
14
|
-
import {
|
|
14
|
+
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
15
15
|
import { createApis } from "../apis/index.js";
|
|
16
16
|
import { ApiResponseError } from "../utils/errors.js";
|
|
17
17
|
import { setLocale } from "../utils/parse_meta.js";
|
|
@@ -45,6 +45,7 @@ export const buildCommands = async (cli) => {
|
|
|
45
45
|
"community",
|
|
46
46
|
"character_elementum",
|
|
47
47
|
"adventure_campaign",
|
|
48
|
+
"premium",
|
|
48
49
|
]);
|
|
49
50
|
return commands.map((cmd) => {
|
|
50
51
|
const command = cli.command(cmd.name);
|
|
@@ -102,7 +103,7 @@ export const buildCommands = async (cli) => {
|
|
|
102
103
|
return null;
|
|
103
104
|
});
|
|
104
105
|
const type = cmd.inputSchema ?? Type.Object({});
|
|
105
|
-
const input = Value.
|
|
106
|
+
const input = Value.Parse(type, args);
|
|
106
107
|
if (IS_DEV) {
|
|
107
108
|
logger.debug("command: %s, params: %o", cmd.name, input);
|
|
108
109
|
}
|
|
@@ -120,6 +121,17 @@ export const buildCommands = async (cli) => {
|
|
|
120
121
|
},
|
|
121
122
|
})
|
|
122
123
|
.catch((e) => {
|
|
124
|
+
if (e instanceof AssertError) {
|
|
125
|
+
logger.error({
|
|
126
|
+
error: {
|
|
127
|
+
type: e.name,
|
|
128
|
+
message: e.message,
|
|
129
|
+
path: e.error?.path,
|
|
130
|
+
schema: e.error?.schema,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
123
135
|
if (e instanceof ApiResponseError) {
|
|
124
136
|
logger.error({
|
|
125
137
|
error: {
|
|
@@ -145,7 +157,7 @@ export const buildCommands = async (cli) => {
|
|
|
145
157
|
if (!result)
|
|
146
158
|
return;
|
|
147
159
|
if (IS_DEV) {
|
|
148
|
-
logger.debug(result);
|
|
160
|
+
logger.debug(JSON.stringify(result, null, 2));
|
|
149
161
|
}
|
|
150
162
|
else {
|
|
151
163
|
logger.info(JSON.stringify(result));
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { parseDate } from "../../utils/date.js";
|
|
3
|
+
import { parseMeta } from "../../utils/parse_meta.js";
|
|
4
|
+
import { createCommand } from "../factory.js";
|
|
5
|
+
const meta = parseMeta(Type.Object({
|
|
6
|
+
name: Type.String(),
|
|
7
|
+
title: Type.String(),
|
|
8
|
+
description: Type.String(),
|
|
9
|
+
parameters: Type.Object({
|
|
10
|
+
spu_uuid: Type.String(),
|
|
11
|
+
}),
|
|
12
|
+
}), import.meta);
|
|
13
|
+
export const createPremiumOrder = createCommand({
|
|
14
|
+
name: meta.name,
|
|
15
|
+
title: meta.title,
|
|
16
|
+
description: meta.description,
|
|
17
|
+
inputSchema: Type.Object({
|
|
18
|
+
spu_uuid: Type.String({ description: meta.parameters.spu_uuid }),
|
|
19
|
+
}),
|
|
20
|
+
}, async ({ spu_uuid }, { apis }) => {
|
|
21
|
+
if (!apis.baseUrl.endsWith("talesofai.com")) {
|
|
22
|
+
throw new Error("This command is not supported in the current region");
|
|
23
|
+
}
|
|
24
|
+
const order = await apis.commerce.createOrder({
|
|
25
|
+
spu_uuid,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
order: {
|
|
29
|
+
uuid: order.uuid,
|
|
30
|
+
spu: {
|
|
31
|
+
uuid: order.spu.uuid,
|
|
32
|
+
name: order.spu.name,
|
|
33
|
+
price: order.spu.price,
|
|
34
|
+
},
|
|
35
|
+
status: order.status,
|
|
36
|
+
status_history: order.status_history.map((item) => ({
|
|
37
|
+
...item,
|
|
38
|
+
time: parseDate(item.time).format(),
|
|
39
|
+
})),
|
|
40
|
+
price: order.price,
|
|
41
|
+
valid_until: parseDate(order.valid_until).format(),
|
|
42
|
+
ctime: parseDate(order.ctime).format(),
|
|
43
|
+
mtime: parseDate(order.mtime).format(),
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { parseDate } from "../../utils/date.js";
|
|
3
|
+
import { parseMeta } from "../../utils/parse_meta.js";
|
|
4
|
+
import { createCommand } from "../factory.js";
|
|
5
|
+
const PlanningMap = {
|
|
6
|
+
0: "Basic",
|
|
7
|
+
1: "Starter",
|
|
8
|
+
2: "Pro",
|
|
9
|
+
3: "Master",
|
|
10
|
+
};
|
|
11
|
+
const meta = parseMeta(Type.Object({
|
|
12
|
+
name: Type.String(),
|
|
13
|
+
title: Type.String(),
|
|
14
|
+
description: Type.String(),
|
|
15
|
+
}), import.meta);
|
|
16
|
+
export const getCurrentPremiumPlan = createCommand({
|
|
17
|
+
name: meta.name,
|
|
18
|
+
title: meta.title,
|
|
19
|
+
description: meta.description,
|
|
20
|
+
}, async (_, { apis }) => {
|
|
21
|
+
if (!apis.baseUrl.endsWith("talesofai.com")) {
|
|
22
|
+
throw new Error("This command is not supported in the current region");
|
|
23
|
+
}
|
|
24
|
+
const user = await apis.user.me();
|
|
25
|
+
const level = user.properties?.vip_level ?? 0;
|
|
26
|
+
return {
|
|
27
|
+
plan: PlanningMap[level],
|
|
28
|
+
until: user.properties?.vip_until
|
|
29
|
+
? parseDate(user.properties.vip_until).format()
|
|
30
|
+
: null,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { parseDate } from "../../utils/date.js";
|
|
3
|
+
import { parseMeta } from "../../utils/parse_meta.js";
|
|
4
|
+
import { createCommand } from "../factory.js";
|
|
5
|
+
const meta = parseMeta(Type.Object({
|
|
6
|
+
name: Type.String(),
|
|
7
|
+
title: Type.String(),
|
|
8
|
+
description: Type.String(),
|
|
9
|
+
parameters: Type.Object({
|
|
10
|
+
order_uuid: Type.String(),
|
|
11
|
+
}),
|
|
12
|
+
}), import.meta);
|
|
13
|
+
export const getPremiumOrder = createCommand({
|
|
14
|
+
name: meta.name,
|
|
15
|
+
title: meta.title,
|
|
16
|
+
description: meta.description,
|
|
17
|
+
inputSchema: Type.Object({
|
|
18
|
+
order_uuid: Type.String({ description: meta.parameters.order_uuid }),
|
|
19
|
+
}),
|
|
20
|
+
}, async ({ order_uuid }, { apis }) => {
|
|
21
|
+
if (!apis.baseUrl.endsWith("talesofai.com")) {
|
|
22
|
+
throw new Error("This command is not supported in the current region");
|
|
23
|
+
}
|
|
24
|
+
const order = await apis.commerce.order({ order_uuid });
|
|
25
|
+
return {
|
|
26
|
+
order: {
|
|
27
|
+
uuid: order.uuid,
|
|
28
|
+
spu: {
|
|
29
|
+
uuid: order.spu.uuid,
|
|
30
|
+
name: order.spu.name,
|
|
31
|
+
price: order.spu.price,
|
|
32
|
+
},
|
|
33
|
+
status: order.status,
|
|
34
|
+
status_history: order.status_history.map((item) => ({
|
|
35
|
+
...item,
|
|
36
|
+
time: parseDate(item.time).format(),
|
|
37
|
+
})),
|
|
38
|
+
price: order.price,
|
|
39
|
+
valid_until: parseDate(order.valid_until).format(),
|
|
40
|
+
ctime: parseDate(order.ctime).format(),
|
|
41
|
+
mtime: parseDate(order.mtime).format(),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { parseDate } from "../../utils/date.js";
|
|
3
|
+
import { parseMeta } from "../../utils/parse_meta.js";
|
|
4
|
+
import { createCommand } from "../factory.js";
|
|
5
|
+
const meta = parseMeta(Type.Object({
|
|
6
|
+
name: Type.String(),
|
|
7
|
+
title: Type.String(),
|
|
8
|
+
description: Type.String(),
|
|
9
|
+
parameters: Type.Object({
|
|
10
|
+
page_index: Type.String(),
|
|
11
|
+
page_size: Type.String(),
|
|
12
|
+
}),
|
|
13
|
+
}), import.meta);
|
|
14
|
+
export const listPremiumOrders = createCommand({
|
|
15
|
+
name: meta.name,
|
|
16
|
+
title: meta.title,
|
|
17
|
+
description: meta.description,
|
|
18
|
+
inputSchema: Type.Object({
|
|
19
|
+
page_index: Type.Integer({
|
|
20
|
+
minimum: 0,
|
|
21
|
+
default: 0,
|
|
22
|
+
description: meta.parameters.page_index,
|
|
23
|
+
}),
|
|
24
|
+
page_size: Type.Integer({
|
|
25
|
+
minimum: 1,
|
|
26
|
+
maximum: 50,
|
|
27
|
+
default: 20,
|
|
28
|
+
description: meta.parameters.page_size,
|
|
29
|
+
}),
|
|
30
|
+
}),
|
|
31
|
+
}, async ({ page_index, page_size }, { apis }) => {
|
|
32
|
+
if (!apis.baseUrl.endsWith("talesofai.com")) {
|
|
33
|
+
throw new Error("This command is not supported in the current region");
|
|
34
|
+
}
|
|
35
|
+
const { list, total } = await apis.commerce.orders({
|
|
36
|
+
page_index,
|
|
37
|
+
page_size,
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
total,
|
|
41
|
+
orders: list.map((order) => ({
|
|
42
|
+
uuid: order.uuid,
|
|
43
|
+
spu: {
|
|
44
|
+
uuid: order.spu.uuid,
|
|
45
|
+
name: order.spu.name,
|
|
46
|
+
price: order.spu.price,
|
|
47
|
+
},
|
|
48
|
+
status: order.status,
|
|
49
|
+
status_history: order.status_history.map((item) => ({
|
|
50
|
+
...item,
|
|
51
|
+
time: parseDate(item.time).format(),
|
|
52
|
+
})),
|
|
53
|
+
price: order.price,
|
|
54
|
+
valid_until: parseDate(order.valid_until).format(),
|
|
55
|
+
ctime: parseDate(order.ctime).format(),
|
|
56
|
+
mtime: parseDate(order.mtime).format(),
|
|
57
|
+
})),
|
|
58
|
+
};
|
|
59
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { Value } from "@sinclair/typebox/value";
|
|
3
|
+
import { safeParseJson } from "../../utils/json.js";
|
|
4
|
+
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
|
+
import { createCommand } from "../factory.js";
|
|
6
|
+
const meta = parseMeta(Type.Object({
|
|
7
|
+
name: Type.String(),
|
|
8
|
+
title: Type.String(),
|
|
9
|
+
description: Type.String(),
|
|
10
|
+
}), import.meta);
|
|
11
|
+
const PlanBasicInfo = Type.Object({
|
|
12
|
+
descriptions: Type.Array(Type.String()),
|
|
13
|
+
infoPopup: Type.Object({
|
|
14
|
+
title: Type.String(),
|
|
15
|
+
content: Type.String(),
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
const Plan = Type.Composite([
|
|
19
|
+
PlanBasicInfo,
|
|
20
|
+
Type.Object({
|
|
21
|
+
price: Type.Object({
|
|
22
|
+
monthly: Type.Number(),
|
|
23
|
+
monthlyOff: Type.Number(),
|
|
24
|
+
monthlyOriginal: Type.Number(),
|
|
25
|
+
yearly: Type.Number(),
|
|
26
|
+
yearlyTotal: Type.Number(),
|
|
27
|
+
off: Type.Number(),
|
|
28
|
+
}),
|
|
29
|
+
spu: Type.Object({
|
|
30
|
+
monthly: Type.Optional(Type.String()),
|
|
31
|
+
yearly: Type.Optional(Type.String()),
|
|
32
|
+
}),
|
|
33
|
+
}),
|
|
34
|
+
]);
|
|
35
|
+
const PlansConfig = Type.Object({
|
|
36
|
+
"en-US": Type.Optional(Type.Record(Type.Union([
|
|
37
|
+
Type.Literal("Master"),
|
|
38
|
+
Type.Literal("Pro"),
|
|
39
|
+
Type.Literal("Starter"),
|
|
40
|
+
]), Type.Optional(Plan))),
|
|
41
|
+
});
|
|
42
|
+
export const listPremiumPlans = createCommand({
|
|
43
|
+
name: meta.name,
|
|
44
|
+
title: meta.title,
|
|
45
|
+
description: meta.description,
|
|
46
|
+
}, async (_, { apis }) => {
|
|
47
|
+
if (!apis.baseUrl.endsWith("talesofai.com")) {
|
|
48
|
+
throw new Error("This command is not supported in the current region");
|
|
49
|
+
}
|
|
50
|
+
const plansConfigValue = await apis.commerce.listPlansConfig();
|
|
51
|
+
if (!plansConfigValue || plansConfigValue.type !== "json") {
|
|
52
|
+
throw new Error("Premium subscription plans config not found");
|
|
53
|
+
}
|
|
54
|
+
const json = safeParseJson(plansConfigValue.value);
|
|
55
|
+
try {
|
|
56
|
+
const plansConfig = Value.Parse(PlansConfig, json);
|
|
57
|
+
const plans = plansConfig["en-US"] ?? {};
|
|
58
|
+
return {
|
|
59
|
+
plans,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new Error("Premium subscription plans config is invalid", {
|
|
64
|
+
cause: error,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { parseDate } from "../../utils/date.js";
|
|
3
|
+
import { parseMeta } from "../../utils/parse_meta.js";
|
|
4
|
+
import { createCommand } from "../factory.js";
|
|
5
|
+
const meta = parseMeta(Type.Object({
|
|
6
|
+
name: Type.String(),
|
|
7
|
+
title: Type.String(),
|
|
8
|
+
description: Type.String(),
|
|
9
|
+
parameters: Type.Object({
|
|
10
|
+
order_uuid: Type.String(),
|
|
11
|
+
channel: Type.String(),
|
|
12
|
+
}),
|
|
13
|
+
}), import.meta);
|
|
14
|
+
export const payPremiumOrder = createCommand({
|
|
15
|
+
name: meta.name,
|
|
16
|
+
title: meta.title,
|
|
17
|
+
description: meta.description,
|
|
18
|
+
inputSchema: Type.Object({
|
|
19
|
+
order_uuid: Type.String({ description: meta.parameters.order_uuid }),
|
|
20
|
+
channel: Type.Union([Type.Literal("stripe-checkout")], {
|
|
21
|
+
description: meta.parameters.channel,
|
|
22
|
+
}),
|
|
23
|
+
}),
|
|
24
|
+
}, async ({ order_uuid, channel }, { apis }) => {
|
|
25
|
+
if (!apis.baseUrl.endsWith("talesofai.com")) {
|
|
26
|
+
throw new Error("This command is not supported in the current region");
|
|
27
|
+
}
|
|
28
|
+
const order = await apis.commerce.order({ order_uuid });
|
|
29
|
+
if (order.status !== "UNPAID") {
|
|
30
|
+
throw new Error("Order is not unpaid");
|
|
31
|
+
}
|
|
32
|
+
if (parseDate(order.valid_until).isBefore(Date.now())) {
|
|
33
|
+
throw new Error("Order is expired");
|
|
34
|
+
}
|
|
35
|
+
const result = await apis.commerce.pay({
|
|
36
|
+
order_uuid,
|
|
37
|
+
channel,
|
|
38
|
+
return_url: "https://app.neta.art/subscribe/callback",
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
checkout_session_url: result.checkout_session_url,
|
|
42
|
+
checkout_session_id: result.checkout_session_id,
|
|
43
|
+
};
|
|
44
|
+
});
|