@monkey-mini-app/api 0.1.4
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/README.md +21 -0
- package/dist/index.js +7 -0
- package/package.json +35 -0
- package/src/index.ts +160 -0
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @monkey-mini-app/api
|
|
2
|
+
|
|
3
|
+
Backend authoring contract for mini-apps (`main.api.ts`).
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { defineApp } from "@monkey-mini-app/api";
|
|
7
|
+
|
|
8
|
+
export default defineApp({
|
|
9
|
+
name: "…",
|
|
10
|
+
description: "…",
|
|
11
|
+
api: {
|
|
12
|
+
async list(ctx) {
|
|
13
|
+
return (await ctx.storage.get("items")) ?? [];
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Runtime:** the host injects `defineApp` when loading `main.api.ts` — this package is for **types / IDE / `pnpm check:templates`**. Do not expect Node to load React from here; there is none.
|
|
20
|
+
|
|
21
|
+
UI authors use `@monkey-mini-app/ui` (`useApp` + components), not this package.
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@monkey-mini-app/api",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Mini-app backend author contract: defineApp + AppCtx types (host injects runtime)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./src/index.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./src/index.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "node ../../scripts/build/api.mjs",
|
|
22
|
+
"prepack": "node ../../scripts/build/api.mjs"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"esbuild": "^0.28.2",
|
|
26
|
+
"typescript": "~5.9.2"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend authoring contract for mini-apps (`main.api.ts`).
|
|
3
|
+
*
|
|
4
|
+
* The host does **not** load this package into the backend process — when it
|
|
5
|
+
* loads `main.api.ts` it injects `defineApp`. Import from `@monkey-mini-app/api`
|
|
6
|
+
* for editor help and type-checking; the object you get at runtime comes from
|
|
7
|
+
* the host (it validates `name` / `description` / `api`).
|
|
8
|
+
*
|
|
9
|
+
* Human-readable contract: skill `references/ctx.md`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** File-backed key/value store scoped to one mini-app (`storage/*.json`). */
|
|
13
|
+
export type AppStorage = {
|
|
14
|
+
/** Stored JSON — shape is yours; the host hands back whatever was written. */
|
|
15
|
+
get(key: string): Promise<any>;
|
|
16
|
+
set(key: string, value: unknown): Promise<void>;
|
|
17
|
+
delete(key: string): Promise<void>;
|
|
18
|
+
clear(): Promise<void>;
|
|
19
|
+
/** Bytes this table occupies on disk. Cheap, and meant for "is my data getting big" checks. */
|
|
20
|
+
bytes(): number;
|
|
21
|
+
/**
|
|
22
|
+
* A second, independent table in the same app (`storage/<name>.storage.json`). Keys do not
|
|
23
|
+
* overlap between tables, and neither layout choice here is yours to make: the host moves a
|
|
24
|
+
* table to one file per key once it stops fitting a single rewrite, which is invisible from
|
|
25
|
+
* this API — `get` / `set` / `delete` / `clear` mean the same thing either way.
|
|
26
|
+
*/
|
|
27
|
+
table(name: string): AppStorage;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** `ctx.http` request shape (either positional fields or `url` + opts). */
|
|
31
|
+
export type AppHttpRequest = {
|
|
32
|
+
url: string;
|
|
33
|
+
method?: string;
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
query?: Record<string, string | number | boolean | null | undefined>;
|
|
36
|
+
body?: unknown;
|
|
37
|
+
timeout?: number;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** `ctx.http` result — always this shape, never a platform `Response`. */
|
|
42
|
+
export type AppHttpResponse = {
|
|
43
|
+
ok: boolean;
|
|
44
|
+
status: number;
|
|
45
|
+
headers: Record<string, string>;
|
|
46
|
+
text: string;
|
|
47
|
+
/** Parsed body when the response was JSON, else `null`. */
|
|
48
|
+
json: any;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Options shared by `ctx.llm` and `ctx.agent`. */
|
|
52
|
+
export type AppModelOptions = {
|
|
53
|
+
provider?: string;
|
|
54
|
+
model?: string;
|
|
55
|
+
system?: string;
|
|
56
|
+
schema?: unknown;
|
|
57
|
+
maxTokens?: number;
|
|
58
|
+
/** Attempts in total, including the first. Default 3 (`llm`); `agent` defaults to 1. */
|
|
59
|
+
retryTimes?: number;
|
|
60
|
+
signal?: AbortSignal;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Why a turn ended — kept loose so hosts can add kinds without breaking apps. */
|
|
64
|
+
export type AppAgentTurnEndReason = {
|
|
65
|
+
kind: string;
|
|
66
|
+
error?: unknown;
|
|
67
|
+
reason?: unknown;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** One `ctx.agent` progress event (observation only — the return stays a string). */
|
|
71
|
+
export type AppAgentEvent =
|
|
72
|
+
| { type: "status"; status: "running" | "idle" }
|
|
73
|
+
| { type: "text-delta"; text: string }
|
|
74
|
+
| { type: "tool"; phase: "start" | "end"; name: string; args?: unknown; result?: unknown }
|
|
75
|
+
| { type: "turn"; phase: "start"; turn: number }
|
|
76
|
+
| { type: "turn"; phase: "end"; turn: number; reason?: AppAgentTurnEndReason }
|
|
77
|
+
| { type: "error"; message: string }
|
|
78
|
+
| { type: "done"; text: string };
|
|
79
|
+
|
|
80
|
+
/** `ctx.agent` options (adds the multi-step knobs on top of the shared ones). */
|
|
81
|
+
export type AppAgentOptions = AppModelOptions & {
|
|
82
|
+
maxIterations?: number;
|
|
83
|
+
onEvent?: (event: AppAgentEvent) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Mirror every progress event to the UI as `ctx.push(streamTo, event)` — so a
|
|
86
|
+
* run started before the panel opened still streams (the host replays it).
|
|
87
|
+
*/
|
|
88
|
+
streamTo?: string;
|
|
89
|
+
cwdType?: "app" | "process" | "temp" | "custom";
|
|
90
|
+
cwd?: string;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** First argument of every `api` method. */
|
|
94
|
+
export type AppCtx = {
|
|
95
|
+
/** Reverse-DNS id of the running mini-app. */
|
|
96
|
+
appId: string;
|
|
97
|
+
/** Absolute `runtime/apps/<appId>` directory. */
|
|
98
|
+
appDir: string;
|
|
99
|
+
storage: AppStorage;
|
|
100
|
+
state: Record<string, unknown>;
|
|
101
|
+
credentials: Record<string, string>;
|
|
102
|
+
log(...args: unknown[]): void;
|
|
103
|
+
/**
|
|
104
|
+
* Push one event to this app's open views; the UI reads it with
|
|
105
|
+
* `useApp().on(name, cb)`. Fire-and-forget: never throws, and `params` must be
|
|
106
|
+
* JSON-serialisable (unsuitable payloads are dropped with a host warning).
|
|
107
|
+
* Buffered per app (last 200) so a reconnecting or late-opening UI replays.
|
|
108
|
+
*/
|
|
109
|
+
push(name: string, params?: unknown): void;
|
|
110
|
+
mcp(name: string, args?: Record<string, unknown>): Promise<any>;
|
|
111
|
+
/** Tool result as a **string** (the host serialises tool output). */
|
|
112
|
+
tool(name: string, args?: Record<string, unknown>): Promise<any>;
|
|
113
|
+
listTools(): unknown[];
|
|
114
|
+
/** Model completion as a **string**. */
|
|
115
|
+
llm(prompt: string, opts?: AppModelOptions): Promise<string>;
|
|
116
|
+
/** Multi-step agent run as a **string**. */
|
|
117
|
+
agent(goal: string, opts?: AppAgentOptions): Promise<string>;
|
|
118
|
+
bash(command: string): Promise<{ stdout: string; stderr: string; exitCode: number }>;
|
|
119
|
+
http(url: string | AppHttpRequest, opts?: Omit<AppHttpRequest, "url">): Promise<AppHttpResponse>;
|
|
120
|
+
system: { metrics(): Promise<any> };
|
|
121
|
+
config: Record<string, unknown>;
|
|
122
|
+
/** Cancel signal for the current call — long jobs must honour it. */
|
|
123
|
+
signal?: AbortSignal;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* One backend method. `args` is whatever `call(method, args)` sent from the UI
|
|
128
|
+
* (a plain object) — validate it, it is untrusted input.
|
|
129
|
+
*/
|
|
130
|
+
export type AppApiMethod = (ctx: AppCtx, args: any) => unknown | Promise<unknown>;
|
|
131
|
+
|
|
132
|
+
/** What `defineApp` takes — the whole `main.api.ts` contract. */
|
|
133
|
+
export type AppDefinition = {
|
|
134
|
+
name: string;
|
|
135
|
+
description: string;
|
|
136
|
+
api: Record<string, AppApiMethod>;
|
|
137
|
+
state?: Record<string, unknown>;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Declare the mini-app backend. Keys of `api` are exactly the `method` strings
|
|
142
|
+
* the UI may `call()`.
|
|
143
|
+
*
|
|
144
|
+
* ```ts
|
|
145
|
+
* import { defineApp } from "@monkey-mini-app/api";
|
|
146
|
+
*
|
|
147
|
+
* export default defineApp({
|
|
148
|
+
* name: "名称",
|
|
149
|
+
* description: "一句话",
|
|
150
|
+
* api: {
|
|
151
|
+
* async list(ctx) {
|
|
152
|
+
* return (await ctx.storage.get("items")) ?? [];
|
|
153
|
+
* },
|
|
154
|
+
* },
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function defineApp<T extends AppDefinition>(def: T): T {
|
|
159
|
+
return def;
|
|
160
|
+
}
|