@vectorx/functions-framework 0.0.0-beta-20260108133839 → 0.0.0-beta-20260320063305

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 CHANGED
@@ -136,6 +136,34 @@ npm test
136
136
  npm run build
137
137
  ```
138
138
 
139
-
140
139
  ### 环境管理
141
140
  读取 .env 文件,校验 env 文件的可用性,获取当前运行环境
141
+
142
+
143
+ ## rcb-ff 自动检测项目类型
144
+
145
+ 当直接使用 `rcb-ff` 命令启动服务时,如果未指定 `--mode` 参数,会自动检测项目类型:
146
+
147
+ ### 检测规则
148
+
149
+ 1. **Agent 项目检测**:
150
+ - 如果存在 `project.config.json` 文件且包含 `agentId` 字段,则判定为 `agent` 项目
151
+
152
+ 2. **Fun 项目检测**:
153
+ - 如果不存在 `project.config.json` 或 `project.config.json` 中不存在 `agentId` 字段
154
+ - 且存在 `agent-cloudbase-functions.json` 配置文件
155
+ - 则判定为 `fun` 项目
156
+
157
+ 3. **默认行为**:
158
+ - 如果无法确定项目类型,默认使用 `agent` 模式(保持向后兼容)
159
+
160
+ ### 使用示例
161
+
162
+ ```bash
163
+ # 自动检测项目类型(推荐)
164
+ rcb-ff --directory ./my-project
165
+
166
+ # 明确指定模式(覆盖自动检测)
167
+ rcb-ff --directory ./my-project --mode fun
168
+ rcb-ff --directory ./my-project --mode agent
169
+ ```
package/bin/rcb-ff.js CHANGED
@@ -7,6 +7,40 @@ const fs = require('fs');
7
7
  const nodemon = require('nodemon');
8
8
  const chalk = require('chalk');
9
9
 
10
+ /**
11
+ * 自动检测项目类型(agent 或 fun)
12
+ * 参考 fun-project-validator.ts 的检测逻辑
13
+ * @param {string} workDir 工作目录
14
+ * @returns {string} 'agent' | 'fun'
15
+ */
16
+ function detectProjectMode(workDir) {
17
+ const projectConfigPath = path.join(workDir, 'project.config.json');
18
+
19
+ // 检查是否存在 project.config.json 且包含 agentId
20
+ if (fs.existsSync(projectConfigPath)) {
21
+ try {
22
+ const projectConfig = JSON.parse(fs.readFileSync(projectConfigPath, 'utf-8'));
23
+ if (projectConfig.agentId) {
24
+ // 存在 agentId,判定为 agent 项目
25
+ return 'agent';
26
+ }
27
+ } catch (error) {
28
+ // project.config.json 解析失败,继续检测
29
+ }
30
+ }
31
+
32
+ // 检查是否存在 agent-cloudbase-functions.json
33
+ const functionsConfigPath = path.join(workDir, 'agent-cloudbase-functions.json');
34
+ if (fs.existsSync(functionsConfigPath)) {
35
+ // 不存在 project.config.json 或不存在 agentId,但存在 agent-cloudbase-functions.json
36
+ // 判定为 fun 项目
37
+ return 'fun';
38
+ }
39
+
40
+ // 默认返回 agent(保持向后兼容)
41
+ return 'agent';
42
+ }
43
+
10
44
  const program = new Command();
11
45
 
12
46
  program
@@ -20,13 +54,22 @@ program
20
54
  .option('--enable-cors', '启用 CORS')
21
55
  .option('--allowed-origins <origins>', 'CORS 允许的域名,用逗号分隔', 'localhost,127.0.0.1')
22
56
  .option('--config <path>', '指定配置文件路径', 'agent-cloudbase-functions.json')
57
+ .option('--mode <mode>', '运行模式: agent | fun(未指定时自动检测)')
23
58
  .option('--enableRedLangfuse', '启用 Red Langfuse 上报')
59
+ .option('--verbose', '输出详细错误堆栈(用于排查问题)')
24
60
  .option('-w, --watch', '启用文件监听模式,文件变化时自动重启服务');
25
61
 
26
62
  program.parse();
27
63
 
28
64
  const options = program.opts();
29
65
 
66
+ // 如果未明确指定 mode,则自动检测
67
+ if (!options.mode) {
68
+ const detectedMode = detectProjectMode(path.resolve(options.directory));
69
+ options.mode = detectedMode;
70
+ console.log(chalk.dim(`[自动检测] 项目类型: ${detectedMode}`));
71
+ }
72
+
30
73
  async function startServer() {
31
74
  try {
32
75
  // 解析并验证目录路径
@@ -46,6 +89,7 @@ async function startServer() {
46
89
  functionsConfigFile: path.resolve(directory, options.config),
47
90
  enableCors: options.enableCors,
48
91
  allowedOrigins: options.allowedOrigins.split(','),
92
+ mode: options.mode === 'fun' ? 'fun' : 'agent',
49
93
  redLangfuseConfig: {
50
94
  enable: Boolean(options.enableRedLangfuse),
51
95
  },
@@ -74,6 +118,7 @@ async function startServer() {
74
118
  // 使用独立的控制台实例打印启动信息
75
119
  startupConsole.log('\n\n' + chalk.bold.cyan(' === RCB Functions Framework ==='));
76
120
  startupConsole.log(`${chalk.green('✔')} ${chalk.bold('状态')}: ${chalk.green('运行中')}`);
121
+ startupConsole.log(`${chalk.green('✔')} ${chalk.bold('模式')}: ${chalk.yellow(frameworkOptions.mode)}`);
77
122
  startupConsole.log(`${chalk.green('✔')} ${chalk.bold('端口')}: ${chalk.yellow(frameworkOptions.port)}`);
78
123
  startupConsole.log(`${chalk.green('✔')} ${chalk.bold('URL')}: ${chalk.blue.underline(`http://localhost:${frameworkOptions.port}`)}`);
79
124
  startupConsole.log(`${chalk.green('✔')} ${chalk.bold('目标函数')}: ${chalk.yellow(frameworkOptions.target)}`);
@@ -111,7 +156,14 @@ async function startServer() {
111
156
  });
112
157
 
113
158
  } catch (err) {
114
- console.error('启动服务器失败:', err);
159
+ // 默认只输出友好错误信息(避免堆栈刷屏);需要排查时可通过 --verbose 输出完整堆栈
160
+ const message = (err && err.message) ? err.message : String(err);
161
+ console.error('启动服务器失败:');
162
+ console.error(message);
163
+ if (options.verbose) {
164
+ const stack = (err && err.stack) ? err.stack : '';
165
+ if (stack) console.error(stack);
166
+ }
115
167
  process.exit(1);
116
168
  }
117
169
  }
package/lib/config.js CHANGED
@@ -1,10 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getBaseUrl = getBaseUrl;
4
- const ENV_BASE_URL = {
5
- development: "https://agentbase-sandbox.xiaohongshu.com",
6
- production: "https://agentbase.xiaohongshu.com",
7
- };
4
+ const endpoints_1 = require("@vectorx/endpoints");
8
5
  function getBaseUrl() {
9
- return ENV_BASE_URL[process.env.OPEN_PLATFORM_STAGE] || ENV_BASE_URL.development;
6
+ return (0, endpoints_1.resolveUrl)("@vectorx/functions-framework", "baseUrl");
10
7
  }
package/lib/constants.js CHANGED
@@ -7,4 +7,5 @@ exports.defaultOptions = {
7
7
  keepAliveTimeoutMS: 25000,
8
8
  functionsConfigFile: "agent-cloudbase-functions.json",
9
9
  enableCors: false,
10
+ mode: "agent",
10
11
  };
package/lib/error.js CHANGED
@@ -30,18 +30,26 @@ function decorateErrorStack(err) {
30
30
  return err.stack.split("\n").join("\n");
31
31
  }
32
32
  function newSysErr(err) {
33
- return new AppError(ErrorCode.SYS_ERR, "System Error.", { cause: err });
33
+ return new AppError(ErrorCode.SYS_ERR, "System Error.", {
34
+ cause: err,
35
+ });
34
36
  }
35
37
  function newBadRequestErr(err) {
36
38
  const message = err instanceof Error ? err.message : err;
37
39
  return new AppError(ErrorCode.BAD_REQUEST, message, { cause: err });
38
40
  }
39
41
  function newTimeoutErr() {
40
- return new AppError(ErrorCode.TIMEOUT, "Request timeout", { cause: new Error("Request timeout") });
42
+ return new AppError(ErrorCode.TIMEOUT, "Request timeout", {
43
+ cause: new Error("Request timeout"),
44
+ });
41
45
  }
42
46
  function newTooManyRequestsErr(err) {
43
- return new AppError(ErrorCode.TOO_MANY_REQUESTS, "Too many requests", { cause: err });
47
+ return new AppError(ErrorCode.TOO_MANY_REQUESTS, "Too many requests", {
48
+ cause: err,
49
+ });
44
50
  }
45
51
  function newUnauthorizedErr(err) {
46
- return new AppError(ErrorCode.UNAUTHORIZED, "Unauthorized", { cause: err });
52
+ return new AppError(ErrorCode.UNAUTHORIZED, "Unauthorized", {
53
+ cause: err,
54
+ });
47
55
  }
package/lib/framework.js CHANGED
@@ -28,7 +28,9 @@ const apm_1 = require("./utils/apm");
28
28
  const console_intercept_1 = require("./utils/console-intercept");
29
29
  function getDependencyVersion(packageName, searchPath) {
30
30
  try {
31
- const packagePath = require.resolve(packageName, { paths: [searchPath] });
31
+ const packagePath = require.resolve(packageName, {
32
+ paths: [searchPath],
33
+ });
32
34
  let currentPath = path_1.default.dirname(packagePath);
33
35
  let packageJsonPath = path_1.default.join(currentPath, "package.json");
34
36
  while (!(0, fs_1.existsSync)(packageJsonPath) && currentPath !== path_1.default.parse(currentPath).root) {
@@ -73,8 +75,9 @@ class AgentServerFramework {
73
75
  }
74
76
  startServer() {
75
77
  return __awaiter(this, void 0, void 0, function* () {
76
- const { functionsConfigFile } = this.options;
78
+ const { functionsConfigFile, mode = "agent" } = this.options;
77
79
  let cloudFunctionConfig;
80
+ let projectConfig;
78
81
  if (!process.env.OPEN_PLATFORM_STAGE) {
79
82
  process.stdout.write(chalk_1.default.yellow(`未设置 OPEN_PLATFORM_STAGE 环境变量,使用默认值: development\n`));
80
83
  process.env.OPEN_PLATFORM_STAGE = "development";
@@ -84,10 +87,14 @@ class AgentServerFramework {
84
87
  const stageEnvFilePath = path_1.default.join(process.cwd(), `.env.${stage}`);
85
88
  let dotEnvContent;
86
89
  if ((0, fs_1.existsSync)(defaultEnvFilePath)) {
87
- dotEnvContent = dotenv_1.default.config({ path: path_1.default.resolve(defaultEnvFilePath) });
90
+ dotEnvContent = dotenv_1.default.config({
91
+ path: path_1.default.resolve(defaultEnvFilePath),
92
+ });
88
93
  }
89
94
  else if ((0, fs_1.existsSync)(stageEnvFilePath)) {
90
- dotEnvContent = dotenv_1.default.config({ path: path_1.default.resolve(stageEnvFilePath) });
95
+ dotEnvContent = dotenv_1.default.config({
96
+ path: path_1.default.resolve(stageEnvFilePath),
97
+ });
91
98
  }
92
99
  if (dotEnvContent && dotEnvContent.parsed) {
93
100
  const envKeys = Object.keys(dotEnvContent.parsed);
@@ -100,9 +107,27 @@ class AgentServerFramework {
100
107
  }
101
108
  });
102
109
  }
103
- const projectConfigPath = path_1.default.join(process.cwd(), "project.config.json");
104
- if (!(0, fs_1.existsSync)(projectConfigPath)) {
105
- throw new Error(`
110
+ if (mode === "agent") {
111
+ ({ projectConfig, cloudFunctionConfig } = this.loadAgentModeConfigs(functionsConfigFile));
112
+ }
113
+ else {
114
+ ({ projectConfig, cloudFunctionConfig } = this.loadFunModeConfigs(functionsConfigFile));
115
+ }
116
+ this.router = new router_1.Router(cloudFunctionConfig);
117
+ const server = (0, server_1.createServer)(this.options, this.router, projectConfig);
118
+ return server;
119
+ });
120
+ }
121
+ getRegisteredFunction(fnName) {
122
+ const fnId = (0, function_registry_1.buildFnId)("@fn", fnName);
123
+ return (0, function_registry_1.getRegisteredFunction)(fnId);
124
+ }
125
+ loadAgentModeConfigs(functionsConfigFile) {
126
+ const projectConfigPath = path_1.default.join(process.cwd(), "project.config.json");
127
+ if (!(0, fs_1.existsSync)(projectConfigPath)) {
128
+ const funConfigPath = path_1.default.join(process.cwd(), "agent-cloudbase-functions.json");
129
+ const maybeFunProject = (0, fs_1.existsSync)(funConfigPath);
130
+ throw new Error(`
106
131
  ❌ 项目配置文件未找到: ${projectConfigPath}
107
132
 
108
133
  请确保:
@@ -113,11 +138,23 @@ class AgentServerFramework {
113
138
  "version": "0.0.1",
114
139
  "desc": "发布示例",
115
140
  }
116
- `);
117
- }
118
- const projectConfig = require(projectConfigPath);
119
- if (!(0, fs_1.existsSync)(functionsConfigFile)) {
120
- throw new Error(`
141
+ ${maybeFunProject
142
+ ? `
143
+ 💡 诊断提示:
144
+ - 检测到当前目录存在云函数配置文件(agent-cloudbase-functions.json)
145
+ - 这可能是一个“云函数(fun)项目”目录,但你使用了“智能体(agent)模式”启动
146
+
147
+ 建议你:
148
+ - 改用 fun 模式启动(例如:rcb-ff --mode fun ... 或使用 rcb fun dev)
149
+ - 或切换到正确的 Agent 项目目录后再启动
150
+
151
+ 参考文档:https://miniapp.xiaohongshu.com/doc/DC185638
152
+ `
153
+ : ""}`);
154
+ }
155
+ const projectConfig = require(projectConfigPath);
156
+ if (!(0, fs_1.existsSync)(functionsConfigFile)) {
157
+ throw new Error(`
121
158
  ❌ 配置文件未找到: ${functionsConfigFile}
122
159
 
123
160
  请确保:
@@ -135,13 +172,42 @@ class AgentServerFramework {
135
172
  ]
136
173
  }
137
174
  `);
175
+ }
176
+ const cloudFunctionConfig = this.loadAndRegisterFunctions(functionsConfigFile, "agent");
177
+ return { projectConfig, cloudFunctionConfig };
178
+ }
179
+ loadFunModeConfigs(functionsConfigFile) {
180
+ if (!(0, fs_1.existsSync)(functionsConfigFile)) {
181
+ throw new Error(`
182
+ ❌ 函数配置文件未找到: ${functionsConfigFile}
183
+
184
+ 请确保:
185
+ 1. 配置文件 'agent-cloudbase-functions.json' 存在于项目根目录
186
+ 2. 配置文件格式正确,且 functions 字段已正确配置
187
+ `);
188
+ }
189
+ const cloudFunctionConfig = this.loadAndRegisterFunctions(functionsConfigFile, "fun");
190
+ const projectConfig = {
191
+ agentId: cloudFunctionConfig.agentId || "local-fun",
192
+ version: "0.0.0-local",
193
+ desc: "Local functions development (fun mode)",
194
+ name: "local-fun",
195
+ "@vectorx/agent-runtime": getDependencyVersion("@vectorx/agent-runtime", process.cwd()) || "",
196
+ "@vectorx/functions-framework": getDependencyVersion("@vectorx/functions-framework", process.cwd()) || "",
197
+ };
198
+ return { projectConfig, cloudFunctionConfig };
199
+ }
200
+ loadAndRegisterFunctions(functionsConfigFile, mode) {
201
+ try {
202
+ const cloudFunctionConfig = (0, function_loader_1.loadFunctionsConfig)(functionsConfigFile);
203
+ const fns = cloudFunctionConfig.functions || [];
204
+ if (!Array.isArray(fns) || fns.length === 0) {
205
+ throw new Error("functions 配置为空,请至少配置一个函数");
138
206
  }
139
- try {
140
- cloudFunctionConfig = (0, function_loader_1.loadFunctionsConfig)(functionsConfigFile);
141
- for (const fn of cloudFunctionConfig.functions) {
142
- const mainFn = (0, function_loader_1.loadFunction)(cloudFunctionConfig.functionsRoot, fn);
143
- if (!mainFn) {
144
- throw new Error(`
207
+ for (const fn of fns) {
208
+ const mainFn = (0, function_loader_1.loadFunction)(cloudFunctionConfig.functionsRoot, fn);
209
+ if (!mainFn) {
210
+ throw new Error(`
145
211
  ❌ 函数加载失败: ${fn.name}
146
212
 
147
213
  请检查:
@@ -149,14 +215,14 @@ class AgentServerFramework {
149
215
  2. 源文件是否存在: ${fn.source}
150
216
  3. 函数是否正确导出
151
217
  `);
152
- }
153
- (0, function_registry_1.registerFunction)(fn.name, mainFn);
154
218
  }
155
- this.router = new router_1.Router(cloudFunctionConfig);
219
+ (0, function_registry_1.registerFunction)(fn.name, mainFn);
156
220
  }
157
- catch (err) {
158
- throw new Error(`
159
- 函数配置加载失败
221
+ return cloudFunctionConfig;
222
+ }
223
+ catch (err) {
224
+ throw new Error(`
225
+ ❌ 函数配置加载失败(${mode} 模式)
160
226
 
161
227
  错误详情: ${err}
162
228
 
@@ -167,13 +233,7 @@ class AgentServerFramework {
167
233
 
168
234
  配置文件路径: ${functionsConfigFile}
169
235
  `);
170
- }
171
- const server = (0, server_1.createServer)(this.options, this.router, projectConfig);
172
- return server;
173
- });
174
- }
175
- getRegisteredFunction(fnName) {
176
- return (0, function_registry_1.getRegisteredFunction)(fnName);
236
+ }
177
237
  }
178
238
  }
179
239
  function createAgentServerFramework(options) {
@@ -30,7 +30,10 @@ function loadFunctionsConfig(configPath) {
30
30
  throw new Error(`Route '${fn.triggerPath}->${fn.name}' conflict with '${fn.triggerPath}->${existsTriggerFnName}', please check your functions config`);
31
31
  }
32
32
  }
33
- config.routes.push({ functionName: fn.name, path: fn.triggerPath });
33
+ config.routes.push({
34
+ functionName: fn.name,
35
+ path: fn.triggerPath,
36
+ });
34
37
  routeMaps.set(fn.triggerPath, fn.name);
35
38
  }
36
39
  }
@@ -45,7 +48,8 @@ function loadFunction(functionsRoot, functionConfig) {
45
48
  if (!functionConfig.source) {
46
49
  functionConfig.source = exports.DEFAULT_FN_NAME;
47
50
  }
48
- const indexPath = (0, path_1.join)(functionsRoot, functionConfig.source);
51
+ const directory = functionConfig.directory || ".";
52
+ const indexPath = (0, path_1.join)(functionsRoot, directory, functionConfig.source);
49
53
  if (!(0, fs_1.existsSync)(indexPath)) {
50
54
  throw new Error(`Function entry file not found at: ${indexPath}, functionConfig: ${JSON.stringify(functionConfig)}`);
51
55
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildFnId = buildFnId;
4
4
  exports.registerFunction = registerFunction;
5
5
  exports.getRegisteredFunction = getRegisteredFunction;
6
+ exports.getAllRegisteredFunctions = getAllRegisteredFunctions;
6
7
  exports.clearRegistry = clearRegistry;
7
8
  const functionRegistry = new Map();
8
9
  function buildFnId(fnName, functionName) {
@@ -15,6 +16,13 @@ function registerFunction(fnName, fn) {
15
16
  function getRegisteredFunction(fnId) {
16
17
  return functionRegistry.get(fnId);
17
18
  }
19
+ function getAllRegisteredFunctions() {
20
+ const result = [];
21
+ functionRegistry.forEach((fn, fnId) => {
22
+ result.push({ name: fnId, userFunction: fn });
23
+ });
24
+ return result;
25
+ }
18
26
  function clearRegistry() {
19
27
  functionRegistry.clear();
20
28
  }
@@ -50,10 +50,62 @@ const request_1 = require("./request");
50
50
  const sse_1 = require("./sse");
51
51
  const unified_responder_1 = require("./unified-responder");
52
52
  const helper_1 = require("./utils/helper");
53
+ const isPlainObject = (val) => {
54
+ if (!val || typeof val !== "object")
55
+ return false;
56
+ const proto = Object.getPrototypeOf(val);
57
+ return proto === Object.prototype || proto === null;
58
+ };
59
+ const parseCookies = (cookieHeader) => {
60
+ const cookies = {};
61
+ if (!cookieHeader || typeof cookieHeader !== "string")
62
+ return cookies;
63
+ const parts = cookieHeader.split(";");
64
+ for (const part of parts) {
65
+ const s = part.trim();
66
+ if (!s)
67
+ continue;
68
+ const idx = s.indexOf("=");
69
+ if (idx === -1)
70
+ continue;
71
+ const key = s.slice(0, idx).trim();
72
+ const val = s.slice(idx + 1).trim();
73
+ if (!key)
74
+ continue;
75
+ try {
76
+ cookies[key] = decodeURIComponent(val);
77
+ }
78
+ catch (_a) {
79
+ cookies[key] = val;
80
+ }
81
+ }
82
+ return cookies;
83
+ };
84
+ const normalizeQuery = (query) => {
85
+ if (!query || typeof query !== "object")
86
+ return {};
87
+ return Object.assign({}, query);
88
+ };
89
+ const normalizeHeaders = (headers) => {
90
+ if (!headers || typeof headers !== "object")
91
+ return {};
92
+ const out = {};
93
+ for (const [k, v] of Object.entries(headers)) {
94
+ out[String(k).toLowerCase()] = v;
95
+ }
96
+ return out;
97
+ };
98
+ const resolveTrigger = (ctx) => {
99
+ var _a, _b;
100
+ const fromHeader = String(((_b = (_a = ctx.request) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b["xhs-cloud-trigger"]) || "").toLowerCase();
101
+ if (fromHeader === "online" || fromHeader === "ide_debug" || fromHeader === "console_debug")
102
+ return fromHeader;
103
+ return "online";
104
+ };
53
105
  const wrapEventFunction = (execute, projectConfig) => {
54
106
  return (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
55
- var _a;
56
- let event;
107
+ var _a, _b, _c, _d, _e;
108
+ let params;
57
109
  if (ctx.request.files) {
58
110
  const filesWithBuffer = {};
59
111
  const fs = yield Promise.resolve().then(() => __importStar(require("fs")));
@@ -79,21 +131,40 @@ const wrapEventFunction = (execute, projectConfig) => {
79
131
  })));
80
132
  filesWithBuffer[key] = Array.isArray(fileOrFiles) ? processedFiles : processedFiles[0];
81
133
  }
82
- event = Object.assign(Object.assign({}, filesWithBuffer), ctx.request.body);
134
+ const fields = isPlainObject(ctx.request.body) ? ctx.request.body : {};
135
+ params = Object.assign(Object.assign({}, fields), filesWithBuffer);
83
136
  }
84
- else if (ctx.request.body) {
85
- event = ctx.request.body;
137
+ else if (ctx.method === "GET" || ctx.method === "HEAD") {
138
+ params = ctx.query || {};
86
139
  }
87
140
  else {
88
- event = ctx.rawBody;
141
+ params = (_a = ctx.request.body) !== null && _a !== void 0 ? _a : ctx.rawBody;
89
142
  }
143
+ if (params === undefined || params === null) {
144
+ params = {};
145
+ }
146
+ const event = { params };
90
147
  let executeDone = false;
91
148
  let hasSwitchSSEMode = false;
149
+ const headers = normalizeHeaders((_b = ctx.request) === null || _b === void 0 ? void 0 : _b.headers);
150
+ const httpMethod = ctx.method;
151
+ const path = ctx.path;
152
+ const url = ctx.url;
153
+ const query = normalizeQuery(ctx.query);
154
+ const cookies = parseCookies(headers.cookie);
155
+ const trigger = resolveTrigger(ctx);
92
156
  const context = {
93
157
  ctxId: ctx.state.eventID,
94
158
  eventID: ctx.state.eventID,
95
159
  eventType: ctx.state.eventType,
96
160
  timestamp: ctx.state.timestamp,
161
+ headers,
162
+ httpMethod,
163
+ path,
164
+ url,
165
+ query,
166
+ cookies,
167
+ trigger,
97
168
  httpContext: ctx.httpContext,
98
169
  baseUrl: (0, config_1.getBaseUrl)(),
99
170
  request: new request_1.Request({
@@ -102,11 +173,26 @@ const wrapEventFunction = (execute, projectConfig) => {
102
173
  restrictedMethods: ["get", "post", "upload", "download"],
103
174
  defaultHeaders: {
104
175
  "agent-id": projectConfig.agentId,
105
- "open-id": ctx.request.headers["open-id"],
176
+ "open-id": ((_d = (_c = ctx.request) === null || _c === void 0 ? void 0 : _c.headers) === null || _d === void 0 ? void 0 : _d["open-id"]) || "UNKNOWN",
106
177
  "x-open-agent-trace-id": ctx.state.eventID,
107
178
  },
108
179
  }),
109
180
  logger: logger_1.functionsLogger,
181
+ set: (field, value) => {
182
+ ctx.set(field, value);
183
+ },
184
+ remove: (field) => {
185
+ ctx.remove(field);
186
+ },
187
+ status: (code) => {
188
+ ctx.status = code;
189
+ },
190
+ setCookie: (name, value, options) => {
191
+ ctx.cookies.set(name, value, options);
192
+ },
193
+ clearCookie: (name, options) => {
194
+ ctx.cookies.set(name, null, Object.assign(Object.assign({}, (options || {})), { expires: new Date(0), maxAge: 0 }));
195
+ },
110
196
  sse: () => {
111
197
  var _a;
112
198
  const sseInstance = (_a = ctx.sse) === null || _a === void 0 ? void 0 : _a.call(ctx);
@@ -127,12 +213,19 @@ const wrapEventFunction = (execute, projectConfig) => {
127
213
  eventID: context.eventID,
128
214
  eventType: context.eventType,
129
215
  timestamp: context.timestamp,
216
+ headers: context.headers,
217
+ httpMethod: context.httpMethod,
218
+ path: context.path,
219
+ url: context.url,
220
+ query: context.query,
221
+ cookies: context.cookies,
222
+ trigger: context.trigger,
130
223
  httpContext: context.httpContext,
131
224
  baseUrl: context.baseUrl,
132
225
  request: context.request,
133
226
  };
134
227
  (0, helper_1.deepFreeze)(contextToFreeze);
135
- const frozenContext = Object.assign(Object.assign({}, contextToFreeze), { logger: context.logger, sse: context.sse });
228
+ const frozenContext = Object.assign(Object.assign({}, contextToFreeze), { logger: context.logger, set: context.set, remove: context.remove, status: context.status, setCookie: context.setCookie, clearCookie: context.clearCookie, sse: context.sse });
136
229
  ctx.state.event = event;
137
230
  ctx.state.contextInjected = frozenContext;
138
231
  let result;
@@ -142,7 +235,7 @@ const wrapEventFunction = (execute, projectConfig) => {
142
235
  catch (e) {
143
236
  ctx.state.error = e;
144
237
  if (hasSwitchSSEMode) {
145
- const sse = (_a = ctx.sse) === null || _a === void 0 ? void 0 : _a.call(ctx);
238
+ const sse = (_e = ctx.sse) === null || _e === void 0 ? void 0 : _e.call(ctx);
146
239
  if (sse && !sse.isClosed) {
147
240
  const errorEvent = {
148
241
  event: "error",
package/lib/index.js CHANGED
@@ -20,5 +20,6 @@ __exportStar(require("./function-loader"), exports);
20
20
  __exportStar(require("./function-registry"), exports);
21
21
  __exportStar(require("./sse"), exports);
22
22
  __exportStar(require("./server"), exports);
23
+ __exportStar(require("./wss"), exports);
23
24
  __exportStar(require("./logger"), exports);
24
25
  __exportStar(require("./async-context"), exports);
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.apmMiddleware = exports.openGwRequestMiddleware = exports.logsQueryMiddleware = exports.loggerMiddleware = exports.functionRouteMiddleware = exports.eventIdMiddleware = exports.contextInjectionMiddleware = exports.asyncContextMiddleware = void 0;
3
+ exports.apmMiddleware = exports.openGwRequestMiddleware = exports.logsQueryMiddleware = exports.loggerMiddleware = exports.functionRouteMiddleware = exports.eventIdMiddleware = exports.envVarsInjectionMiddleware = exports.contextInjectionMiddleware = exports.asyncContextMiddleware = void 0;
4
4
  var middle_async_context_1 = require("./middle-async-context");
5
5
  Object.defineProperty(exports, "asyncContextMiddleware", { enumerable: true, get: function () { return middle_async_context_1.asyncContextMiddleware; } });
6
6
  var middle_context_injection_1 = require("./middle-context-injection");
7
7
  Object.defineProperty(exports, "contextInjectionMiddleware", { enumerable: true, get: function () { return middle_context_injection_1.contextInjectionMiddleware; } });
8
+ var middle_env_vars_injection_1 = require("./middle-env-vars-injection");
9
+ Object.defineProperty(exports, "envVarsInjectionMiddleware", { enumerable: true, get: function () { return middle_env_vars_injection_1.envVarsInjectionMiddleware; } });
8
10
  var middle_event_id_1 = require("./middle-event-id");
9
11
  Object.defineProperty(exports, "eventIdMiddleware", { enumerable: true, get: function () { return middle_event_id_1.eventIdMiddleware; } });
10
12
  var middle_function_route_1 = require("./middle-function-route");
@@ -25,7 +25,7 @@ function loggerMiddleware() {
25
25
  yield next();
26
26
  return;
27
27
  }
28
- process.stdout.write(chalk_1.default.greenBright(`▶️ ${chalk_1.default.gray(`[${new Date().toLocaleString()} - ${ctx.method}:${eventId}]`)} ${ctx.url}`));
28
+ process.stdout.write(chalk_1.default.greenBright(`▶️ ${chalk_1.default.gray(`[${new Date().toLocaleString()} - ${ctx.method}:${eventId}]`)} ${ctx.url}\n`));
29
29
  try {
30
30
  const accessLog = {
31
31
  type: "HTTP_ACCESS",
@@ -44,6 +44,7 @@ function loggerMiddleware() {
44
44
  finally {
45
45
  const endTime = Date.now();
46
46
  const duration = endTime - startTime;
47
+ const contentType = ctx.get("content-type") || "-";
47
48
  const accessLog = {
48
49
  type: "HTTP_ACCESS",
49
50
  method: ctx.method,
@@ -65,7 +66,7 @@ function loggerMiddleware() {
65
66
  asyncContext.userCodeLogsFlushTimer = undefined;
66
67
  }
67
68
  logger_1.functionsLogger.logUserCodelog();
68
- process.stdout.write(chalk_1.default.greenBright(`▶️ ${chalk_1.default.gray(`[${new Date().toLocaleString()} - ${eventId.slice(0, -10)}]`)} - ${duration}ms\n`));
69
+ process.stdout.write(chalk_1.default.greenBright(`▶️ ${chalk_1.default.gray(`[${new Date().toLocaleString()} - ${eventId.slice(0, -10)}]`)} ${chalk_1.default.bold(`${ctx.method} ${ctx.path}`)} ${chalk_1.default.bold(`[${contentType}]`)} - ${duration}ms\n`));
69
70
  process.stdout.write(chalk_1.default.greenBright(`\n`));
70
71
  }
71
72
  });