@xeonr/upload-pool-sdk 1.0.0 → 1.2.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.
@@ -1,24 +1,70 @@
1
1
  /**
2
2
  * ConnectRPC clients for the two services the SDK talks to:
3
- * - InternalUploadsService — per-upload callbacks (UpdateUpload,
4
- * RequestMetaUpload, ConfirmMetaUpload, GetProcessingContext).
5
- * Auth: the per-job update_token from the job envelope, passed
6
- * as the in-band `updateToken` field on each request.
7
- * - IntegrationQueueService — accept / complete / report-error.
8
- * Auth: the pool token, passed as `queueToken` on each request.
3
+ * - InternalUploadsService (`apiEndpoint`) — per-upload callbacks
4
+ * (UpdateUpload, RequestMetaUpload, ConfirmMetaUpload,
5
+ * GetProcessingContext). Auth: the per-job `update_token` from the
6
+ * job envelope, passed as the in-band `updateToken` field on each
7
+ * request.
8
+ * - IntegrationQueueService (`pipelineEndpoint`) accept / complete /
9
+ * report-error. Auth: the pool token, passed as `queueToken` on each
10
+ * request.
11
+ *
12
+ * The two services live on different processes (Go uploads-api vs Node
13
+ * pipeline-api) so we keep them on separate transports and don't try to
14
+ * share a baseUrl.
15
+ *
16
+ * Each request is wrapped in a logging interceptor that emits one
17
+ * `rpc.request` line on dispatch and one of `rpc.response` /
18
+ * `rpc.error` on completion. Latency and connect-error codes are
19
+ * captured so failed RPCs are diagnosable from worker logs alone.
9
20
  */
10
21
  import { createConnectTransport } from "@connectrpc/connect-node";
11
- import { createClient } from "@connectrpc/connect";
22
+ import { createClient, ConnectError, Code, } from "@connectrpc/connect";
12
23
  import { InternalUploadsService } from "./protocol/uplim/api/v1/uploads_pb.js";
13
24
  import { IntegrationQueueService } from "./protocol/uplim/workflow/v1/integration_queue_pb.js";
14
- export function createRpcClients(endpoint) {
15
- const transport = createConnectTransport({
16
- baseUrl: endpoint,
25
+ function loggingInterceptor(logger, target) {
26
+ return (next) => async (req) => {
27
+ const startedAt = Date.now();
28
+ const method = `${req.service.typeName}/${req.method.name}`;
29
+ logger.debug("rpc.request", { method, target });
30
+ try {
31
+ const res = await next(req);
32
+ logger.debug("rpc.response", {
33
+ method,
34
+ target,
35
+ durationMs: Date.now() - startedAt,
36
+ });
37
+ return res;
38
+ }
39
+ catch (err) {
40
+ const code = err instanceof ConnectError ? Code[err.code] : undefined;
41
+ const message = err instanceof Error ? err.message : String(err);
42
+ logger.error("rpc.error", {
43
+ method,
44
+ target,
45
+ code,
46
+ message,
47
+ durationMs: Date.now() - startedAt,
48
+ });
49
+ throw err;
50
+ }
51
+ };
52
+ }
53
+ export function createRpcClients(config) {
54
+ const rpcLogger = config.logger.child({ component: "rpc" });
55
+ const apiTransport = createConnectTransport({
56
+ baseUrl: config.apiEndpoint,
57
+ httpVersion: "1.1",
58
+ interceptors: [loggingInterceptor(rpcLogger, "api")],
59
+ });
60
+ const pipelineTransport = createConnectTransport({
61
+ baseUrl: config.pipelineEndpoint,
17
62
  httpVersion: "1.1",
63
+ interceptors: [loggingInterceptor(rpcLogger, "pipeline")],
18
64
  });
19
65
  return {
20
- internalUploads: createClient(InternalUploadsService, transport),
21
- integrationQueue: createClient(IntegrationQueueService, transport),
66
+ internalUploads: createClient(InternalUploadsService, apiTransport),
67
+ integrationQueue: createClient(IntegrationQueueService, pipelineTransport),
22
68
  };
23
69
  }
24
70
  //# sourceMappingURL=rpc-clients.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-clients.js","sourceRoot":"","sources":["../src/rpc-clients.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAe,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,sDAAsD,CAAC;AAO/F,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAChD,MAAM,SAAS,GAAG,sBAAsB,CAAC;QACxC,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,KAAK;KAClB,CAAC,CAAC;IACH,OAAO;QACN,eAAe,EAAE,YAAY,CAAC,sBAAsB,EAAE,SAAS,CAAC;QAChE,gBAAgB,EAAE,YAAY,CAAC,uBAAuB,EAAE,SAAS,CAAC;KAClE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"rpc-clients.js","sourceRoot":"","sources":["../src/rpc-clients.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACN,YAAY,EAGZ,YAAY,EACZ,IAAI,GACJ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,sDAAsD,CAAC;AAQ/F,SAAS,kBAAkB,CAAC,MAAc,EAAE,MAAc;IACzD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE;gBAC5B,MAAM;gBACN,MAAM;gBACN,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aAClC,CAAC,CAAC;YACH,OAAO,GAAG,CAAC;QACZ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,GACT,GAAG,YAAY,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC1D,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE;gBACzB,MAAM;gBACN,MAAM;gBACN,IAAI;gBACJ,OAAO;gBACP,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aAClC,CAAC,CAAC;YACH,MAAM,GAAG,CAAC;QACX,CAAC;IACF,CAAC,CAAC;AACH,CAAC;AAQD,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACxD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAE5D,MAAM,YAAY,GAAG,sBAAsB,CAAC;QAC3C,OAAO,EAAE,MAAM,CAAC,WAAW;QAC3B,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,CAAC,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;KACpD,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;QAChD,OAAO,EAAE,MAAM,CAAC,gBAAgB;QAChC,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,CAAC,kBAAkB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;KACzD,CAAC,CAAC;IACH,OAAO;QACN,eAAe,EAAE,YAAY,CAAC,sBAAsB,EAAE,YAAY,CAAC;QACnE,gBAAgB,EAAE,YAAY,CAAC,uBAAuB,EAAE,iBAAiB,CAAC;KAC1E,CAAC;AACH,CAAC"}
@@ -1,8 +1,10 @@
1
+ import type { Logger } from "./logger.js";
1
2
  export interface SseClientConfig {
2
3
  endpoint: string;
3
4
  token: string;
4
5
  workerId: string;
5
6
  capabilities: string[];
7
+ logger: Logger;
6
8
  onConnected: () => void;
7
9
  onDisconnected: (reason: string) => void;
8
10
  onJobDispatch: (payload: unknown) => void;
@@ -12,6 +14,8 @@ export declare class SseClient {
12
14
  private es;
13
15
  private stopped;
14
16
  private reconnectDelay;
17
+ private connectAttempt;
18
+ private connectedAt;
15
19
  constructor(config: SseClientConfig);
16
20
  start(): void;
17
21
  stop(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"sse-client.d.ts","sourceRoot":"","sources":["../src/sse-client.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAKD,qBAAa,SAAS;IAKT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,EAAE,CAA4B;IACtC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAwB;gBAEjB,MAAM,EAAE,eAAe;IAEpD,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IAQZ,OAAO,CAAC,OAAO;CAuCf"}
1
+ {"version":3,"file":"sse-client.d.ts","sourceRoot":"","sources":["../src/sse-client.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAKD,qBAAa,SAAS;IAOT,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC,OAAO,CAAC,EAAE,CAA4B;IACtC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,WAAW,CAAuB;gBAEb,MAAM,EAAE,eAAe;IAEpD,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IASZ,OAAO,CAAC,OAAO;CA6Ff"}
@@ -5,6 +5,11 @@
5
5
  *
6
6
  * Reconnect strategy: exponential backoff (1s, 2s, 4s, 8s, capped at 30s).
7
7
  * On `job:dispatch` events the SDK invokes the registered onJob callback.
8
+ *
9
+ * All lifecycle transitions emit structured logs via the injected
10
+ * `Logger` so connection failures are visible in the worker's k8s logs
11
+ * (otherwise a worker that can't connect at all looks identical to one
12
+ * that's idle).
8
13
  */
9
14
  import { EventSource } from "eventsource";
10
15
  const RECONNECT_INITIAL_MS = 1_000;
@@ -14,6 +19,8 @@ export class SseClient {
14
19
  es = null;
15
20
  stopped = false;
16
21
  reconnectDelay = RECONNECT_INITIAL_MS;
22
+ connectAttempt = 0;
23
+ connectedAt = null;
17
24
  constructor(config) {
18
25
  this.config = config;
19
26
  }
@@ -27,35 +34,82 @@ export class SseClient {
27
34
  this.es.close();
28
35
  this.es = null;
29
36
  }
37
+ this.config.logger.info("sse.stopped");
30
38
  }
31
39
  connect() {
32
40
  if (this.stopped)
33
41
  return;
42
+ this.connectAttempt++;
34
43
  const url = new URL(`${this.config.endpoint}/queue/connect`);
35
44
  url.searchParams.set("queueToken", this.config.token);
36
45
  url.searchParams.set("workerId", this.config.workerId);
37
46
  if (this.config.capabilities.length > 0) {
38
47
  url.searchParams.set("capabilities", this.config.capabilities.join(","));
39
48
  }
49
+ // Strip the token from the logged URL — the queueToken param is the
50
+ // pool secret, no reason to bake it into telemetry.
51
+ const loggedUrl = new URL(url.toString());
52
+ loggedUrl.searchParams.set("queueToken", "[redacted]");
53
+ this.config.logger.info("sse.connect.start", {
54
+ url: loggedUrl.toString(),
55
+ attempt: this.connectAttempt,
56
+ capabilities: this.config.capabilities,
57
+ });
40
58
  this.es = new EventSource(url.toString());
59
+ this.es.addEventListener("open", () => {
60
+ this.config.logger.debug("sse.open");
61
+ });
41
62
  this.es.addEventListener("connected", () => {
42
63
  this.reconnectDelay = RECONNECT_INITIAL_MS;
64
+ this.connectedAt = Date.now();
65
+ this.config.logger.info("sse.connect.opened", {
66
+ attempt: this.connectAttempt,
67
+ });
43
68
  this.config.onConnected();
44
69
  });
45
70
  this.es.addEventListener("job:dispatch", (event) => {
46
71
  try {
47
72
  const data = JSON.parse(event.data);
73
+ this.config.logger.debug("sse.event.job_dispatch", {
74
+ jobId: data.jobId,
75
+ });
48
76
  this.config.onJobDispatch(data);
49
77
  }
50
78
  catch (err) {
51
- this.config.onDisconnected(`bad job payload: ${err.message}`);
79
+ const reason = `bad job payload: ${err.message}`;
80
+ this.config.logger.error("sse.event.parse_error", {
81
+ err,
82
+ rawData: event.data,
83
+ });
84
+ this.config.onDisconnected(reason);
52
85
  }
53
86
  });
54
- // heartbeat events are no-ops receipt alone keeps the connection alive.
55
- this.es.onerror = () => {
87
+ // heartbeat events are no-ops at the dispatch layer receipt alone
88
+ // keeps the connection alive. We log at debug so noisy keep-alive
89
+ // traffic doesn't drown the info stream.
90
+ this.es.addEventListener("heartbeat", () => {
91
+ this.config.logger.debug("sse.event.heartbeat");
92
+ });
93
+ this.es.onerror = (err) => {
56
94
  if (this.stopped)
57
95
  return;
58
- this.config.onDisconnected("sse error");
96
+ const errMessage = err?.message ??
97
+ err?.type ??
98
+ "unknown";
99
+ const status = err?.status ??
100
+ err?.code;
101
+ const wasConnected = this.connectedAt !== null;
102
+ const uptimeMs = wasConnected ? Date.now() - this.connectedAt : null;
103
+ this.config.logger.warn("sse.disconnected", {
104
+ message: errMessage,
105
+ status,
106
+ wasConnected,
107
+ uptimeMs,
108
+ attempt: this.connectAttempt,
109
+ nextReconnectMs: this.reconnectDelay,
110
+ });
111
+ this.config.onDisconnected(`sse error: ${errMessage}`);
112
+ this.connectedAt = null;
59
113
  if (this.es) {
60
114
  this.es.close();
61
115
  this.es = null;
@@ -1 +1 @@
1
- {"version":3,"file":"sse-client.js","sourceRoot":"","sources":["../src/sse-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sse-client.js","sourceRoot":"","sources":["../src/sse-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAc1C,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEhC,MAAM,OAAO,SAAS;IAOQ;IANrB,EAAE,GAAuB,IAAI,CAAC;IAC9B,OAAO,GAAG,KAAK,CAAC;IAChB,cAAc,GAAG,oBAAoB,CAAC;IACtC,cAAc,GAAG,CAAC,CAAC;IACnB,WAAW,GAAkB,IAAI,CAAC;IAE1C,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAExD,KAAK;QACJ,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,EAAE,CAAC;IAChB,CAAC;IAED,IAAI;QACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC;IAEO,OAAO;QACd,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,gBAAgB,CAAC,CAAC;QAC7D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,CAAC;QAED,oEAAoE;QACpE,oDAAoD;QACpD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC1C,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAEvD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;YAC5C,GAAG,EAAE,SAAS,CAAC,QAAQ,EAAE;YACzB,OAAO,EAAE,IAAI,CAAC,cAAc;YAC5B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;SACtC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE1C,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;YACrC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE;YAC1C,IAAI,CAAC,cAAc,GAAG,oBAAoB,CAAC;YAC3C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;gBAC7C,OAAO,EAAE,IAAI,CAAC,cAAc;aAC5B,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE;YAClD,IAAI,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAE,KAAsB,CAAC,IAAI,CAAC,CAAC;gBACtD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE;oBAClD,KAAK,EAAG,IAA2B,CAAC,KAAK;iBACzC,CAAC,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,MAAM,MAAM,GAAG,oBAAqB,GAAa,CAAC,OAAO,EAAE,CAAC;gBAC5D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;oBACjD,GAAG;oBACH,OAAO,EAAG,KAAsB,CAAC,IAAI;iBACrC,CAAC,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;QACF,CAAC,CAAC,CAAC;QAEH,oEAAoE;QACpE,kEAAkE;QAClE,yCAAyC;QACzC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE;YAC1C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,CAAC,GAAY,EAAE,EAAE;YAClC,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO;YACzB,MAAM,UAAU,GACd,GAA4D,EAAE,OAAO;gBACrE,GAAyB,EAAE,IAAI;gBAChC,SAAS,CAAC;YACX,MAAM,MAAM,GAAI,GAA0C,EAAE,MAAM;gBAChE,GAAyB,EAAE,IAAI,CAAC;YAClC,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC;YAC/C,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAY,CAAC,CAAC,CAAC,IAAI,CAAC;YAEtE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE;gBAC3C,OAAO,EAAE,UAAU;gBACnB,MAAM;gBACN,YAAY;gBACZ,QAAQ;gBACR,OAAO,EAAE,IAAI,CAAC,cAAc;gBAC5B,eAAe,EAAE,IAAI,CAAC,cAAc;aACpC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,cAAc,UAAU,EAAE,CAAC,CAAC;YACvD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YAExB,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;YAChB,CAAC;YAED,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YACtD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAC3E,CAAC,CAAC;IACH,CAAC;CACD"}
package/dist/types.d.ts CHANGED
@@ -16,16 +16,47 @@
16
16
  export interface PoolConfig {
17
17
  /** Pool token, prefixed with "tpq_". From the pool's creation response. */
18
18
  token: string;
19
- /** API endpoint base URL, e.g. "https://api.upl.im". */
20
- endpoint: string;
19
+ /**
20
+ * Public uploads-api base URL, e.g. "https://uploads-api.xeonr.dev".
21
+ * Hosts `InternalUploadsService` (RequestMetaUpload, ConfirmMetaUpload,
22
+ * UpdateUpload, GetProcessingContext).
23
+ *
24
+ * Use the public https URL even when running inside the same k8s cluster
25
+ * as the API — keeps third-party workers and first-party workers on a
26
+ * single code path (TLS, normal ingress, no service-mesh assumptions).
27
+ */
28
+ apiEndpoint: string;
29
+ /**
30
+ * Public pipeline-api base URL, e.g. "https://uploads-pipeline-api.xeonr.dev".
31
+ * Hosts the SSE `/queue/connect` endpoint and `IntegrationQueueService`
32
+ * (AcceptJob, CompleteJob, ReportError).
33
+ *
34
+ * Distinct from `apiEndpoint` because the pipeline runs as a separate
35
+ * Node service; conflating the two would silently route worker traffic
36
+ * to the wrong process.
37
+ */
38
+ pipelineEndpoint: string;
21
39
  /** Optional worker identifier. Defaults to hostname + random suffix. */
22
40
  workerId?: string;
23
41
  /** Handlers keyed by content type URN (e.g. "default:image"). */
24
42
  handlers: Record<string, JobHandler>;
25
43
  /** Fallback handler if URN has no specific entry in `handlers`. Optional. */
26
44
  onUnhandled?: JobHandler;
27
- /** Lifecycle / error hook. Defaults to console-based logging. */
45
+ /**
46
+ * Lifecycle / error hook. Receives every handler exception alongside
47
+ * the job context. The SDK also logs every failure via `logger` —
48
+ * `onError` is for hooks that need to fan out to external systems
49
+ * (sentry, pagerduty). Optional.
50
+ */
28
51
  onError?: (err: Error, ctx?: JobContext) => void;
52
+ /**
53
+ * Structured logger. Defaults to a JSON-line logger that writes to
54
+ * stdout (`info`/`debug`) and stderr (`warn`/`error`), honoring
55
+ * `UPL_LOG_LEVEL`. Pass `noopLogger` from this package for silence,
56
+ * or supply your own implementing the `Logger` interface to bridge
57
+ * to pino/winston.
58
+ */
59
+ logger?: import("./logger.js").Logger;
29
60
  /** Max concurrent in-flight jobs. Defaults to 1. */
30
61
  concurrency?: number;
31
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeonr/upload-pool-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Self-hosted worker SDK for the upl.im content type pipeline. Implement a handler per content type URN; the SDK handles SSE connection, job acceptance, presigned thumbnail upload, and metadata callbacks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -8,7 +8,8 @@
8
8
  *
9
9
  * await createPool({
10
10
  * token: process.env.UPL_POOL_TOKEN!,
11
- * endpoint: process.env.UPL_API_URL!,
11
+ * apiEndpoint: process.env.UPL_API_URL!,
12
+ * pipelineEndpoint: process.env.UPL_PIPELINE_API_URL!,
12
13
  * handlers: {
13
14
  * "my-integration:invoice": async (ctx) => {
14
15
  * const buf = await ctx.downloadBuffer();
@@ -23,6 +24,8 @@ import type { PoolConfig } from "./types.js";
23
24
 
24
25
  export { Pool } from "./pool.js";
25
26
  export { NonRetryableError } from "./errors.js";
27
+ export { JsonLogger, noopLogger } from "./logger.js";
28
+ export type { Logger, LogLevel } from "./logger.js";
26
29
  export type {
27
30
  PoolConfig,
28
31
  JobContext,
@@ -17,6 +17,7 @@ import {
17
17
  } from "./protocol/uplim/api/v1/uploads_pb.js";
18
18
  import { UploadMetadataSchema } from "./protocol/uplim/api/v1/metadata_pb.js";
19
19
  import type { RpcClients } from "./rpc-clients.js";
20
+ import type { Logger } from "./logger.js";
20
21
  import type {
21
22
  FolderContext,
22
23
  JobContext,
@@ -54,6 +55,7 @@ export interface JobEnvelope {
54
55
  export function createJobContext(
55
56
  envelope: JobEnvelope,
56
57
  rpc: RpcClients,
58
+ logger: Logger,
57
59
  ): JobContext {
58
60
  const ctx: JobContext = {
59
61
  jobId: envelope.jobId,
@@ -71,28 +73,45 @@ export function createJobContext(
71
73
  sourceUrl: envelope.sourceUrl,
72
74
 
73
75
  async download() {
76
+ logger.debug("source.download.start");
74
77
  const resp = await fetch(envelope.sourceUrl);
75
78
  if (!resp.ok || !resp.body) {
79
+ logger.error("source.download.failed", {
80
+ status: resp.status,
81
+ statusText: resp.statusText,
82
+ });
76
83
  throw new Error(`source download failed: ${resp.status} ${resp.statusText}`);
77
84
  }
78
85
  return resp.body;
79
86
  },
80
87
 
81
88
  async downloadBuffer() {
89
+ logger.debug("source.download.start", { mode: "buffer" });
82
90
  const resp = await fetch(envelope.sourceUrl);
83
91
  if (!resp.ok) {
92
+ logger.error("source.download.failed", {
93
+ status: resp.status,
94
+ statusText: resp.statusText,
95
+ });
84
96
  throw new Error(`source download failed: ${resp.status} ${resp.statusText}`);
85
97
  }
86
98
  const buf = await resp.arrayBuffer();
99
+ logger.debug("source.download.complete", { sizeBytes: buf.byteLength });
87
100
  return new Uint8Array(buf);
88
101
  },
89
102
 
90
103
  async downloadToFile(path: string) {
91
104
  const data = await ctx.downloadBuffer();
92
105
  await writeFile(path, data);
106
+ logger.debug("source.download.to_file", { path, sizeBytes: data.byteLength });
93
107
  },
94
108
 
95
109
  async uploadMeta(opts: UploadMetaOpts) {
110
+ logger.debug("meta.upload.start", {
111
+ type: opts.type,
112
+ instance: opts.instance,
113
+ filename: opts.filename,
114
+ });
96
115
  const protoType = META_TYPE_MAP[opts.type];
97
116
  const metaType = create(MetaTypeSchema, {
98
117
  type: protoType,
@@ -135,6 +154,10 @@ export function createJobContext(
135
154
  metadataId: [meta.metadataId],
136
155
  }),
137
156
  );
157
+ logger.info("meta.upload.complete", {
158
+ type: opts.type,
159
+ metadataId: meta.metadataId,
160
+ });
138
161
  },
139
162
 
140
163
  async setMetadata(metadata: UploadMetadataPartial | UploadMetadataProto) {
@@ -163,6 +186,7 @@ export function createJobContext(
163
186
  thumbnailGenerationVersion: thumbnailVersion,
164
187
  }),
165
188
  );
189
+ logger.debug("metadata.set", { thumbnailVersion });
166
190
  },
167
191
 
168
192
  async markHasThumbnail(version: number) {
@@ -173,6 +197,7 @@ export function createJobContext(
173
197
  thumbnailGenerationVersion: version,
174
198
  }),
175
199
  );
200
+ logger.info("thumbnail.marked", { version });
176
201
  },
177
202
 
178
203
  async setDescription(text: string, tags?: string[]) {
@@ -185,12 +210,20 @@ export function createJobContext(
185
210
  }),
186
211
  }),
187
212
  );
213
+ logger.info("description.set", {
214
+ length: text.length,
215
+ tags: tags?.length ?? 0,
216
+ });
188
217
  },
189
218
 
190
219
  async withPresignedUploads<T>(
191
220
  opts: PresignedUploadRequest[],
192
221
  callback: (handles: import("./types.js").MetaUploadHandle[]) => Promise<T>,
193
222
  ): Promise<T> {
223
+ logger.debug("presigned.upload.request", {
224
+ count: opts.length,
225
+ types: opts.map((o) => o.type),
226
+ });
194
227
  const metaTypes = opts.map((opt) => create(MetaTypeSchema, {
195
228
  type: META_TYPE_MAP[opt.type],
196
229
  n: opt.instance,
@@ -222,6 +255,7 @@ export function createJobContext(
222
255
  metadataId: requested.metaUploads.map((m) => m.metadataId),
223
256
  }),
224
257
  );
258
+ logger.info("presigned.upload.complete", { count: handles.length });
225
259
  return result;
226
260
  },
227
261
  };
package/src/logger.ts ADDED
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Logging interface for the SDK. Customers can plug in their own
3
+ * logger (pino, winston, console) by passing `logger` to createPool;
4
+ * by default we emit structured JSON lines to stdout/stderr so logs
5
+ * are grep-friendly in k8s.
6
+ *
7
+ * The shape mirrors the pipeline-api's logger contract for consistency
8
+ * across the upl.im stack.
9
+ */
10
+
11
+ export type LogLevel = "debug" | "info" | "warn" | "error";
12
+
13
+ export interface Logger {
14
+ debug(event: string, context?: Record<string, unknown>): void;
15
+ info(event: string, context?: Record<string, unknown>): void;
16
+ warn(event: string, context?: Record<string, unknown>): void;
17
+ error(event: string, context?: Record<string, unknown>): void;
18
+ /**
19
+ * Return a derived logger that merges these context fields into every
20
+ * subsequent log call. Used by Pool.handleDispatch to attach jobId /
21
+ * uploadId / urn to every line emitted during the job.
22
+ */
23
+ child(context: Record<string, unknown>): Logger;
24
+ }
25
+
26
+ const SENSITIVE_KEYS = new Set([
27
+ "token",
28
+ "queueToken",
29
+ "queue_token",
30
+ "workerToken",
31
+ "worker_token",
32
+ "updateToken",
33
+ "update_token",
34
+ "authorization",
35
+ "Authorization",
36
+ ]);
37
+
38
+ /**
39
+ * Redact obvious secrets so a careless `logger.info("rpc.request", { headers })`
40
+ * doesn't leak the pool token to log aggregators. Best-effort; not a
41
+ * substitute for thinking about what you're logging.
42
+ */
43
+ function redact(value: unknown): unknown {
44
+ if (value && typeof value === "object" && !Array.isArray(value)) {
45
+ const out: Record<string, unknown> = {};
46
+ for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
47
+ if (SENSITIVE_KEYS.has(k)) {
48
+ out[k] = typeof v === "string" && v.length > 8
49
+ ? `${v.slice(0, 4)}…(${v.length - 4} redacted)`
50
+ : "[redacted]";
51
+ } else if (v && typeof v === "object") {
52
+ out[k] = redact(v);
53
+ } else {
54
+ out[k] = v;
55
+ }
56
+ }
57
+ return out;
58
+ }
59
+ if (Array.isArray(value)) return value.map(redact);
60
+ return value;
61
+ }
62
+
63
+ function serializeError(err: unknown): Record<string, unknown> {
64
+ if (err instanceof Error) {
65
+ return {
66
+ name: err.name,
67
+ message: err.message,
68
+ stack: err.stack,
69
+ ...(err as unknown as Record<string, unknown>),
70
+ };
71
+ }
72
+ return { value: String(err) };
73
+ }
74
+
75
+ /**
76
+ * Default JSON logger. Emits one line per call. `error` and `warn` go to
77
+ * stderr; `info` and `debug` go to stdout. Honors `UPL_LOG_LEVEL` env var
78
+ * (`debug` | `info` | `warn` | `error`) to filter out noise in prod.
79
+ */
80
+ export class JsonLogger implements Logger {
81
+ private readonly base: Record<string, unknown>;
82
+ private readonly minLevel: LogLevel;
83
+
84
+ constructor(base: Record<string, unknown> = {}, minLevel?: LogLevel) {
85
+ this.base = base;
86
+ this.minLevel = minLevel ?? (process.env.UPL_LOG_LEVEL as LogLevel) ?? "info";
87
+ }
88
+
89
+ child(context: Record<string, unknown>): Logger {
90
+ return new JsonLogger({ ...this.base, ...context }, this.minLevel);
91
+ }
92
+
93
+ debug(event: string, context?: Record<string, unknown>): void {
94
+ this.emit("debug", event, context);
95
+ }
96
+ info(event: string, context?: Record<string, unknown>): void {
97
+ this.emit("info", event, context);
98
+ }
99
+ warn(event: string, context?: Record<string, unknown>): void {
100
+ this.emit("warn", event, context);
101
+ }
102
+ error(event: string, context?: Record<string, unknown>): void {
103
+ this.emit("error", event, context);
104
+ }
105
+
106
+ private shouldEmit(level: LogLevel): boolean {
107
+ const order: Record<LogLevel, number> = {
108
+ debug: 10,
109
+ info: 20,
110
+ warn: 30,
111
+ error: 40,
112
+ };
113
+ return order[level] >= order[this.minLevel];
114
+ }
115
+
116
+ private emit(
117
+ level: LogLevel,
118
+ event: string,
119
+ context?: Record<string, unknown>,
120
+ ): void {
121
+ if (!this.shouldEmit(level)) return;
122
+
123
+ const merged: Record<string, unknown> = {
124
+ ...this.base,
125
+ ...(context ? (redact(context) as Record<string, unknown>) : {}),
126
+ };
127
+ if (merged.err !== undefined) {
128
+ merged.err = serializeError(merged.err);
129
+ }
130
+ if (merged.error !== undefined && merged.error instanceof Error) {
131
+ merged.error = serializeError(merged.error);
132
+ }
133
+
134
+ const line = JSON.stringify({
135
+ ts: new Date().toISOString(),
136
+ level,
137
+ logger: "@xeonr/upload-pool-sdk",
138
+ event,
139
+ ...merged,
140
+ });
141
+
142
+ // eslint-disable-next-line no-console
143
+ (level === "error" || level === "warn" ? console.error : console.log)(line);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * No-op logger for tests or callers who want silence. createPool ignores
149
+ * this if `logger` is unset and uses JsonLogger by default.
150
+ */
151
+ export const noopLogger: Logger = {
152
+ debug() {},
153
+ info() {},
154
+ warn() {},
155
+ error() {},
156
+ child() {
157
+ return noopLogger;
158
+ },
159
+ };