@constructive-io/knative-job-fn 0.2.7 → 0.3.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 CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.3.0](https://github.com/constructive-io/jobs/compare/@constructive-io/knative-job-fn@0.2.8...@constructive-io/knative-job-fn@0.3.0) (2026-01-18)
7
+
8
+ **Note:** Version bump only for package @constructive-io/knative-job-fn
9
+
10
+ ## [0.2.8](https://github.com/constructive-io/jobs/compare/@constructive-io/knative-job-fn@0.2.7...@constructive-io/knative-job-fn@0.2.8) (2026-01-18)
11
+
12
+ **Note:** Version bump only for package @constructive-io/knative-job-fn
13
+
6
14
  ## [0.2.7](https://github.com/constructive-io/jobs/compare/@constructive-io/knative-job-fn@0.2.6...@constructive-io/knative-job-fn@0.2.7) (2025-12-25)
7
15
 
8
16
  **Note:** Version bump only for package @constructive-io/knative-job-fn
package/dist/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
- declare const _default: {
1
+ import type { Server as HttpServer } from 'http';
2
+ declare const createJobApp: () => {
2
3
  post: (...args: any[]) => any;
3
- listen: (port: any, cb?: () => void) => void;
4
+ listen: (port: any, hostOrCb?: string | (() => void), cb?: () => void) => HttpServer;
4
5
  };
5
- export default _default;
6
+ declare const defaultApp: {
7
+ post: (...args: any[]) => any;
8
+ listen: (port: any, hostOrCb?: string | (() => void), cb?: () => void) => HttpServer;
9
+ };
10
+ export { createJobApp };
11
+ export default defaultApp;
package/dist/index.js CHANGED
@@ -3,11 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createJobApp = void 0;
6
7
  const express_1 = __importDefault(require("express"));
7
8
  const body_parser_1 = __importDefault(require("body-parser"));
8
9
  const node_http_1 = __importDefault(require("node:http"));
9
10
  const node_https_1 = __importDefault(require("node:https"));
10
11
  const node_url_1 = require("node:url");
12
+ const logger_1 = require("@pgpmjs/logger");
11
13
  function getHeaders(req) {
12
14
  return {
13
15
  'x-worker-id': req.get('X-Worker-Id'),
@@ -16,48 +18,6 @@ function getHeaders(req) {
16
18
  'x-callback-url': req.get('X-Callback-Url')
17
19
  };
18
20
  }
19
- const app = (0, express_1.default)();
20
- app.use(body_parser_1.default.json());
21
- // Basic request logging for all incoming job invocations.
22
- app.use((req, res, next) => {
23
- try {
24
- // Log only the headers we care about plus a shallow body snapshot
25
- const headers = getHeaders(req);
26
- let body;
27
- if (req.body && typeof req.body === 'object') {
28
- // Only log top-level keys to avoid exposing sensitive body contents.
29
- body = { keys: Object.keys(req.body) };
30
- }
31
- else if (typeof req.body === 'string') {
32
- // For string bodies, log only the length.
33
- body = { length: req.body.length };
34
- }
35
- else {
36
- body = undefined;
37
- }
38
- // eslint-disable-next-line no-console
39
- console.log('[knative-job-fn] Incoming job request', {
40
- method: req.method,
41
- path: req.originalUrl || req.url,
42
- headers,
43
- body
44
- });
45
- }
46
- catch {
47
- // best-effort logging; never block the request
48
- }
49
- next();
50
- });
51
- // Echo job headers back on responses for debugging/traceability.
52
- app.use((req, res, next) => {
53
- res.set({
54
- 'Content-Type': 'application/json',
55
- 'X-Worker-Id': req.get('X-Worker-Id'),
56
- 'X-Database-Id': req.get('X-Database-Id'),
57
- 'X-Job-Id': req.get('X-Job-Id')
58
- });
59
- next();
60
- });
61
21
  // Normalize callback URL so it always points at the /callback endpoint.
62
22
  const normalizeCallbackUrl = (rawUrl) => {
63
23
  try {
@@ -123,8 +83,7 @@ const sendJobCallback = async (ctx, status, errorMessage) => {
123
83
  body.error = errorMessage || 'ERROR';
124
84
  }
125
85
  try {
126
- // eslint-disable-next-line no-console
127
- console.log('[knative-job-fn] Sending job callback', {
86
+ logger.info('Sending job callback', {
128
87
  status,
129
88
  target: normalizeCallbackUrl(callbackUrl),
130
89
  workerId,
@@ -134,99 +93,150 @@ const sendJobCallback = async (ctx, status, errorMessage) => {
134
93
  await postJson(target, headers, body);
135
94
  }
136
95
  catch (err) {
137
- // eslint-disable-next-line no-console
138
- console.error('[knative-job-fn] Failed to POST job callback', {
96
+ logger.error('Failed to POST job callback', {
139
97
  target,
140
98
  status,
141
99
  err
142
100
  });
143
101
  }
144
102
  };
145
- // Attach per-request context and a finish hook to send success callbacks.
146
- app.use((req, res, next) => {
147
- const ctx = {
148
- callbackUrl: req.get('X-Callback-Url'),
149
- workerId: req.get('X-Worker-Id'),
150
- jobId: req.get('X-Job-Id'),
151
- databaseId: req.get('X-Database-Id')
152
- };
153
- // Store on res.locals so the error middleware can also mark callbacks as sent.
154
- res.locals = res.locals || {};
155
- res.locals.jobContext = ctx;
156
- res.locals.jobCallbackSent = false;
157
- if (ctx.callbackUrl && ctx.workerId && ctx.jobId) {
158
- res.on('finish', () => {
159
- // If an error handler already sent a callback, skip.
160
- if (res.locals.jobCallbackSent)
161
- return;
162
- res.locals.jobCallbackSent = true;
163
- // eslint-disable-next-line no-console
164
- console.log('[knative-job-fn] Function completed', {
165
- workerId: ctx.workerId,
166
- jobId: ctx.jobId,
167
- databaseId: ctx.databaseId,
168
- statusCode: res.statusCode
103
+ const logger = (0, logger_1.createLogger)('knative-job-fn');
104
+ const createJobApp = () => {
105
+ const app = (0, express_1.default)();
106
+ app.use(body_parser_1.default.json());
107
+ // Basic request logging for all incoming job invocations.
108
+ app.use((req, res, next) => {
109
+ try {
110
+ // Log only the headers we care about plus a shallow body snapshot
111
+ const headers = getHeaders(req);
112
+ let body;
113
+ if (req.body && typeof req.body === 'object') {
114
+ // Only log top-level keys to avoid exposing sensitive body contents.
115
+ body = { keys: Object.keys(req.body) };
116
+ }
117
+ else if (typeof req.body === 'string') {
118
+ // For string bodies, log only the length.
119
+ body = { length: req.body.length };
120
+ }
121
+ else {
122
+ body = undefined;
123
+ }
124
+ logger.info('Incoming job request', {
125
+ method: req.method,
126
+ path: req.originalUrl || req.url,
127
+ headers,
128
+ body
169
129
  });
170
- void sendJobCallback(ctx, 'success');
130
+ }
131
+ catch {
132
+ // best-effort logging; never block the request
133
+ }
134
+ next();
135
+ });
136
+ // Echo job headers back on responses for debugging/traceability.
137
+ app.use((req, res, next) => {
138
+ res.set({
139
+ 'Content-Type': 'application/json',
140
+ 'X-Worker-Id': req.get('X-Worker-Id'),
141
+ 'X-Database-Id': req.get('X-Database-Id'),
142
+ 'X-Job-Id': req.get('X-Job-Id')
171
143
  });
172
- }
173
- next();
174
- });
175
- exports.default = {
176
- post: function (...args) {
177
- return app.post.apply(app, args);
178
- },
179
- listen: (port, cb = () => { }) => {
180
- // NOTE Remember that Express middleware executes in order.
181
- // You should define error handlers last, after all other middleware.
182
- // Otherwise, your error handler won't get called
183
- // eslint-disable-next-line no-unused-vars
184
- app.use(async (error, req, res, next) => {
185
- res.set({
186
- 'Content-Type': 'application/json',
187
- 'X-Job-Error': true
144
+ next();
145
+ });
146
+ // Attach per-request context and a finish hook to send success callbacks.
147
+ app.use((req, res, next) => {
148
+ const ctx = {
149
+ callbackUrl: req.get('X-Callback-Url'),
150
+ workerId: req.get('X-Worker-Id'),
151
+ jobId: req.get('X-Job-Id'),
152
+ databaseId: req.get('X-Database-Id')
153
+ };
154
+ // Store on res.locals so the error middleware can also mark callbacks as sent.
155
+ res.locals = res.locals || {};
156
+ res.locals.jobContext = ctx;
157
+ res.locals.jobCallbackSent = false;
158
+ if (ctx.callbackUrl && ctx.workerId && ctx.jobId) {
159
+ res.on('finish', () => {
160
+ // If an error handler already sent a callback, skip.
161
+ if (res.locals.jobCallbackSent)
162
+ return;
163
+ res.locals.jobCallbackSent = true;
164
+ logger.info('Function completed', {
165
+ workerId: ctx.workerId,
166
+ jobId: ctx.jobId,
167
+ databaseId: ctx.databaseId,
168
+ statusCode: res.statusCode
169
+ });
170
+ void sendJobCallback(ctx, 'success');
188
171
  });
189
- // Mark job as having errored via callback, if available.
190
- try {
191
- const ctx = res.locals?.jobContext;
192
- if (ctx && !res.locals.jobCallbackSent) {
193
- res.locals.jobCallbackSent = true;
194
- await sendJobCallback(ctx, 'error', error?.message);
172
+ }
173
+ next();
174
+ });
175
+ return {
176
+ post: function (...args) {
177
+ return app.post.apply(app, args);
178
+ },
179
+ listen: (port, hostOrCb, cb = () => { }) => {
180
+ // NOTE Remember that Express middleware executes in order.
181
+ // You should define error handlers last, after all other middleware.
182
+ // Otherwise, your error handler won't get called
183
+ // eslint-disable-next-line no-unused-vars
184
+ app.use(async (error, req, res, next) => {
185
+ res.set({
186
+ 'Content-Type': 'application/json',
187
+ 'X-Job-Error': true
188
+ });
189
+ // Mark job as having errored via callback, if available.
190
+ try {
191
+ const ctx = res.locals?.jobContext;
192
+ if (ctx && !res.locals.jobCallbackSent) {
193
+ res.locals.jobCallbackSent = true;
194
+ await sendJobCallback(ctx, 'error', error?.message);
195
+ }
195
196
  }
196
- }
197
- catch (err) {
198
- // eslint-disable-next-line no-console
199
- console.error('[knative-job-fn] Failed to send error callback', err);
200
- }
201
- // Log the full error context for debugging.
202
- try {
203
- const headers = getHeaders(req);
204
- // Some error types (e.g. GraphQL ClientError) expose response info.
205
- const errorDetails = {
206
- message: error?.message,
207
- name: error?.name,
208
- stack: error?.stack
209
- };
210
- if (error?.response) {
211
- errorDetails.response = {
212
- status: error.response.status,
213
- statusText: error.response.statusText,
214
- errors: error.response.errors,
215
- data: error.response.data
197
+ catch (err) {
198
+ logger.error('Failed to send error callback', err);
199
+ }
200
+ // Log the full error context for debugging.
201
+ try {
202
+ const headers = getHeaders(req);
203
+ // Some error types (e.g. GraphQL ClientError) expose response info.
204
+ const errorDetails = {
205
+ message: error?.message,
206
+ name: error?.name,
207
+ stack: error?.stack
216
208
  };
209
+ if (error?.response) {
210
+ errorDetails.response = {
211
+ status: error.response.status,
212
+ statusText: error.response.statusText,
213
+ errors: error.response.errors,
214
+ data: error.response.data
215
+ };
216
+ }
217
+ logger.error('Function error', {
218
+ headers,
219
+ path: req.originalUrl || req.url,
220
+ error: errorDetails
221
+ });
217
222
  }
218
- // eslint-disable-next-line no-console
219
- console.error('[knative-job-fn] Function error', {
220
- headers,
221
- path: req.originalUrl || req.url,
222
- error: errorDetails
223
- });
224
- }
225
- catch {
226
- // never throw from the error logger
227
- }
228
- res.status(200).json({ message: error.message });
229
- });
230
- app.listen(port, cb);
231
- }
223
+ catch {
224
+ // never throw from the error logger
225
+ }
226
+ res.status(200).json({ message: error.message });
227
+ });
228
+ const host = typeof hostOrCb === 'string' ? hostOrCb : undefined;
229
+ const callback = typeof hostOrCb === 'function' ? hostOrCb : cb;
230
+ const onListen = () => {
231
+ callback();
232
+ };
233
+ const server = host
234
+ ? app.listen(port, host, onListen)
235
+ : app.listen(port, onListen);
236
+ return server;
237
+ }
238
+ };
232
239
  };
240
+ exports.createJobApp = createJobApp;
241
+ const defaultApp = createJobApp();
242
+ exports.default = defaultApp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/knative-job-fn",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "description": "knative job fn",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "homepage": "https://github.com/constructive-io/jobs/tree/master/packages/knative-job-fn#readme",
@@ -28,8 +28,9 @@
28
28
  "url": "https://github.com/constructive-io/jobs/issues"
29
29
  },
30
30
  "dependencies": {
31
+ "@pgpmjs/logger": "^1.4.0",
31
32
  "body-parser": "1.19.0",
32
33
  "express": "5.2.1"
33
34
  },
34
- "gitHead": "976cc9e0e09201c7df40518a1797f4178fc21c2c"
35
+ "gitHead": "481b3a50b4eec2da6b376c4cd1868065e1e28edb"
35
36
  }
package/src/index.ts CHANGED
@@ -3,6 +3,8 @@ import bodyParser from 'body-parser';
3
3
  import http from 'node:http';
4
4
  import https from 'node:https';
5
5
  import { URL } from 'node:url';
6
+ import type { Server as HttpServer } from 'http';
7
+ import { createLogger } from '@pgpmjs/logger';
6
8
 
7
9
  type JobCallbackStatus = 'success' | 'error';
8
10
 
@@ -22,51 +24,6 @@ function getHeaders(req: any) {
22
24
  };
23
25
  }
24
26
 
25
- const app: any = express();
26
-
27
- app.use(bodyParser.json());
28
-
29
- // Basic request logging for all incoming job invocations.
30
- app.use((req: any, res: any, next: any) => {
31
- try {
32
- // Log only the headers we care about plus a shallow body snapshot
33
- const headers = getHeaders(req);
34
-
35
- let body: any;
36
- if (req.body && typeof req.body === 'object') {
37
- // Only log top-level keys to avoid exposing sensitive body contents.
38
- body = { keys: Object.keys(req.body) };
39
- } else if (typeof req.body === 'string') {
40
- // For string bodies, log only the length.
41
- body = { length: req.body.length };
42
- } else {
43
- body = undefined;
44
- }
45
-
46
- // eslint-disable-next-line no-console
47
- console.log('[knative-job-fn] Incoming job request', {
48
- method: req.method,
49
- path: req.originalUrl || req.url,
50
- headers,
51
- body
52
- });
53
- } catch {
54
- // best-effort logging; never block the request
55
- }
56
- next();
57
- });
58
-
59
- // Echo job headers back on responses for debugging/traceability.
60
- app.use((req: any, res: any, next: any) => {
61
- res.set({
62
- 'Content-Type': 'application/json',
63
- 'X-Worker-Id': req.get('X-Worker-Id'),
64
- 'X-Database-Id': req.get('X-Database-Id'),
65
- 'X-Job-Id': req.get('X-Job-Id')
66
- });
67
- next();
68
- });
69
-
70
27
  // Normalize callback URL so it always points at the /callback endpoint.
71
28
  const normalizeCallbackUrl = (rawUrl: string): string => {
72
29
  try {
@@ -152,8 +109,7 @@ const sendJobCallback = async (
152
109
  }
153
110
 
154
111
  try {
155
- // eslint-disable-next-line no-console
156
- console.log('[knative-job-fn] Sending job callback', {
112
+ logger.info('Sending job callback', {
157
113
  status,
158
114
  target: normalizeCallbackUrl(callbackUrl),
159
115
  workerId,
@@ -162,8 +118,7 @@ const sendJobCallback = async (
162
118
  });
163
119
  await postJson(target, headers, body);
164
120
  } catch (err) {
165
- // eslint-disable-next-line no-console
166
- console.error('[knative-job-fn] Failed to POST job callback', {
121
+ logger.error('Failed to POST job callback', {
167
122
  target,
168
123
  status,
169
124
  err
@@ -171,98 +126,162 @@ const sendJobCallback = async (
171
126
  }
172
127
  };
173
128
 
174
- // Attach per-request context and a finish hook to send success callbacks.
175
- app.use((req: any, res: any, next: any) => {
176
- const ctx: JobContext = {
177
- callbackUrl: req.get('X-Callback-Url'),
178
- workerId: req.get('X-Worker-Id'),
179
- jobId: req.get('X-Job-Id'),
180
- databaseId: req.get('X-Database-Id')
181
- };
129
+ const logger = createLogger('knative-job-fn');
182
130
 
183
- // Store on res.locals so the error middleware can also mark callbacks as sent.
184
- res.locals = res.locals || {};
185
- res.locals.jobContext = ctx;
186
- res.locals.jobCallbackSent = false;
187
-
188
- if (ctx.callbackUrl && ctx.workerId && ctx.jobId) {
189
- res.on('finish', () => {
190
- // If an error handler already sent a callback, skip.
191
- if (res.locals.jobCallbackSent) return;
192
- res.locals.jobCallbackSent = true;
193
- // eslint-disable-next-line no-console
194
- console.log('[knative-job-fn] Function completed', {
195
- workerId: ctx.workerId,
196
- jobId: ctx.jobId,
197
- databaseId: ctx.databaseId,
198
- statusCode: res.statusCode
131
+ const createJobApp = () => {
132
+ const app: any = express();
133
+
134
+ app.use(bodyParser.json());
135
+
136
+ // Basic request logging for all incoming job invocations.
137
+ app.use((req: any, res: any, next: any) => {
138
+ try {
139
+ // Log only the headers we care about plus a shallow body snapshot
140
+ const headers = getHeaders(req);
141
+
142
+ let body: any;
143
+ if (req.body && typeof req.body === 'object') {
144
+ // Only log top-level keys to avoid exposing sensitive body contents.
145
+ body = { keys: Object.keys(req.body) };
146
+ } else if (typeof req.body === 'string') {
147
+ // For string bodies, log only the length.
148
+ body = { length: req.body.length };
149
+ } else {
150
+ body = undefined;
151
+ }
152
+
153
+ logger.info('Incoming job request', {
154
+ method: req.method,
155
+ path: req.originalUrl || req.url,
156
+ headers,
157
+ body
199
158
  });
200
- void sendJobCallback(ctx, 'success');
159
+ } catch {
160
+ // best-effort logging; never block the request
161
+ }
162
+ next();
163
+ });
164
+
165
+ // Echo job headers back on responses for debugging/traceability.
166
+ app.use((req: any, res: any, next: any) => {
167
+ res.set({
168
+ 'Content-Type': 'application/json',
169
+ 'X-Worker-Id': req.get('X-Worker-Id'),
170
+ 'X-Database-Id': req.get('X-Database-Id'),
171
+ 'X-Job-Id': req.get('X-Job-Id')
201
172
  });
202
- }
173
+ next();
174
+ });
203
175
 
204
- next();
205
- });
206
-
207
- export default {
208
- post: function (...args: any[]) {
209
- return app.post.apply(app, args as any);
210
- },
211
- listen: (port: any, cb: () => void = () => {}) => {
212
- // NOTE Remember that Express middleware executes in order.
213
- // You should define error handlers last, after all other middleware.
214
- // Otherwise, your error handler won't get called
215
- // eslint-disable-next-line no-unused-vars
216
- app.use(async (error: any, req: any, res: any, next: any) => {
217
- res.set({
218
- 'Content-Type': 'application/json',
219
- 'X-Job-Error': true
176
+ // Attach per-request context and a finish hook to send success callbacks.
177
+ app.use((req: any, res: any, next: any) => {
178
+ const ctx: JobContext = {
179
+ callbackUrl: req.get('X-Callback-Url'),
180
+ workerId: req.get('X-Worker-Id'),
181
+ jobId: req.get('X-Job-Id'),
182
+ databaseId: req.get('X-Database-Id')
183
+ };
184
+
185
+ // Store on res.locals so the error middleware can also mark callbacks as sent.
186
+ res.locals = res.locals || {};
187
+ res.locals.jobContext = ctx;
188
+ res.locals.jobCallbackSent = false;
189
+
190
+ if (ctx.callbackUrl && ctx.workerId && ctx.jobId) {
191
+ res.on('finish', () => {
192
+ // If an error handler already sent a callback, skip.
193
+ if (res.locals.jobCallbackSent) return;
194
+ res.locals.jobCallbackSent = true;
195
+ logger.info('Function completed', {
196
+ workerId: ctx.workerId,
197
+ jobId: ctx.jobId,
198
+ databaseId: ctx.databaseId,
199
+ statusCode: res.statusCode
200
+ });
201
+ void sendJobCallback(ctx, 'success');
220
202
  });
203
+ }
204
+
205
+ next();
206
+ });
221
207
 
222
- // Mark job as having errored via callback, if available.
223
- try {
224
- const ctx: JobContext | undefined = res.locals?.jobContext;
225
- if (ctx && !res.locals.jobCallbackSent) {
226
- res.locals.jobCallbackSent = true;
227
- await sendJobCallback(ctx, 'error', error?.message);
208
+ return {
209
+ post: function (...args: any[]) {
210
+ return app.post.apply(app, args as any);
211
+ },
212
+ listen: (
213
+ port: any,
214
+ hostOrCb?: string | (() => void),
215
+ cb: () => void = () => {}
216
+ ): HttpServer => {
217
+ // NOTE Remember that Express middleware executes in order.
218
+ // You should define error handlers last, after all other middleware.
219
+ // Otherwise, your error handler won't get called
220
+ // eslint-disable-next-line no-unused-vars
221
+ app.use(async (error: any, req: any, res: any, next: any) => {
222
+ res.set({
223
+ 'Content-Type': 'application/json',
224
+ 'X-Job-Error': true
225
+ });
226
+
227
+ // Mark job as having errored via callback, if available.
228
+ try {
229
+ const ctx: JobContext | undefined = res.locals?.jobContext;
230
+ if (ctx && !res.locals.jobCallbackSent) {
231
+ res.locals.jobCallbackSent = true;
232
+ await sendJobCallback(ctx, 'error', error?.message);
233
+ }
234
+ } catch (err) {
235
+ logger.error('Failed to send error callback', err);
228
236
  }
229
- } catch (err) {
230
- // eslint-disable-next-line no-console
231
- console.error('[knative-job-fn] Failed to send error callback', err);
232
- }
233
237
 
234
- // Log the full error context for debugging.
235
- try {
236
- const headers = getHeaders(req);
237
-
238
- // Some error types (e.g. GraphQL ClientError) expose response info.
239
- const errorDetails: any = {
240
- message: error?.message,
241
- name: error?.name,
242
- stack: error?.stack
243
- };
244
-
245
- if (error?.response) {
246
- errorDetails.response = {
247
- status: error.response.status,
248
- statusText: error.response.statusText,
249
- errors: error.response.errors,
250
- data: error.response.data
238
+ // Log the full error context for debugging.
239
+ try {
240
+ const headers = getHeaders(req);
241
+
242
+ // Some error types (e.g. GraphQL ClientError) expose response info.
243
+ const errorDetails: any = {
244
+ message: error?.message,
245
+ name: error?.name,
246
+ stack: error?.stack
251
247
  };
248
+
249
+ if (error?.response) {
250
+ errorDetails.response = {
251
+ status: error.response.status,
252
+ statusText: error.response.statusText,
253
+ errors: error.response.errors,
254
+ data: error.response.data
255
+ };
256
+ }
257
+
258
+ logger.error('Function error', {
259
+ headers,
260
+ path: req.originalUrl || req.url,
261
+ error: errorDetails
262
+ });
263
+ } catch {
264
+ // never throw from the error logger
252
265
  }
253
266
 
254
- // eslint-disable-next-line no-console
255
- console.error('[knative-job-fn] Function error', {
256
- headers,
257
- path: req.originalUrl || req.url,
258
- error: errorDetails
259
- });
260
- } catch {
261
- // never throw from the error logger
262
- }
267
+ res.status(200).json({ message: error.message });
268
+ });
263
269
 
264
- res.status(200).json({ message: error.message });
265
- });
266
- app.listen(port, cb);
267
- }
270
+ const host = typeof hostOrCb === 'string' ? hostOrCb : undefined;
271
+ const callback = typeof hostOrCb === 'function' ? hostOrCb : cb;
272
+ const onListen = () => {
273
+ callback();
274
+ };
275
+ const server = host
276
+ ? app.listen(port, host, onListen)
277
+ : app.listen(port, onListen);
278
+
279
+ return server;
280
+ }
281
+ };
268
282
  };
283
+
284
+ const defaultApp = createJobApp();
285
+
286
+ export { createJobApp };
287
+ export default defaultApp;