@pablo2410/core-server 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 +245 -0
- package/dist/index.js +467 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal environment interface required by core-server utilities.
|
|
3
|
+
* Each subdomain provides its own ENV object that satisfies this shape.
|
|
4
|
+
*/
|
|
5
|
+
interface CoreEnv {
|
|
6
|
+
forgeApiUrl: string;
|
|
7
|
+
forgeApiKey: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Storage upload function signature.
|
|
11
|
+
* Subdomains provide their own storagePut implementation.
|
|
12
|
+
*/
|
|
13
|
+
type StoragePutFn = (key: string, data: Buffer | Uint8Array | string, contentType?: string) => Promise<{
|
|
14
|
+
key: string;
|
|
15
|
+
url: string;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Data API helper — calls the Manus built-in Data API Hub.
|
|
20
|
+
*
|
|
21
|
+
* Quick example:
|
|
22
|
+
* const callDataApi = createDataApiClient(ENV);
|
|
23
|
+
* await callDataApi("Youtube/search", {
|
|
24
|
+
* query: { gl: "US", hl: "en", q: "manus" },
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
type DataApiCallOptions = {
|
|
29
|
+
query?: Record<string, unknown>;
|
|
30
|
+
body?: Record<string, unknown>;
|
|
31
|
+
pathParams?: Record<string, unknown>;
|
|
32
|
+
formData?: Record<string, unknown>;
|
|
33
|
+
};
|
|
34
|
+
declare function createDataApiClient(env: CoreEnv): (apiId: string, options?: DataApiCallOptions) => Promise<unknown>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* LLM helper — calls the Manus built-in LLM API (OpenAI-compatible).
|
|
38
|
+
*
|
|
39
|
+
* Example:
|
|
40
|
+
* const invokeLLM = createLLMClient(ENV);
|
|
41
|
+
* const result = await invokeLLM({
|
|
42
|
+
* messages: [
|
|
43
|
+
* { role: "system", content: "You are a helpful assistant." },
|
|
44
|
+
* { role: "user", content: "Hello, world!" },
|
|
45
|
+
* ],
|
|
46
|
+
* });
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
type Role = "system" | "user" | "assistant" | "tool" | "function";
|
|
50
|
+
type TextContent = {
|
|
51
|
+
type: "text";
|
|
52
|
+
text: string;
|
|
53
|
+
};
|
|
54
|
+
type ImageContent = {
|
|
55
|
+
type: "image_url";
|
|
56
|
+
image_url: {
|
|
57
|
+
url: string;
|
|
58
|
+
detail?: "auto" | "low" | "high";
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
type FileContent = {
|
|
62
|
+
type: "file_url";
|
|
63
|
+
file_url: {
|
|
64
|
+
url: string;
|
|
65
|
+
mime_type?: "audio/mpeg" | "audio/wav" | "application/pdf" | "audio/mp4" | "video/mp4";
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
type MessageContent = string | TextContent | ImageContent | FileContent;
|
|
69
|
+
type Message = {
|
|
70
|
+
role: Role;
|
|
71
|
+
name?: string;
|
|
72
|
+
tool_call_id?: string;
|
|
73
|
+
content: MessageContent | MessageContent[];
|
|
74
|
+
};
|
|
75
|
+
type Tool = {
|
|
76
|
+
type: "function";
|
|
77
|
+
function: {
|
|
78
|
+
name: string;
|
|
79
|
+
description?: string;
|
|
80
|
+
parameters?: Record<string, unknown>;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
type ToolChoiceExplicit = {
|
|
84
|
+
type: "function";
|
|
85
|
+
function: {
|
|
86
|
+
name: string;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
type ToolChoice = "none" | "auto" | "required" | {
|
|
90
|
+
name: string;
|
|
91
|
+
} | ToolChoiceExplicit;
|
|
92
|
+
type JsonSchema = {
|
|
93
|
+
name: string;
|
|
94
|
+
schema: Record<string, unknown>;
|
|
95
|
+
strict?: boolean;
|
|
96
|
+
};
|
|
97
|
+
type ResponseFormat = {
|
|
98
|
+
type: "text";
|
|
99
|
+
} | {
|
|
100
|
+
type: "json_object";
|
|
101
|
+
} | {
|
|
102
|
+
type: "json_schema";
|
|
103
|
+
json_schema: JsonSchema;
|
|
104
|
+
};
|
|
105
|
+
type OutputSchema = {
|
|
106
|
+
name: string;
|
|
107
|
+
schema: Record<string, unknown>;
|
|
108
|
+
strict?: boolean;
|
|
109
|
+
};
|
|
110
|
+
type InvokeParams = {
|
|
111
|
+
messages: Message[];
|
|
112
|
+
tools?: Tool[];
|
|
113
|
+
toolChoice?: ToolChoice;
|
|
114
|
+
tool_choice?: ToolChoice;
|
|
115
|
+
outputSchema?: OutputSchema;
|
|
116
|
+
output_schema?: OutputSchema;
|
|
117
|
+
responseFormat?: ResponseFormat;
|
|
118
|
+
response_format?: ResponseFormat;
|
|
119
|
+
};
|
|
120
|
+
type InvokeResult = {
|
|
121
|
+
id: string;
|
|
122
|
+
object: string;
|
|
123
|
+
created: number;
|
|
124
|
+
model: string;
|
|
125
|
+
choices: Array<{
|
|
126
|
+
index: number;
|
|
127
|
+
message: {
|
|
128
|
+
role: string;
|
|
129
|
+
content: string | null;
|
|
130
|
+
tool_calls?: Array<{
|
|
131
|
+
id: string;
|
|
132
|
+
type: "function";
|
|
133
|
+
function: {
|
|
134
|
+
name: string;
|
|
135
|
+
arguments: string;
|
|
136
|
+
};
|
|
137
|
+
}>;
|
|
138
|
+
};
|
|
139
|
+
finish_reason: string;
|
|
140
|
+
}>;
|
|
141
|
+
usage?: {
|
|
142
|
+
prompt_tokens: number;
|
|
143
|
+
completion_tokens: number;
|
|
144
|
+
total_tokens: number;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
declare function createLLMClient(env: CoreEnv): (params: InvokeParams) => Promise<InvokeResult>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Image generation helper using internal ImageService.
|
|
151
|
+
*
|
|
152
|
+
* Example:
|
|
153
|
+
* import { storagePut } from "../storage";
|
|
154
|
+
* const generateImage = createImageGenerator(ENV, storagePut);
|
|
155
|
+
* const { url } = await generateImage({ prompt: "A serene landscape" });
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
type GenerateImageOptions = {
|
|
159
|
+
prompt: string;
|
|
160
|
+
originalImages?: Array<{
|
|
161
|
+
url?: string;
|
|
162
|
+
b64Json?: string;
|
|
163
|
+
mimeType?: string;
|
|
164
|
+
}>;
|
|
165
|
+
};
|
|
166
|
+
type GenerateImageResponse = {
|
|
167
|
+
url?: string;
|
|
168
|
+
};
|
|
169
|
+
declare function createImageGenerator(env: CoreEnv, storagePut: StoragePutFn): (options: GenerateImageOptions) => Promise<GenerateImageResponse>;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Google Maps API Integration for Manus WebDev Templates.
|
|
173
|
+
*
|
|
174
|
+
* Main function: createMapClient(env) returns makeRequest<T>(endpoint, params)
|
|
175
|
+
* All credentials are automatically injected. Array parameters use | as separator.
|
|
176
|
+
*
|
|
177
|
+
* Example:
|
|
178
|
+
* const makeRequest = createMapClient(ENV);
|
|
179
|
+
* const result = await makeRequest<GeocodeResult>(
|
|
180
|
+
* "/maps/api/geocode/json",
|
|
181
|
+
* { address: "1600 Amphitheatre Parkway" }
|
|
182
|
+
* );
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
type MapRequestParams = Record<string, string | number | boolean | string[] | undefined>;
|
|
186
|
+
declare function createMapClient(env: CoreEnv): <T = unknown>(endpoint: string, params?: MapRequestParams) => Promise<T>;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Owner notification helper — pushes operational updates to the Manus project owner.
|
|
190
|
+
*
|
|
191
|
+
* Example:
|
|
192
|
+
* const notifyOwner = createNotificationClient(ENV);
|
|
193
|
+
* await notifyOwner({ title: "New submission", content: "User X submitted form Y" });
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
type NotificationPayload = {
|
|
197
|
+
title: string;
|
|
198
|
+
content: string;
|
|
199
|
+
};
|
|
200
|
+
declare function createNotificationClient(env: CoreEnv): (payload: NotificationPayload) => Promise<boolean>;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Voice transcription helper using internal Speech-to-Text service (Whisper API).
|
|
204
|
+
*
|
|
205
|
+
* Example:
|
|
206
|
+
* const transcribeAudio = createTranscriptionClient(ENV);
|
|
207
|
+
* const result = await transcribeAudio({
|
|
208
|
+
* audioUrl: "https://storage.example.com/audio/recording.mp3",
|
|
209
|
+
* language: "en",
|
|
210
|
+
* });
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
type TranscribeOptions = {
|
|
214
|
+
audioUrl: string;
|
|
215
|
+
language?: string;
|
|
216
|
+
prompt?: string;
|
|
217
|
+
};
|
|
218
|
+
type WhisperSegment = {
|
|
219
|
+
id: number;
|
|
220
|
+
seek: number;
|
|
221
|
+
start: number;
|
|
222
|
+
end: number;
|
|
223
|
+
text: string;
|
|
224
|
+
tokens: number[];
|
|
225
|
+
temperature: number;
|
|
226
|
+
avg_logprob: number;
|
|
227
|
+
compression_ratio: number;
|
|
228
|
+
no_speech_prob: number;
|
|
229
|
+
};
|
|
230
|
+
type WhisperResponse = {
|
|
231
|
+
task: string;
|
|
232
|
+
language: string;
|
|
233
|
+
duration: number;
|
|
234
|
+
text: string;
|
|
235
|
+
segments: WhisperSegment[];
|
|
236
|
+
};
|
|
237
|
+
type TranscriptionError = {
|
|
238
|
+
error: string;
|
|
239
|
+
code: string;
|
|
240
|
+
details: string;
|
|
241
|
+
};
|
|
242
|
+
type TranscriptionResult = WhisperResponse | TranscriptionError;
|
|
243
|
+
declare function createTranscriptionClient(env: CoreEnv): (options: TranscribeOptions) => Promise<TranscriptionResult>;
|
|
244
|
+
|
|
245
|
+
export { type CoreEnv, type DataApiCallOptions, type FileContent, type GenerateImageOptions, type GenerateImageResponse, type ImageContent, type InvokeParams, type InvokeResult, type MapRequestParams, type Message, type MessageContent, type NotificationPayload, type OutputSchema, type ResponseFormat, type Role, type StoragePutFn, type TextContent, type Tool, type ToolChoice, type TranscribeOptions, type TranscriptionError, type TranscriptionResult, type WhisperResponse, type WhisperSegment, createDataApiClient, createImageGenerator, createLLMClient, createMapClient, createNotificationClient, createTranscriptionClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
// src/dataApi.ts
|
|
2
|
+
function createDataApiClient(env) {
|
|
3
|
+
return async function callDataApi(apiId, options = {}) {
|
|
4
|
+
if (!env.forgeApiUrl) {
|
|
5
|
+
throw new Error("BUILT_IN_FORGE_API_URL is not configured");
|
|
6
|
+
}
|
|
7
|
+
if (!env.forgeApiKey) {
|
|
8
|
+
throw new Error("BUILT_IN_FORGE_API_KEY is not configured");
|
|
9
|
+
}
|
|
10
|
+
const baseUrl = env.forgeApiUrl.endsWith("/") ? env.forgeApiUrl : `${env.forgeApiUrl}/`;
|
|
11
|
+
const fullUrl = new URL(
|
|
12
|
+
"webdevtoken.v1.WebDevService/CallApi",
|
|
13
|
+
baseUrl
|
|
14
|
+
).toString();
|
|
15
|
+
const response = await fetch(fullUrl, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
accept: "application/json",
|
|
19
|
+
"content-type": "application/json",
|
|
20
|
+
"connect-protocol-version": "1",
|
|
21
|
+
authorization: `Bearer ${env.forgeApiKey}`
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
apiId,
|
|
25
|
+
query: options.query,
|
|
26
|
+
body: options.body,
|
|
27
|
+
path_params: options.pathParams,
|
|
28
|
+
multipart_form_data: options.formData
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
const detail = await response.text().catch(() => "");
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Data API request failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const payload = await response.json().catch(() => ({}));
|
|
38
|
+
if (payload && typeof payload === "object" && "jsonData" in payload) {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(
|
|
41
|
+
payload.jsonData ?? "{}"
|
|
42
|
+
);
|
|
43
|
+
} catch {
|
|
44
|
+
return payload.jsonData;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return payload;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/llm.ts
|
|
52
|
+
var ensureArray = (value) => Array.isArray(value) ? value : [value];
|
|
53
|
+
var normalizeContentPart = (part) => {
|
|
54
|
+
if (typeof part === "string") {
|
|
55
|
+
return { type: "text", text: part };
|
|
56
|
+
}
|
|
57
|
+
if (part.type === "text") return part;
|
|
58
|
+
if (part.type === "image_url") return part;
|
|
59
|
+
if (part.type === "file_url") return part;
|
|
60
|
+
throw new Error("Unsupported message content part");
|
|
61
|
+
};
|
|
62
|
+
var normalizeMessage = (message) => {
|
|
63
|
+
const { role, name, tool_call_id } = message;
|
|
64
|
+
if (role === "tool" || role === "function") {
|
|
65
|
+
const content = ensureArray(message.content).map((part) => typeof part === "string" ? part : JSON.stringify(part)).join("\n");
|
|
66
|
+
return { role, name, tool_call_id, content };
|
|
67
|
+
}
|
|
68
|
+
const contentParts = ensureArray(message.content).map(normalizeContentPart);
|
|
69
|
+
if (contentParts.length === 1 && contentParts[0].type === "text") {
|
|
70
|
+
return { role, name, content: contentParts[0].text };
|
|
71
|
+
}
|
|
72
|
+
return { role, name, content: contentParts };
|
|
73
|
+
};
|
|
74
|
+
var normalizeToolChoice = (toolChoice, tools) => {
|
|
75
|
+
if (!toolChoice) return void 0;
|
|
76
|
+
if (toolChoice === "none" || toolChoice === "auto") return toolChoice;
|
|
77
|
+
if (toolChoice === "required") {
|
|
78
|
+
if (!tools || tools.length === 0) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
"tool_choice 'required' was provided but no tools were configured"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (tools.length > 1) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"tool_choice 'required' needs a single tool or specify the tool name explicitly"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return { type: "function", function: { name: tools[0].function.name } };
|
|
89
|
+
}
|
|
90
|
+
if ("name" in toolChoice) {
|
|
91
|
+
return { type: "function", function: { name: toolChoice.name } };
|
|
92
|
+
}
|
|
93
|
+
return toolChoice;
|
|
94
|
+
};
|
|
95
|
+
var normalizeResponseFormat = ({
|
|
96
|
+
responseFormat,
|
|
97
|
+
response_format,
|
|
98
|
+
outputSchema,
|
|
99
|
+
output_schema
|
|
100
|
+
}) => {
|
|
101
|
+
const explicitFormat = responseFormat || response_format;
|
|
102
|
+
if (explicitFormat) {
|
|
103
|
+
if (explicitFormat.type === "json_schema" && !explicitFormat.json_schema?.schema) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"responseFormat json_schema requires a defined schema object"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return explicitFormat;
|
|
109
|
+
}
|
|
110
|
+
const schema = outputSchema || output_schema;
|
|
111
|
+
if (!schema) return void 0;
|
|
112
|
+
if (!schema.name || !schema.schema) {
|
|
113
|
+
throw new Error("outputSchema requires both name and schema");
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
type: "json_schema",
|
|
117
|
+
json_schema: {
|
|
118
|
+
name: schema.name,
|
|
119
|
+
schema: schema.schema,
|
|
120
|
+
...typeof schema.strict === "boolean" ? { strict: schema.strict } : {}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
function createLLMClient(env) {
|
|
125
|
+
const resolveApiUrl = () => env.forgeApiUrl && env.forgeApiUrl.trim().length > 0 ? `${env.forgeApiUrl.replace(/\/$/, "")}/v1/chat/completions` : "https://forge.manus.im/v1/chat/completions";
|
|
126
|
+
const assertApiKey = () => {
|
|
127
|
+
if (!env.forgeApiKey) {
|
|
128
|
+
throw new Error("OPENAI_API_KEY is not configured");
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
return async function invokeLLM(params) {
|
|
132
|
+
assertApiKey();
|
|
133
|
+
const {
|
|
134
|
+
messages,
|
|
135
|
+
tools,
|
|
136
|
+
toolChoice,
|
|
137
|
+
tool_choice,
|
|
138
|
+
outputSchema,
|
|
139
|
+
output_schema,
|
|
140
|
+
responseFormat,
|
|
141
|
+
response_format
|
|
142
|
+
} = params;
|
|
143
|
+
const payload = {
|
|
144
|
+
model: "gemini-2.5-flash",
|
|
145
|
+
messages: messages.map(normalizeMessage)
|
|
146
|
+
};
|
|
147
|
+
if (tools && tools.length > 0) {
|
|
148
|
+
payload.tools = tools;
|
|
149
|
+
}
|
|
150
|
+
const normalizedToolChoice = normalizeToolChoice(
|
|
151
|
+
toolChoice || tool_choice,
|
|
152
|
+
tools
|
|
153
|
+
);
|
|
154
|
+
if (normalizedToolChoice) {
|
|
155
|
+
payload.tool_choice = normalizedToolChoice;
|
|
156
|
+
}
|
|
157
|
+
payload.max_tokens = 32768;
|
|
158
|
+
payload.thinking = { budget_tokens: 128 };
|
|
159
|
+
const normalizedResponseFormat = normalizeResponseFormat({
|
|
160
|
+
responseFormat,
|
|
161
|
+
response_format,
|
|
162
|
+
outputSchema,
|
|
163
|
+
output_schema
|
|
164
|
+
});
|
|
165
|
+
if (normalizedResponseFormat) {
|
|
166
|
+
payload.response_format = normalizedResponseFormat;
|
|
167
|
+
}
|
|
168
|
+
const response = await fetch(resolveApiUrl(), {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: {
|
|
171
|
+
"content-type": "application/json",
|
|
172
|
+
authorization: `Bearer ${env.forgeApiKey}`
|
|
173
|
+
},
|
|
174
|
+
body: JSON.stringify(payload)
|
|
175
|
+
});
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
const errorText = await response.text();
|
|
178
|
+
throw new Error(
|
|
179
|
+
`LLM invoke failed: ${response.status} ${response.statusText} \u2013 ${errorText}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
return await response.json();
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/imageGeneration.ts
|
|
187
|
+
function createImageGenerator(env, storagePut) {
|
|
188
|
+
return async function generateImage(options) {
|
|
189
|
+
if (!env.forgeApiUrl) {
|
|
190
|
+
throw new Error("BUILT_IN_FORGE_API_URL is not configured");
|
|
191
|
+
}
|
|
192
|
+
if (!env.forgeApiKey) {
|
|
193
|
+
throw new Error("BUILT_IN_FORGE_API_KEY is not configured");
|
|
194
|
+
}
|
|
195
|
+
const baseUrl = env.forgeApiUrl.endsWith("/") ? env.forgeApiUrl : `${env.forgeApiUrl}/`;
|
|
196
|
+
const fullUrl = new URL(
|
|
197
|
+
"images.v1.ImageService/GenerateImage",
|
|
198
|
+
baseUrl
|
|
199
|
+
).toString();
|
|
200
|
+
const response = await fetch(fullUrl, {
|
|
201
|
+
method: "POST",
|
|
202
|
+
headers: {
|
|
203
|
+
accept: "application/json",
|
|
204
|
+
"content-type": "application/json",
|
|
205
|
+
"connect-protocol-version": "1",
|
|
206
|
+
authorization: `Bearer ${env.forgeApiKey}`
|
|
207
|
+
},
|
|
208
|
+
body: JSON.stringify({
|
|
209
|
+
prompt: options.prompt,
|
|
210
|
+
original_images: options.originalImages || []
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
if (!response.ok) {
|
|
214
|
+
const detail = await response.text().catch(() => "");
|
|
215
|
+
throw new Error(
|
|
216
|
+
`Image generation request failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const result = await response.json();
|
|
220
|
+
const base64Data = result.image.b64Json;
|
|
221
|
+
const buffer = Buffer.from(base64Data, "base64");
|
|
222
|
+
const { url } = await storagePut(
|
|
223
|
+
`generated/${Date.now()}.png`,
|
|
224
|
+
buffer,
|
|
225
|
+
result.image.mimeType
|
|
226
|
+
);
|
|
227
|
+
return { url };
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/map.ts
|
|
232
|
+
function createMapClient(env) {
|
|
233
|
+
return async function makeRequest(endpoint, params = {}) {
|
|
234
|
+
if (!env.forgeApiUrl) {
|
|
235
|
+
throw new Error("BUILT_IN_FORGE_API_URL is not configured");
|
|
236
|
+
}
|
|
237
|
+
if (!env.forgeApiKey) {
|
|
238
|
+
throw new Error("BUILT_IN_FORGE_API_KEY is not configured");
|
|
239
|
+
}
|
|
240
|
+
const baseUrl = env.forgeApiUrl.endsWith("/") ? env.forgeApiUrl : `${env.forgeApiUrl}/`;
|
|
241
|
+
const proxyUrl = new URL(
|
|
242
|
+
"webdevtoken.v1.WebDevService/GoogleMapsProxy",
|
|
243
|
+
baseUrl
|
|
244
|
+
).toString();
|
|
245
|
+
const processedParams = {};
|
|
246
|
+
for (const [key, value] of Object.entries(params)) {
|
|
247
|
+
if (value === void 0) continue;
|
|
248
|
+
if (Array.isArray(value)) {
|
|
249
|
+
processedParams[key] = value.join("|");
|
|
250
|
+
} else {
|
|
251
|
+
processedParams[key] = String(value);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const response = await fetch(proxyUrl, {
|
|
255
|
+
method: "POST",
|
|
256
|
+
headers: {
|
|
257
|
+
accept: "application/json",
|
|
258
|
+
"content-type": "application/json",
|
|
259
|
+
"connect-protocol-version": "1",
|
|
260
|
+
authorization: `Bearer ${env.forgeApiKey}`
|
|
261
|
+
},
|
|
262
|
+
body: JSON.stringify({
|
|
263
|
+
endpoint,
|
|
264
|
+
params: processedParams
|
|
265
|
+
})
|
|
266
|
+
});
|
|
267
|
+
if (!response.ok) {
|
|
268
|
+
const detail = await response.text().catch(() => "");
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Maps API request failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : ""}`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
const wrapper = await response.json();
|
|
274
|
+
if (wrapper.jsonData) {
|
|
275
|
+
try {
|
|
276
|
+
return JSON.parse(wrapper.jsonData);
|
|
277
|
+
} catch {
|
|
278
|
+
return wrapper.jsonData;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return wrapper;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/notification.ts
|
|
286
|
+
var TITLE_MAX_LENGTH = 1200;
|
|
287
|
+
var CONTENT_MAX_LENGTH = 2e4;
|
|
288
|
+
function createNotificationClient(env) {
|
|
289
|
+
return async function notifyOwner(payload) {
|
|
290
|
+
if (!env.forgeApiUrl) {
|
|
291
|
+
throw new Error("BUILT_IN_FORGE_API_URL is not configured");
|
|
292
|
+
}
|
|
293
|
+
if (!env.forgeApiKey) {
|
|
294
|
+
throw new Error("BUILT_IN_FORGE_API_KEY is not configured");
|
|
295
|
+
}
|
|
296
|
+
const title = payload.title.length > TITLE_MAX_LENGTH ? payload.title.slice(0, TITLE_MAX_LENGTH) : payload.title;
|
|
297
|
+
const content = payload.content.length > CONTENT_MAX_LENGTH ? payload.content.slice(0, CONTENT_MAX_LENGTH) : payload.content;
|
|
298
|
+
const baseUrl = env.forgeApiUrl.endsWith("/") ? env.forgeApiUrl : `${env.forgeApiUrl}/`;
|
|
299
|
+
const fullUrl = new URL(
|
|
300
|
+
"webdevtoken.v1.WebDevService/NotifyOwner",
|
|
301
|
+
baseUrl
|
|
302
|
+
).toString();
|
|
303
|
+
try {
|
|
304
|
+
const response = await fetch(fullUrl, {
|
|
305
|
+
method: "POST",
|
|
306
|
+
headers: {
|
|
307
|
+
accept: "application/json",
|
|
308
|
+
"content-type": "application/json",
|
|
309
|
+
"connect-protocol-version": "1",
|
|
310
|
+
authorization: `Bearer ${env.forgeApiKey}`
|
|
311
|
+
},
|
|
312
|
+
body: JSON.stringify({ title, content })
|
|
313
|
+
});
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
console.error(
|
|
316
|
+
`Notification failed: ${response.status} ${response.statusText}`
|
|
317
|
+
);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error("Notification error:", error);
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/voiceTranscription.ts
|
|
329
|
+
var SUPPORTED_MIME_TYPES = [
|
|
330
|
+
"audio/webm",
|
|
331
|
+
"audio/mp3",
|
|
332
|
+
"audio/mpeg",
|
|
333
|
+
"audio/wav",
|
|
334
|
+
"audio/wave",
|
|
335
|
+
"audio/ogg",
|
|
336
|
+
"audio/m4a",
|
|
337
|
+
"audio/mp4"
|
|
338
|
+
];
|
|
339
|
+
function getFileExtension(mimeType) {
|
|
340
|
+
const mimeToExt = {
|
|
341
|
+
"audio/webm": "webm",
|
|
342
|
+
"audio/mp3": "mp3",
|
|
343
|
+
"audio/mpeg": "mp3",
|
|
344
|
+
"audio/wav": "wav",
|
|
345
|
+
"audio/wave": "wav",
|
|
346
|
+
"audio/ogg": "ogg",
|
|
347
|
+
"audio/m4a": "m4a",
|
|
348
|
+
"audio/mp4": "m4a"
|
|
349
|
+
};
|
|
350
|
+
return mimeToExt[mimeType] || "audio";
|
|
351
|
+
}
|
|
352
|
+
function getLanguageName(langCode) {
|
|
353
|
+
const langMap = {
|
|
354
|
+
en: "English",
|
|
355
|
+
es: "Spanish",
|
|
356
|
+
fr: "French",
|
|
357
|
+
de: "German",
|
|
358
|
+
it: "Italian",
|
|
359
|
+
pt: "Portuguese",
|
|
360
|
+
ru: "Russian",
|
|
361
|
+
ja: "Japanese",
|
|
362
|
+
ko: "Korean",
|
|
363
|
+
zh: "Chinese",
|
|
364
|
+
ar: "Arabic",
|
|
365
|
+
hi: "Hindi",
|
|
366
|
+
nl: "Dutch",
|
|
367
|
+
pl: "Polish",
|
|
368
|
+
tr: "Turkish",
|
|
369
|
+
sv: "Swedish",
|
|
370
|
+
da: "Danish",
|
|
371
|
+
no: "Norwegian",
|
|
372
|
+
fi: "Finnish"
|
|
373
|
+
};
|
|
374
|
+
return langMap[langCode] || langCode;
|
|
375
|
+
}
|
|
376
|
+
function createTranscriptionClient(env) {
|
|
377
|
+
return async function transcribeAudio(options) {
|
|
378
|
+
try {
|
|
379
|
+
if (!env.forgeApiUrl) {
|
|
380
|
+
throw new Error("BUILT_IN_FORGE_API_URL is not configured");
|
|
381
|
+
}
|
|
382
|
+
if (!env.forgeApiKey) {
|
|
383
|
+
throw new Error("BUILT_IN_FORGE_API_KEY is not configured");
|
|
384
|
+
}
|
|
385
|
+
const audioResponse = await fetch(options.audioUrl);
|
|
386
|
+
if (!audioResponse.ok) {
|
|
387
|
+
return {
|
|
388
|
+
error: "Failed to fetch audio file",
|
|
389
|
+
code: "FETCH_FAILED",
|
|
390
|
+
details: `HTTP ${audioResponse.status} ${audioResponse.statusText}`
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
const contentType = audioResponse.headers.get("content-type") || "audio/webm";
|
|
394
|
+
const mimeType = contentType.split(";")[0].trim();
|
|
395
|
+
if (!SUPPORTED_MIME_TYPES.includes(
|
|
396
|
+
mimeType
|
|
397
|
+
)) {
|
|
398
|
+
return {
|
|
399
|
+
error: "Unsupported audio format",
|
|
400
|
+
code: "UNSUPPORTED_FORMAT",
|
|
401
|
+
details: `MIME type '${mimeType}' is not supported. Supported: ${SUPPORTED_MIME_TYPES.join(", ")}`
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const audioBuffer = await audioResponse.arrayBuffer();
|
|
405
|
+
const sizeMB = audioBuffer.byteLength / (1024 * 1024);
|
|
406
|
+
if (sizeMB > 16) {
|
|
407
|
+
return {
|
|
408
|
+
error: "Audio file exceeds maximum size limit",
|
|
409
|
+
code: "FILE_TOO_LARGE",
|
|
410
|
+
details: `File size is ${sizeMB.toFixed(2)}MB, maximum allowed is 16MB`
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
const formData = new FormData();
|
|
414
|
+
const filename = `audio.${getFileExtension(mimeType)}`;
|
|
415
|
+
const audioBlob = new Blob([new Uint8Array(audioBuffer)], {
|
|
416
|
+
type: mimeType
|
|
417
|
+
});
|
|
418
|
+
formData.append("file", audioBlob, filename);
|
|
419
|
+
formData.append("model", "whisper-1");
|
|
420
|
+
formData.append("response_format", "verbose_json");
|
|
421
|
+
const prompt = options.prompt || (options.language ? `Transcribe the user's voice to text, the user's working language is ${getLanguageName(options.language)}` : "Transcribe the user's voice to text");
|
|
422
|
+
formData.append("prompt", prompt);
|
|
423
|
+
const baseUrl = env.forgeApiUrl.endsWith("/") ? env.forgeApiUrl : `${env.forgeApiUrl}/`;
|
|
424
|
+
const fullUrl = new URL("v1/audio/transcriptions", baseUrl).toString();
|
|
425
|
+
const response = await fetch(fullUrl, {
|
|
426
|
+
method: "POST",
|
|
427
|
+
headers: {
|
|
428
|
+
authorization: `Bearer ${env.forgeApiKey}`,
|
|
429
|
+
"Accept-Encoding": "identity"
|
|
430
|
+
},
|
|
431
|
+
body: formData
|
|
432
|
+
});
|
|
433
|
+
if (!response.ok) {
|
|
434
|
+
const errorText = await response.text().catch(() => "");
|
|
435
|
+
return {
|
|
436
|
+
error: "Transcription service request failed",
|
|
437
|
+
code: "TRANSCRIPTION_FAILED",
|
|
438
|
+
details: `${response.status} ${response.statusText}${errorText ? `: ${errorText}` : ""}`
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
const whisperResponse = await response.json();
|
|
442
|
+
if (!whisperResponse.text || typeof whisperResponse.text !== "string") {
|
|
443
|
+
return {
|
|
444
|
+
error: "Invalid transcription response",
|
|
445
|
+
code: "SERVICE_ERROR",
|
|
446
|
+
details: "Transcription service returned an invalid response format"
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return whisperResponse;
|
|
450
|
+
} catch (error) {
|
|
451
|
+
return {
|
|
452
|
+
error: "Voice transcription failed",
|
|
453
|
+
code: "SERVICE_ERROR",
|
|
454
|
+
details: error instanceof Error ? error.message : "An unexpected error occurred"
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
export {
|
|
460
|
+
createDataApiClient,
|
|
461
|
+
createImageGenerator,
|
|
462
|
+
createLLMClient,
|
|
463
|
+
createMapClient,
|
|
464
|
+
createNotificationClient,
|
|
465
|
+
createTranscriptionClient
|
|
466
|
+
};
|
|
467
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dataApi.ts","../src/llm.ts","../src/imageGeneration.ts","../src/map.ts","../src/notification.ts","../src/voiceTranscription.ts"],"sourcesContent":["/**\n * Data API helper — calls the Manus built-in Data API Hub.\n *\n * Quick example:\n * const callDataApi = createDataApiClient(ENV);\n * await callDataApi(\"Youtube/search\", {\n * query: { gl: \"US\", hl: \"en\", q: \"manus\" },\n * });\n */\nimport type { CoreEnv } from \"./types\";\n\nexport type DataApiCallOptions = {\n query?: Record<string, unknown>;\n body?: Record<string, unknown>;\n pathParams?: Record<string, unknown>;\n formData?: Record<string, unknown>;\n};\n\nexport function createDataApiClient(env: CoreEnv) {\n return async function callDataApi(\n apiId: string,\n options: DataApiCallOptions = {}\n ): Promise<unknown> {\n if (!env.forgeApiUrl) {\n throw new Error(\"BUILT_IN_FORGE_API_URL is not configured\");\n }\n if (!env.forgeApiKey) {\n throw new Error(\"BUILT_IN_FORGE_API_KEY is not configured\");\n }\n\n const baseUrl = env.forgeApiUrl.endsWith(\"/\")\n ? env.forgeApiUrl\n : `${env.forgeApiUrl}/`;\n const fullUrl = new URL(\n \"webdevtoken.v1.WebDevService/CallApi\",\n baseUrl\n ).toString();\n\n const response = await fetch(fullUrl, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n \"connect-protocol-version\": \"1\",\n authorization: `Bearer ${env.forgeApiKey}`,\n },\n body: JSON.stringify({\n apiId,\n query: options.query,\n body: options.body,\n path_params: options.pathParams,\n multipart_form_data: options.formData,\n }),\n });\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Data API request failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : \"\"}`\n );\n }\n\n const payload = await response.json().catch(() => ({}));\n if (payload && typeof payload === \"object\" && \"jsonData\" in payload) {\n try {\n return JSON.parse(\n (payload as Record<string, string>).jsonData ?? \"{}\"\n );\n } catch {\n return (payload as Record<string, unknown>).jsonData;\n }\n }\n return payload;\n };\n}\n","/**\n * LLM helper — calls the Manus built-in LLM API (OpenAI-compatible).\n *\n * Example:\n * const invokeLLM = createLLMClient(ENV);\n * const result = await invokeLLM({\n * messages: [\n * { role: \"system\", content: \"You are a helpful assistant.\" },\n * { role: \"user\", content: \"Hello, world!\" },\n * ],\n * });\n */\nimport type { CoreEnv } from \"./types\";\n\nexport type Role = \"system\" | \"user\" | \"assistant\" | \"tool\" | \"function\";\n\nexport type TextContent = {\n type: \"text\";\n text: string;\n};\n\nexport type ImageContent = {\n type: \"image_url\";\n image_url: {\n url: string;\n detail?: \"auto\" | \"low\" | \"high\";\n };\n};\n\nexport type FileContent = {\n type: \"file_url\";\n file_url: {\n url: string;\n mime_type?:\n | \"audio/mpeg\"\n | \"audio/wav\"\n | \"application/pdf\"\n | \"audio/mp4\"\n | \"video/mp4\";\n };\n};\n\nexport type MessageContent = string | TextContent | ImageContent | FileContent;\n\nexport type Message = {\n role: Role;\n name?: string;\n tool_call_id?: string;\n content: MessageContent | MessageContent[];\n};\n\nexport type Tool = {\n type: \"function\";\n function: {\n name: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n};\n\ntype ToolChoiceExplicit = {\n type: \"function\";\n function: { name: string };\n};\n\nexport type ToolChoice =\n | \"none\"\n | \"auto\"\n | \"required\"\n | { name: string }\n | ToolChoiceExplicit;\n\ntype JsonSchema = {\n name: string;\n schema: Record<string, unknown>;\n strict?: boolean;\n};\n\nexport type ResponseFormat =\n | { type: \"text\" }\n | { type: \"json_object\" }\n | { type: \"json_schema\"; json_schema: JsonSchema };\n\nexport type OutputSchema = {\n name: string;\n schema: Record<string, unknown>;\n strict?: boolean;\n};\n\nexport type InvokeParams = {\n messages: Message[];\n tools?: Tool[];\n toolChoice?: ToolChoice;\n tool_choice?: ToolChoice;\n outputSchema?: OutputSchema;\n output_schema?: OutputSchema;\n responseFormat?: ResponseFormat;\n response_format?: ResponseFormat;\n};\n\nexport type InvokeResult = {\n id: string;\n object: string;\n created: number;\n model: string;\n choices: Array<{\n index: number;\n message: {\n role: string;\n content: string | null;\n tool_calls?: Array<{\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason: string;\n }>;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n };\n};\n\nconst ensureArray = (\n value: MessageContent | MessageContent[]\n): MessageContent[] => (Array.isArray(value) ? value : [value]);\n\nconst normalizeContentPart = (\n part: MessageContent\n): TextContent | ImageContent | FileContent => {\n if (typeof part === \"string\") {\n return { type: \"text\", text: part };\n }\n if (part.type === \"text\") return part;\n if (part.type === \"image_url\") return part;\n if (part.type === \"file_url\") return part;\n throw new Error(\"Unsupported message content part\");\n};\n\nconst normalizeMessage = (message: Message) => {\n const { role, name, tool_call_id } = message;\n if (role === \"tool\" || role === \"function\") {\n const content = ensureArray(message.content)\n .map((part) => (typeof part === \"string\" ? part : JSON.stringify(part)))\n .join(\"\\n\");\n return { role, name, tool_call_id, content };\n }\n const contentParts = ensureArray(message.content).map(normalizeContentPart);\n if (contentParts.length === 1 && contentParts[0].type === \"text\") {\n return { role, name, content: contentParts[0].text };\n }\n return { role, name, content: contentParts };\n};\n\nconst normalizeToolChoice = (\n toolChoice: ToolChoice | undefined,\n tools: Tool[] | undefined\n): \"none\" | \"auto\" | ToolChoiceExplicit | undefined => {\n if (!toolChoice) return undefined;\n if (toolChoice === \"none\" || toolChoice === \"auto\") return toolChoice;\n if (toolChoice === \"required\") {\n if (!tools || tools.length === 0) {\n throw new Error(\n \"tool_choice 'required' was provided but no tools were configured\"\n );\n }\n if (tools.length > 1) {\n throw new Error(\n \"tool_choice 'required' needs a single tool or specify the tool name explicitly\"\n );\n }\n return { type: \"function\", function: { name: tools[0].function.name } };\n }\n if (\"name\" in toolChoice) {\n return { type: \"function\", function: { name: toolChoice.name } };\n }\n return toolChoice;\n};\n\nconst normalizeResponseFormat = ({\n responseFormat,\n response_format,\n outputSchema,\n output_schema,\n}: {\n responseFormat?: ResponseFormat;\n response_format?: ResponseFormat;\n outputSchema?: OutputSchema;\n output_schema?: OutputSchema;\n}):\n | { type: \"json_schema\"; json_schema: JsonSchema }\n | { type: \"text\" }\n | { type: \"json_object\" }\n | undefined => {\n const explicitFormat = responseFormat || response_format;\n if (explicitFormat) {\n if (\n explicitFormat.type === \"json_schema\" &&\n !explicitFormat.json_schema?.schema\n ) {\n throw new Error(\n \"responseFormat json_schema requires a defined schema object\"\n );\n }\n return explicitFormat;\n }\n const schema = outputSchema || output_schema;\n if (!schema) return undefined;\n if (!schema.name || !schema.schema) {\n throw new Error(\"outputSchema requires both name and schema\");\n }\n return {\n type: \"json_schema\",\n json_schema: {\n name: schema.name,\n schema: schema.schema,\n ...(typeof schema.strict === \"boolean\" ? { strict: schema.strict } : {}),\n },\n };\n};\n\nexport function createLLMClient(env: CoreEnv) {\n const resolveApiUrl = () =>\n env.forgeApiUrl && env.forgeApiUrl.trim().length > 0\n ? `${env.forgeApiUrl.replace(/\\/$/, \"\")}/v1/chat/completions`\n : \"https://forge.manus.im/v1/chat/completions\";\n\n const assertApiKey = () => {\n if (!env.forgeApiKey) {\n throw new Error(\"OPENAI_API_KEY is not configured\");\n }\n };\n\n return async function invokeLLM(\n params: InvokeParams\n ): Promise<InvokeResult> {\n assertApiKey();\n\n const {\n messages,\n tools,\n toolChoice,\n tool_choice,\n outputSchema,\n output_schema,\n responseFormat,\n response_format,\n } = params;\n\n const payload: Record<string, unknown> = {\n model: \"gemini-2.5-flash\",\n messages: messages.map(normalizeMessage),\n };\n\n if (tools && tools.length > 0) {\n payload.tools = tools;\n }\n\n const normalizedToolChoice = normalizeToolChoice(\n toolChoice || tool_choice,\n tools\n );\n if (normalizedToolChoice) {\n payload.tool_choice = normalizedToolChoice;\n }\n\n payload.max_tokens = 32768;\n payload.thinking = { budget_tokens: 128 };\n\n const normalizedResponseFormat = normalizeResponseFormat({\n responseFormat,\n response_format,\n outputSchema,\n output_schema,\n });\n if (normalizedResponseFormat) {\n payload.response_format = normalizedResponseFormat;\n }\n\n const response = await fetch(resolveApiUrl(), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${env.forgeApiKey}`,\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `LLM invoke failed: ${response.status} ${response.statusText} – ${errorText}`\n );\n }\n\n return (await response.json()) as InvokeResult;\n };\n}\n","/**\n * Image generation helper using internal ImageService.\n *\n * Example:\n * import { storagePut } from \"../storage\";\n * const generateImage = createImageGenerator(ENV, storagePut);\n * const { url } = await generateImage({ prompt: \"A serene landscape\" });\n */\nimport type { CoreEnv, StoragePutFn } from \"./types\";\n\nexport type GenerateImageOptions = {\n prompt: string;\n originalImages?: Array<{\n url?: string;\n b64Json?: string;\n mimeType?: string;\n }>;\n};\n\nexport type GenerateImageResponse = {\n url?: string;\n};\n\nexport function createImageGenerator(env: CoreEnv, storagePut: StoragePutFn) {\n return async function generateImage(\n options: GenerateImageOptions\n ): Promise<GenerateImageResponse> {\n if (!env.forgeApiUrl) {\n throw new Error(\"BUILT_IN_FORGE_API_URL is not configured\");\n }\n if (!env.forgeApiKey) {\n throw new Error(\"BUILT_IN_FORGE_API_KEY is not configured\");\n }\n\n const baseUrl = env.forgeApiUrl.endsWith(\"/\")\n ? env.forgeApiUrl\n : `${env.forgeApiUrl}/`;\n const fullUrl = new URL(\n \"images.v1.ImageService/GenerateImage\",\n baseUrl\n ).toString();\n\n const response = await fetch(fullUrl, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n \"connect-protocol-version\": \"1\",\n authorization: `Bearer ${env.forgeApiKey}`,\n },\n body: JSON.stringify({\n prompt: options.prompt,\n original_images: options.originalImages || [],\n }),\n });\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Image generation request failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : \"\"}`\n );\n }\n\n const result = (await response.json()) as {\n image: {\n b64Json: string;\n mimeType: string;\n };\n };\n\n const base64Data = result.image.b64Json;\n const buffer = Buffer.from(base64Data, \"base64\");\n\n const { url } = await storagePut(\n `generated/${Date.now()}.png`,\n buffer,\n result.image.mimeType\n );\n\n return { url };\n };\n}\n","/**\n * Google Maps API Integration for Manus WebDev Templates.\n *\n * Main function: createMapClient(env) returns makeRequest<T>(endpoint, params)\n * All credentials are automatically injected. Array parameters use | as separator.\n *\n * Example:\n * const makeRequest = createMapClient(ENV);\n * const result = await makeRequest<GeocodeResult>(\n * \"/maps/api/geocode/json\",\n * { address: \"1600 Amphitheatre Parkway\" }\n * );\n */\nimport type { CoreEnv } from \"./types\";\n\nexport type MapRequestParams = Record<\n string,\n string | number | boolean | string[] | undefined\n>;\n\nexport function createMapClient(env: CoreEnv) {\n return async function makeRequest<T = unknown>(\n endpoint: string,\n params: MapRequestParams = {}\n ): Promise<T> {\n if (!env.forgeApiUrl) {\n throw new Error(\"BUILT_IN_FORGE_API_URL is not configured\");\n }\n if (!env.forgeApiKey) {\n throw new Error(\"BUILT_IN_FORGE_API_KEY is not configured\");\n }\n\n const baseUrl = env.forgeApiUrl.endsWith(\"/\")\n ? env.forgeApiUrl\n : `${env.forgeApiUrl}/`;\n const proxyUrl = new URL(\n \"webdevtoken.v1.WebDevService/GoogleMapsProxy\",\n baseUrl\n ).toString();\n\n const processedParams: Record<string, string> = {};\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n processedParams[key] = value.join(\"|\");\n } else {\n processedParams[key] = String(value);\n }\n }\n\n const response = await fetch(proxyUrl, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n \"connect-protocol-version\": \"1\",\n authorization: `Bearer ${env.forgeApiKey}`,\n },\n body: JSON.stringify({\n endpoint,\n params: processedParams,\n }),\n });\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Maps API request failed (${response.status} ${response.statusText})${detail ? `: ${detail}` : \"\"}`\n );\n }\n\n const wrapper = (await response.json()) as { jsonData?: string };\n if (wrapper.jsonData) {\n try {\n return JSON.parse(wrapper.jsonData) as T;\n } catch {\n return wrapper.jsonData as unknown as T;\n }\n }\n return wrapper as unknown as T;\n };\n}\n","/**\n * Owner notification helper — pushes operational updates to the Manus project owner.\n *\n * Example:\n * const notifyOwner = createNotificationClient(ENV);\n * await notifyOwner({ title: \"New submission\", content: \"User X submitted form Y\" });\n */\nimport type { CoreEnv } from \"./types\";\n\nexport type NotificationPayload = {\n title: string;\n content: string;\n};\n\nconst TITLE_MAX_LENGTH = 1200;\nconst CONTENT_MAX_LENGTH = 20000;\n\nexport function createNotificationClient(env: CoreEnv) {\n return async function notifyOwner(\n payload: NotificationPayload\n ): Promise<boolean> {\n if (!env.forgeApiUrl) {\n throw new Error(\"BUILT_IN_FORGE_API_URL is not configured\");\n }\n if (!env.forgeApiKey) {\n throw new Error(\"BUILT_IN_FORGE_API_KEY is not configured\");\n }\n\n const title =\n payload.title.length > TITLE_MAX_LENGTH\n ? payload.title.slice(0, TITLE_MAX_LENGTH)\n : payload.title;\n const content =\n payload.content.length > CONTENT_MAX_LENGTH\n ? payload.content.slice(0, CONTENT_MAX_LENGTH)\n : payload.content;\n\n const baseUrl = env.forgeApiUrl.endsWith(\"/\")\n ? env.forgeApiUrl\n : `${env.forgeApiUrl}/`;\n const fullUrl = new URL(\n \"webdevtoken.v1.WebDevService/NotifyOwner\",\n baseUrl\n ).toString();\n\n try {\n const response = await fetch(fullUrl, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n \"connect-protocol-version\": \"1\",\n authorization: `Bearer ${env.forgeApiKey}`,\n },\n body: JSON.stringify({ title, content }),\n });\n\n if (!response.ok) {\n console.error(\n `Notification failed: ${response.status} ${response.statusText}`\n );\n return false;\n }\n return true;\n } catch (error) {\n console.error(\"Notification error:\", error);\n return false;\n }\n };\n}\n","/**\n * Voice transcription helper using internal Speech-to-Text service (Whisper API).\n *\n * Example:\n * const transcribeAudio = createTranscriptionClient(ENV);\n * const result = await transcribeAudio({\n * audioUrl: \"https://storage.example.com/audio/recording.mp3\",\n * language: \"en\",\n * });\n */\nimport type { CoreEnv } from \"./types\";\n\nexport type TranscribeOptions = {\n audioUrl: string;\n language?: string;\n prompt?: string;\n};\n\nexport type WhisperSegment = {\n id: number;\n seek: number;\n start: number;\n end: number;\n text: string;\n tokens: number[];\n temperature: number;\n avg_logprob: number;\n compression_ratio: number;\n no_speech_prob: number;\n};\n\nexport type WhisperResponse = {\n task: string;\n language: string;\n duration: number;\n text: string;\n segments: WhisperSegment[];\n};\n\nexport type TranscriptionError = {\n error: string;\n code: string;\n details: string;\n};\n\nexport type TranscriptionResult = WhisperResponse | TranscriptionError;\n\nconst SUPPORTED_MIME_TYPES = [\n \"audio/webm\",\n \"audio/mp3\",\n \"audio/mpeg\",\n \"audio/wav\",\n \"audio/wave\",\n \"audio/ogg\",\n \"audio/m4a\",\n \"audio/mp4\",\n] as const;\n\nfunction getFileExtension(mimeType: string): string {\n const mimeToExt: Record<string, string> = {\n \"audio/webm\": \"webm\",\n \"audio/mp3\": \"mp3\",\n \"audio/mpeg\": \"mp3\",\n \"audio/wav\": \"wav\",\n \"audio/wave\": \"wav\",\n \"audio/ogg\": \"ogg\",\n \"audio/m4a\": \"m4a\",\n \"audio/mp4\": \"m4a\",\n };\n return mimeToExt[mimeType] || \"audio\";\n}\n\nfunction getLanguageName(langCode: string): string {\n const langMap: Record<string, string> = {\n en: \"English\",\n es: \"Spanish\",\n fr: \"French\",\n de: \"German\",\n it: \"Italian\",\n pt: \"Portuguese\",\n ru: \"Russian\",\n ja: \"Japanese\",\n ko: \"Korean\",\n zh: \"Chinese\",\n ar: \"Arabic\",\n hi: \"Hindi\",\n nl: \"Dutch\",\n pl: \"Polish\",\n tr: \"Turkish\",\n sv: \"Swedish\",\n da: \"Danish\",\n no: \"Norwegian\",\n fi: \"Finnish\",\n };\n return langMap[langCode] || langCode;\n}\n\nexport function createTranscriptionClient(env: CoreEnv) {\n return async function transcribeAudio(\n options: TranscribeOptions\n ): Promise<TranscriptionResult> {\n try {\n if (!env.forgeApiUrl) {\n throw new Error(\"BUILT_IN_FORGE_API_URL is not configured\");\n }\n if (!env.forgeApiKey) {\n throw new Error(\"BUILT_IN_FORGE_API_KEY is not configured\");\n }\n\n // Step 1: Fetch the audio file to determine MIME type and validate\n const audioResponse = await fetch(options.audioUrl);\n if (!audioResponse.ok) {\n return {\n error: \"Failed to fetch audio file\",\n code: \"FETCH_FAILED\",\n details: `HTTP ${audioResponse.status} ${audioResponse.statusText}`,\n };\n }\n\n const contentType =\n audioResponse.headers.get(\"content-type\") || \"audio/webm\";\n const mimeType = contentType.split(\";\")[0].trim();\n\n if (\n !SUPPORTED_MIME_TYPES.includes(\n mimeType as (typeof SUPPORTED_MIME_TYPES)[number]\n )\n ) {\n return {\n error: \"Unsupported audio format\",\n code: \"UNSUPPORTED_FORMAT\",\n details: `MIME type '${mimeType}' is not supported. Supported: ${SUPPORTED_MIME_TYPES.join(\", \")}`,\n };\n }\n\n // Step 2: Read audio buffer and check size\n const audioBuffer = await audioResponse.arrayBuffer();\n const sizeMB = audioBuffer.byteLength / (1024 * 1024);\n if (sizeMB > 16) {\n return {\n error: \"Audio file exceeds maximum size limit\",\n code: \"FILE_TOO_LARGE\",\n details: `File size is ${sizeMB.toFixed(2)}MB, maximum allowed is 16MB`,\n };\n }\n\n // Step 3: Create FormData for multipart upload to Whisper API\n const formData = new FormData();\n const filename = `audio.${getFileExtension(mimeType)}`;\n const audioBlob = new Blob([new Uint8Array(audioBuffer)], {\n type: mimeType,\n });\n formData.append(\"file\", audioBlob, filename);\n formData.append(\"model\", \"whisper-1\");\n formData.append(\"response_format\", \"verbose_json\");\n\n const prompt =\n options.prompt ||\n (options.language\n ? `Transcribe the user's voice to text, the user's working language is ${getLanguageName(options.language)}`\n : \"Transcribe the user's voice to text\");\n formData.append(\"prompt\", prompt);\n\n // Step 4: Call the transcription service\n const baseUrl = env.forgeApiUrl.endsWith(\"/\")\n ? env.forgeApiUrl\n : `${env.forgeApiUrl}/`;\n const fullUrl = new URL(\"v1/audio/transcriptions\", baseUrl).toString();\n\n const response = await fetch(fullUrl, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${env.forgeApiKey}`,\n \"Accept-Encoding\": \"identity\",\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n return {\n error: \"Transcription service request failed\",\n code: \"TRANSCRIPTION_FAILED\",\n details: `${response.status} ${response.statusText}${errorText ? `: ${errorText}` : \"\"}`,\n };\n }\n\n // Step 5: Parse and return the transcription result\n const whisperResponse = (await response.json()) as WhisperResponse;\n\n if (\n !whisperResponse.text ||\n typeof whisperResponse.text !== \"string\"\n ) {\n return {\n error: \"Invalid transcription response\",\n code: \"SERVICE_ERROR\",\n details:\n \"Transcription service returned an invalid response format\",\n };\n }\n\n return whisperResponse;\n } catch (error) {\n return {\n error: \"Voice transcription failed\",\n code: \"SERVICE_ERROR\",\n details:\n error instanceof Error\n ? error.message\n : \"An unexpected error occurred\",\n };\n }\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pablo2410/core-server",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Shared server utilities for Oplytics.digital subdomains",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"prepare": "pnpm build"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/Pablo2410/oplytics-core-server"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^25.5.0",
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"typescript": "^5.6.0",
|
|
32
|
+
"vitest": "^3.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@trpc/server": ">=11.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|