@bonsae/node-red-salesforce 0.1.0 → 0.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.
package/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
1
  var P = Object.defineProperty;
2
- var J = (r, o, n) => o in r ? P(r, o, { enumerable: !0, configurable: !0, writable: !0, value: n }) : r[o] = n;
3
- var f = (r, o) => P(r, "name", { value: o, configurable: !0 });
4
- var i = (r, o, n) => J(r, typeof o != "symbol" ? o + "" : o, n);
5
- import { fileURLToPath as V } from "url";
6
- import { dirname as H } from "path";
7
- import { registerTypes as Y } from "@bonsae/nrg/server";
8
- import { defineSchema as h, SchemaType as t, ConfigNode as G, IONode as F, defineModule as K } from "@bonsae/nrg/server";
9
- import W from "jsforce";
10
- import N from "node:crypto";
11
- var Q = V(import.meta.url), Lt = H(Q);
12
- const X = h(
2
+ var B = (a, o, n) => o in a ? P(a, o, { enumerable: !0, configurable: !0, writable: !0, value: n }) : a[o] = n;
3
+ var f = (a, o) => P(a, "name", { value: o, configurable: !0 });
4
+ var i = (a, o, n) => B(a, typeof o != "symbol" ? o + "" : o, n);
5
+ import { fileURLToPath as q } from "url";
6
+ import { dirname as J } from "path";
7
+ import { registerTypes as G } from "@bonsae/nrg/server";
8
+ import { defineSchema as h, SchemaType as t, ConfigNode as Q, IONode as A, defineModule as Y } from "@bonsae/nrg/server";
9
+ import K from "jsforce";
10
+ import M from "node:crypto";
11
+ var V = q(import.meta.url), Lt = J(V);
12
+ const W = h(
13
13
  {
14
14
  name: t.String({ default: "" }),
15
15
  loginUrl: t.String({
@@ -41,74 +41,74 @@ const X = h(
41
41
  )
42
42
  },
43
43
  { $id: "salesforce-connection:config" }
44
- ), Z = h(
44
+ ), X = h(
45
45
  {
46
46
  accessToken: t.String({ default: "", format: "password" }),
47
47
  refreshToken: t.String({ default: "", format: "password" }),
48
48
  instanceUrl: t.String({ default: "" })
49
49
  },
50
50
  { $id: "salesforce-connection:credentials" }
51
- ), z = 600 * 1e3, C = /* @__PURE__ */ new Map();
52
- function B() {
53
- return N.randomBytes(32).toString("base64url");
51
+ ), H = 600 * 1e3, k = /* @__PURE__ */ new Map();
52
+ function Z() {
53
+ return M.randomBytes(32).toString("base64url");
54
54
  }
55
- f(B, "generateCodeVerifier");
56
- function D(r) {
57
- return N.createHash("sha256").update(r).digest("base64url");
55
+ f(Z, "generateCodeVerifier");
56
+ function D(a) {
57
+ return M.createHash("sha256").update(a).digest("base64url");
58
58
  }
59
59
  f(D, "generateCodeChallenge");
60
- function _(r) {
61
- const o = N.randomUUID(), n = B(), e = D(n);
62
- C.set(o, {
60
+ function _(a) {
61
+ const o = M.randomUUID(), n = Z(), e = D(n);
62
+ k.set(o, {
63
63
  codeVerifier: n,
64
- nodeId: r.nodeId,
65
- clientId: r.clientId,
66
- loginUrl: r.loginUrl,
67
- callbackUrl: r.callbackUrl,
64
+ nodeId: a.nodeId,
65
+ clientId: a.clientId,
66
+ loginUrl: a.loginUrl,
67
+ callbackUrl: a.callbackUrl,
68
68
  timestamp: Date.now()
69
69
  });
70
- for (const [s, a] of C)
71
- Date.now() - a.timestamp > z && C.delete(s);
70
+ for (const [s, r] of k)
71
+ Date.now() - r.timestamp > H && k.delete(s);
72
72
  return { state: o, codeChallenge: e };
73
73
  }
74
74
  f(_, "createAuthState");
75
- function tt(r) {
76
- const o = C.get(r);
77
- return !o || (C.delete(r), Date.now() - o.timestamp > z) ? null : o;
75
+ function tt(a) {
76
+ const o = k.get(a);
77
+ return !o || (k.delete(a), Date.now() - o.timestamp > H) ? null : o;
78
78
  }
79
79
  f(tt, "consumeAuthState");
80
- function et(r) {
81
- return r.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
80
+ function et(a) {
81
+ return a.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
82
82
  }
83
83
  f(et, "escapeHtml");
84
- function k(r, o = !0) {
84
+ function F(a, o = !0) {
85
85
  const n = o ? "<script>setTimeout(function(){window.close()},3000)</script>" : "";
86
- return `<html><body><h2>Authorization Failed</h2><p>${et(r)}</p>${n}</body></html>`;
86
+ return `<html><body><h2>Authorization Failed</h2><p>${et(a)}</p>${n}</body></html>`;
87
87
  }
88
- f(k, "errorPage");
89
- function nt(r) {
90
- const o = (r.settings.httpAdminRoot || "").replace(
88
+ f(F, "errorPage");
89
+ function nt(a) {
90
+ const o = (a.settings.httpAdminRoot || "").replace(
91
91
  /\/$/,
92
92
  ""
93
93
  );
94
- r.httpAdmin.post("/salesforce/auth/start", (n, e) => {
94
+ a.httpAdmin.post("/salesforce/auth/start", (n, e) => {
95
95
  try {
96
96
  const {
97
97
  nodeId: s,
98
- loginUrl: a,
98
+ loginUrl: r,
99
99
  clientId: l,
100
100
  callbackUrl: d
101
101
  } = n.body;
102
- if (!s || !a || !l) {
102
+ if (!s || !r || !l) {
103
103
  e.status(400).json({ error: "nodeId, loginUrl, and clientId are required" });
104
104
  return;
105
105
  }
106
106
  const c = d || `${n.protocol}://${n.get("host")}${o}/salesforce/auth/callback`, { state: g, codeChallenge: u } = _({
107
107
  nodeId: s,
108
108
  clientId: l,
109
- loginUrl: a,
109
+ loginUrl: r,
110
110
  callbackUrl: c
111
- }), p = new URLSearchParams({
111
+ }), m = new URLSearchParams({
112
112
  response_type: "code",
113
113
  client_id: l,
114
114
  redirect_uri: c,
@@ -117,30 +117,30 @@ function nt(r) {
117
117
  code_challenge_method: "S256"
118
118
  });
119
119
  e.json({
120
- authorizationUrl: `${a}/services/oauth2/authorize?${p.toString()}`
120
+ authorizationUrl: `${r}/services/oauth2/authorize?${m.toString()}`
121
121
  });
122
122
  } catch (s) {
123
- r.log.error(
123
+ a.log.error(
124
124
  `salesforce-connection: auth/start error: ${s instanceof Error ? s.message : String(s)}`
125
125
  ), e.status(500).json({ error: "Failed to start authorization" });
126
126
  }
127
- }), r.httpAdmin.get("/salesforce/auth/callback", async (n, e) => {
127
+ }), a.httpAdmin.get("/salesforce/auth/callback", async (n, e) => {
128
128
  try {
129
- const { code: s, state: a, error: l, error_description: d } = n.query;
129
+ const { code: s, state: r, error: l, error_description: d } = n.query;
130
130
  if (l) {
131
- r.log.error(
131
+ a.log.error(
132
132
  `salesforce-connection: OAuth error: ${l} - ${d}`
133
- ), e.status(400).send(k(String(d || l)));
133
+ ), e.status(400).send(F(String(d || l)));
134
134
  return;
135
135
  }
136
- if (!s || !a) {
137
- e.status(400).send(k("Missing code or state parameter"));
136
+ if (!s || !r) {
137
+ e.status(400).send(F("Missing code or state parameter"));
138
138
  return;
139
139
  }
140
- const c = tt(a);
140
+ const c = tt(r);
141
141
  if (!c) {
142
142
  e.status(400).send(
143
- k(
143
+ F(
144
144
  "Invalid or expired authorization state. Please try again."
145
145
  )
146
146
  );
@@ -161,25 +161,25 @@ function nt(r) {
161
161
  }
162
162
  );
163
163
  if (!g.ok) {
164
- const w = await g.text();
165
- r.log.error(
166
- `salesforce-connection: Token exchange failed: ${w}`
164
+ const p = await g.text();
165
+ a.log.error(
166
+ `salesforce-connection: Token exchange failed: ${p}`
167
167
  ), e.status(500).send(
168
- k(
168
+ F(
169
169
  "Token exchange failed. Check the Node-RED logs for details."
170
170
  )
171
171
  );
172
172
  return;
173
173
  }
174
174
  const u = await g.json();
175
- r.nodes.addCredentials(c.nodeId, {
175
+ a.nodes.addCredentials(c.nodeId, {
176
176
  accessToken: u.access_token,
177
177
  refreshToken: u.refresh_token,
178
178
  instanceUrl: u.instance_url
179
- }), r.log.info(
179
+ }), a.log.info(
180
180
  `salesforce-connection: Successfully authorized node ${c.nodeId} for ${u.instance_url}`
181
181
  );
182
- const p = JSON.stringify({
182
+ const m = JSON.stringify({
183
183
  type: "salesforce-auth-success",
184
184
  nodeId: c.nodeId,
185
185
  accessToken: u.access_token,
@@ -193,23 +193,23 @@ function nt(r) {
193
193
  <p>You can close this window.</p>
194
194
  <script>
195
195
  if (window.opener) {
196
- window.opener.postMessage(${p}, "*");
196
+ window.opener.postMessage(${m}, "*");
197
197
  }
198
198
  setTimeout(function() { window.close(); }, 1500);
199
199
  </script>
200
200
  </body>
201
201
  </html>`);
202
202
  } catch (s) {
203
- r.log.error(
203
+ a.log.error(
204
204
  `salesforce-connection: auth/callback error: ${s instanceof Error ? s.message : String(s)}`
205
- ), e.status(500).send(k("An unexpected error occurred."));
205
+ ), e.status(500).send(F("An unexpected error occurred."));
206
206
  }
207
- }), r.httpAdmin.get("/salesforce/auth/status/:nodeId", (n, e) => {
207
+ }), a.httpAdmin.get("/salesforce/auth/status/:nodeId", (n, e) => {
208
208
  try {
209
- const s = r.nodes.getCredentials(n.params.nodeId), a = !!(s != null && s.accessToken && (s != null && s.instanceUrl));
209
+ const s = a.nodes.getCredentials(n.params.nodeId), r = !!(s != null && s.accessToken && (s != null && s.instanceUrl));
210
210
  e.json({
211
- authenticated: a,
212
- instanceUrl: a ? s.instanceUrl : void 0
211
+ authenticated: r,
212
+ instanceUrl: r ? s.instanceUrl : void 0
213
213
  });
214
214
  } catch {
215
215
  e.json({ authenticated: !1 });
@@ -217,11 +217,11 @@ function nt(r) {
217
217
  });
218
218
  }
219
219
  f(nt, "initAuthRoutes");
220
- function ot(r) {
221
- nt(r);
220
+ function ot(a) {
221
+ nt(a);
222
222
  }
223
223
  f(ot, "initRoutes");
224
- const L = class L extends G {
224
+ const C = class C extends Q {
225
225
  constructor() {
226
226
  super(...arguments);
227
227
  i(this, "conn", null);
@@ -236,7 +236,7 @@ const L = class L extends G {
236
236
  throw new Error(
237
237
  "Salesforce connection not authorized. Please authorize in the node configuration."
238
238
  );
239
- return this.conn = new W.Connection({
239
+ return this.conn = new K.Connection({
240
240
  oauth2: {
241
241
  clientId: this.config.clientId,
242
242
  loginUrl: this.config.loginUrl
@@ -264,12 +264,12 @@ const L = class L extends G {
264
264
  this.conn = null;
265
265
  }
266
266
  };
267
- f(L, "SalesforceConnection"), i(L, "type", "salesforce-connection"), i(L, "configSchema", X), i(L, "credentialsSchema", Z);
268
- let $ = L;
267
+ f(C, "SalesforceConnection"), i(C, "type", "salesforce-connection"), i(C, "configSchema", W), i(C, "credentialsSchema", X);
268
+ let w = C;
269
269
  const it = h(
270
270
  {
271
271
  name: t.String({ default: "", "x-nrg-form": { icon: "tag" } }),
272
- connection: t.NodeRef($, {
272
+ connection: t.NodeRef(w, {
273
273
  "x-nrg-form": { icon: "cloud" }
274
274
  }),
275
275
  query: t.TypedInput({
@@ -292,7 +292,7 @@ const it = h(
292
292
  done: t.Boolean()
293
293
  },
294
294
  { $id: "salesforce-soql:output" }
295
- ), m = class m extends F {
295
+ ), y = class y extends A {
296
296
  async input(o) {
297
297
  const n = this.config.connection;
298
298
  if (!n) {
@@ -301,16 +301,16 @@ const it = h(
301
301
  }
302
302
  try {
303
303
  this.status({ fill: "green", shape: "dot", text: "querying..." });
304
- const e = await n.getConnection(), s = await this.config.query.resolve(o), a = await e.query(s);
304
+ const e = await n.getConnection(), s = await this.config.query.resolve(o), r = await e.query(s);
305
305
  this.status({
306
306
  fill: "green",
307
307
  shape: "dot",
308
- text: `${a.totalSize} records`
308
+ text: `${r.totalSize} records`
309
309
  }), this.send({
310
310
  ...o,
311
- payload: a.records,
312
- totalSize: a.totalSize,
313
- done: a.done
311
+ payload: r.records,
312
+ totalSize: r.totalSize,
313
+ done: r.done
314
314
  });
315
315
  } catch (e) {
316
316
  this.status({
@@ -324,12 +324,12 @@ const it = h(
324
324
  }
325
325
  }
326
326
  };
327
- f(m, "SalesforceSoql"), i(m, "type", "salesforce-soql"), i(m, "category", "salesforce"), i(m, "color", "#FFFFFF"), i(m, "inputs", 1), i(m, "outputs", 1), i(m, "configSchema", it), i(m, "inputSchema", st), i(m, "outputsSchema", rt);
328
- let O = m;
327
+ f(y, "SalesforceSoql"), i(y, "type", "salesforce-soql"), i(y, "category", "salesforce"), i(y, "color", "#FFFFFF"), i(y, "inputs", 1), i(y, "outputs", 1), i(y, "configSchema", it), i(y, "inputSchema", st), i(y, "outputsSchema", rt);
328
+ let R = y;
329
329
  const at = h(
330
330
  {
331
331
  name: t.String({ default: "", "x-nrg-form": { icon: "tag" } }),
332
- connection: t.NodeRef($, {
332
+ connection: t.NodeRef(w, {
333
333
  "x-nrg-form": { icon: "cloud" }
334
334
  }),
335
335
  operation: t.Union(
@@ -359,7 +359,10 @@ const at = h(
359
359
  default: "",
360
360
  "x-nrg-form": { icon: "key" }
361
361
  })
362
- )
362
+ ),
363
+ emitError: t.Boolean({ default: !1 }),
364
+ emitComplete: t.Boolean({ default: !1 }),
365
+ emitStatus: t.Boolean({ default: !1 })
363
366
  },
364
367
  {
365
368
  $id: "salesforce-dml:config",
@@ -385,7 +388,7 @@ const at = h(
385
388
  payload: t.Any()
386
389
  },
387
390
  { $id: "salesforce-dml:output" }
388
- ), y = class y extends F {
391
+ ), x = class x extends A {
389
392
  async input(o) {
390
393
  const n = this.config.connection;
391
394
  if (!n) {
@@ -395,7 +398,7 @@ const at = h(
395
398
  try {
396
399
  const e = this.config.operation;
397
400
  this.status({ fill: "green", shape: "dot", text: `${e}...` });
398
- const s = await n.getConnection(), a = await this.config.sObjectType.resolve(o), l = s.sobject(a), d = await this.config.record.resolve(o) ?? o.payload;
401
+ const s = await n.getConnection(), r = await this.config.sObjectType.resolve(o), l = s.sobject(r), d = await this.config.record.resolve(o) ?? o.payload;
399
402
  let c;
400
403
  switch (e) {
401
404
  case "create":
@@ -429,12 +432,12 @@ const at = h(
429
432
  }
430
433
  }
431
434
  };
432
- f(y, "SalesforceDml"), i(y, "type", "salesforce-dml"), i(y, "category", "salesforce"), i(y, "color", "#FFFFFF"), i(y, "inputs", 1), i(y, "outputs", 1), i(y, "configSchema", at), i(y, "inputSchema", ct), i(y, "outputsSchema", lt);
433
- let R = y;
435
+ f(x, "SalesforceDml"), i(x, "type", "salesforce-dml"), i(x, "category", "salesforce"), i(x, "color", "#FFFFFF"), i(x, "inputs", 1), i(x, "outputs", 1), i(x, "configSchema", at), i(x, "inputSchema", ct), i(x, "outputsSchema", lt);
436
+ let S = x;
434
437
  const dt = h(
435
438
  {
436
439
  name: t.String({ default: "", "x-nrg-form": { icon: "tag" } }),
437
- connection: t.NodeRef($, {
440
+ connection: t.NodeRef(w, {
438
441
  "x-nrg-form": { icon: "cloud" }
439
442
  }),
440
443
  operation: t.Union(
@@ -494,7 +497,10 @@ const dt = h(
494
497
  default: !1,
495
498
  "x-nrg-form": { icon: "flag", toggle: !0 }
496
499
  }),
497
- outputs: t.Number({ default: 2 })
500
+ outputs: t.Number({ default: 2 }),
501
+ emitError: t.Boolean({ default: !1 }),
502
+ emitComplete: t.Boolean({ default: !1 }),
503
+ emitStatus: t.Boolean({ default: !1 })
498
504
  },
499
505
  {
500
506
  $id: "salesforce-bulk:config",
@@ -522,7 +528,7 @@ h(
522
528
  },
523
529
  { $id: "salesforce-bulk:output" }
524
530
  );
525
- const T = class T extends F {
531
+ const I = class I extends A {
526
532
  sendRecord(o, n) {
527
533
  const e = this.config.emitJobCreated ? 3 : 2, s = Array(e).fill(null);
528
534
  s[0] = { ...o, payload: n }, this.send(s);
@@ -547,7 +553,7 @@ const T = class T extends F {
547
553
  shape: "dot",
548
554
  text: `bulk ${e}...`
549
555
  });
550
- const s = await n.getConnection(), a = await this.config.sObjectType.resolve(o);
556
+ const s = await n.getConnection(), r = await this.config.sObjectType.resolve(o);
551
557
  let l = 0;
552
558
  if (e === "query") {
553
559
  const d = await s.bulk2.query(o.payload, {
@@ -564,11 +570,11 @@ const T = class T extends F {
564
570
  fill: "green",
565
571
  shape: "dot",
566
572
  text: `bulk ${e}: ${l} records`
567
- }), this.sendComplete(o, { operation: e, sObjectType: a, totalRecords: l });
573
+ }), this.sendComplete(o, { operation: e, sObjectType: r, totalRecords: l });
568
574
  } else {
569
575
  const d = o.payload, c = s.bulk2.createJob({
570
576
  operation: e,
571
- object: a,
577
+ object: r,
572
578
  columnDelimiter: this.config.columnDelimiter,
573
579
  lineEnding: this.config.lineEnding,
574
580
  ...e === "upsert" && this.config.externalIdField ? { externalIdFieldName: this.config.externalIdField } : {},
@@ -577,28 +583,28 @@ const T = class T extends F {
577
583
  await c.open(), this.sendJobCreated(o, {
578
584
  jobId: c.id,
579
585
  operation: e,
580
- sObjectType: a,
586
+ sObjectType: r,
581
587
  state: "Open"
582
588
  }), await c.uploadData(d), await c.close(), await c.poll(this.config.pollInterval, this.config.pollTimeout);
583
- const g = await c.getAllResults(), u = g.successfulResults ?? [], p = g.failedResults ?? [], w = g.unprocessedRecords ?? [];
584
- l = u.length + p.length + w.length;
585
- for (const A of u)
586
- this.sendRecord(o, A);
587
- for (const A of p)
588
- this.sendRecord(o, A);
589
- const q = u.length, M = p.length;
589
+ const g = await c.getAllResults(), u = g.successfulResults ?? [], m = g.failedResults ?? [], p = g.unprocessedRecords ?? [];
590
+ l = u.length + m.length + p.length;
591
+ for (const U of u)
592
+ this.sendRecord(o, U);
593
+ for (const U of m)
594
+ this.sendRecord(o, U);
595
+ const L = u.length, z = m.length;
590
596
  this.status({
591
- fill: M > 0 ? "red" : "green",
597
+ fill: z > 0 ? "red" : "green",
592
598
  shape: "dot",
593
599
  text: `bulk ${e}: ${l} records`
594
600
  }), this.sendComplete(o, {
595
601
  jobId: c.id,
596
602
  operation: e,
597
- sObjectType: a,
603
+ sObjectType: r,
598
604
  totalRecords: l,
599
- successCount: q,
600
- failureCount: M,
601
- unprocessedCount: w.length
605
+ successCount: L,
606
+ failureCount: z,
607
+ unprocessedCount: p.length
602
608
  });
603
609
  }
604
610
  } catch (e) {
@@ -607,12 +613,12 @@ const T = class T extends F {
607
613
  }
608
614
  }
609
615
  };
610
- f(T, "SalesforceBulk"), i(T, "type", "salesforce-bulk"), i(T, "category", "salesforce"), i(T, "color", "#FFFFFF"), i(T, "inputs", 1), i(T, "outputs", 2), i(T, "configSchema", dt), i(T, "inputSchema", ut);
611
- let S = T;
616
+ f(I, "SalesforceBulk"), i(I, "type", "salesforce-bulk"), i(I, "category", "salesforce"), i(I, "color", "#FFFFFF"), i(I, "inputs", 1), i(I, "outputs", 2), i(I, "configSchema", dt), i(I, "inputSchema", ut);
617
+ let O = I;
612
618
  const ht = h(
613
619
  {
614
620
  name: t.String({ default: "", "x-nrg-form": { icon: "tag" } }),
615
- connection: t.NodeRef($, {
621
+ connection: t.NodeRef(w, {
616
622
  "x-nrg-form": { icon: "cloud" }
617
623
  }),
618
624
  sObjectType: t.TypedInput({
@@ -620,7 +626,10 @@ const ht = h(
620
626
  icon: "cube",
621
627
  typedInputTypes: ["str", "msg"]
622
628
  }
623
- })
629
+ }),
630
+ emitError: t.Boolean({ default: !1 }),
631
+ emitComplete: t.Boolean({ default: !1 }),
632
+ emitStatus: t.Boolean({ default: !1 })
624
633
  },
625
634
  { $id: "salesforce-describe:config" }
626
635
  ), pt = h(
@@ -638,7 +647,7 @@ const ht = h(
638
647
  })
639
648
  },
640
649
  { $id: "salesforce-describe:output" }
641
- ), b = class b extends F {
650
+ ), b = class b extends A {
642
651
  async input(o) {
643
652
  const n = this.config.connection;
644
653
  if (!n) {
@@ -647,18 +656,18 @@ const ht = h(
647
656
  }
648
657
  try {
649
658
  this.status({ fill: "green", shape: "dot", text: "describing..." });
650
- const e = await n.getConnection(), s = await this.config.sObjectType.resolve(o), a = await e.sobject(s).describe();
659
+ const e = await n.getConnection(), s = await this.config.sObjectType.resolve(o), r = await e.sobject(s).describe();
651
660
  this.status({
652
661
  fill: "green",
653
662
  shape: "dot",
654
- text: `${a.name}: ${a.fields.length} fields`
663
+ text: `${r.name}: ${r.fields.length} fields`
655
664
  }), this.send({
656
665
  ...o,
657
666
  payload: {
658
- name: a.name,
659
- fields: a.fields,
660
- childRelationships: a.childRelationships,
661
- recordTypeInfos: a.recordTypeInfos
667
+ name: r.name,
668
+ fields: r.fields,
669
+ childRelationships: r.childRelationships,
670
+ recordTypeInfos: r.recordTypeInfos
662
671
  }
663
672
  });
664
673
  } catch (e) {
@@ -674,11 +683,11 @@ const ht = h(
674
683
  }
675
684
  };
676
685
  f(b, "SalesforceDescribe"), i(b, "type", "salesforce-describe"), i(b, "category", "salesforce"), i(b, "color", "#FFFFFF"), i(b, "inputs", 1), i(b, "outputs", 1), i(b, "configSchema", ht), i(b, "inputSchema", pt), i(b, "outputsSchema", ft);
677
- let E = b;
686
+ let j = b;
678
687
  const gt = h(
679
688
  {
680
689
  name: t.String({ default: "", "x-nrg-form": { icon: "tag" } }),
681
- connection: t.NodeRef($, {
690
+ connection: t.NodeRef(w, {
682
691
  "x-nrg-form": { icon: "cloud" }
683
692
  }),
684
693
  channelName: t.String({
@@ -704,7 +713,9 @@ const gt = h(
704
713
  minimum: 1,
705
714
  maximum: 100,
706
715
  "x-nrg-form": { icon: "sort-numeric-asc" }
707
- })
716
+ }),
717
+ emitError: t.Boolean({ default: !1 }),
718
+ emitStatus: t.Boolean({ default: !1 })
708
719
  },
709
720
  {
710
721
  $id: "salesforce-streaming:config",
@@ -728,12 +739,15 @@ const gt = h(
728
739
  topic: t.String()
729
740
  },
730
741
  { $id: "salesforce-streaming:output" }
731
- ), I = class I extends F {
742
+ ), $ = class $ extends A {
732
743
  constructor() {
733
744
  super(...arguments);
734
745
  i(this, "client", null);
735
746
  i(this, "reconnectAttempt", 0);
736
747
  i(this, "maxReconnectDelay", 6e4);
748
+ i(this, "maxReconnectAttempts", 10);
749
+ i(this, "grpcErrorHandler", null);
750
+ i(this, "stopped", !1);
737
751
  }
738
752
  async created() {
739
753
  const n = this.config.connection;
@@ -744,71 +758,109 @@ const gt = h(
744
758
  await this.subscribe(n);
745
759
  }
746
760
  async subscribe(n) {
747
- try {
748
- this.status({ fill: "green", shape: "dot", text: "connecting..." });
749
- const e = n.getAccessToken(), s = n.getInstanceUrl();
750
- if (!e || !s) {
751
- this.status({ fill: "red", shape: "dot", text: "not authorized" }), this.error("Salesforce connection not authorized");
752
- return;
761
+ if (!this.stopped)
762
+ try {
763
+ this.status({ fill: "green", shape: "dot", text: "connecting..." });
764
+ let e;
765
+ try {
766
+ e = await n.getConnection(), await e.identity();
767
+ } catch {
768
+ this.status({ fill: "red", shape: "dot", text: "auth expired" }), this.error("Salesforce token expired. Re-authorize the connection.");
769
+ return;
770
+ }
771
+ const s = n.getAccessToken(), r = n.getInstanceUrl();
772
+ if (!s || !r) {
773
+ this.status({ fill: "red", shape: "dot", text: "not authorized" }), this.error("Salesforce connection not authorized");
774
+ return;
775
+ }
776
+ const l = (await import("salesforce-pubsub-api-client")).default;
777
+ this.client = new l({
778
+ authType: "user-supplied",
779
+ accessToken: s,
780
+ instanceUrl: r
781
+ }), await this.client.connect();
782
+ const d = this.config.numRequested || null, c = this.config.channelName, g = /* @__PURE__ */ f((u, m, p) => {
783
+ if (m === "event" || m === "lastevent")
784
+ this.send({
785
+ payload: (p == null ? void 0 : p.payload) ?? p,
786
+ replayId: p == null ? void 0 : p.replayId,
787
+ channel: c,
788
+ topic: c
789
+ });
790
+ else if (m === "error") {
791
+ const L = p instanceof Error ? p.message : String(p ?? "stream error");
792
+ if (this.warn(`Streaming error: ${L}`), L.includes("UNAUTHENTICATED") || L.includes("authentication")) {
793
+ this.stopped = !0, this.status({
794
+ fill: "red",
795
+ shape: "dot",
796
+ text: "auth expired — re-authorize"
797
+ }), this.error(
798
+ "Salesforce token expired. Re-authorize the connection."
799
+ ), this.cleanup();
800
+ return;
801
+ }
802
+ this.status({ fill: "red", shape: "dot", text: L }), this.scheduleReconnect(n);
803
+ } else if (m === "end") {
804
+ if (this.stopped) return;
805
+ this.log("Streaming subscription ended"), this.status({ fill: "red", shape: "dot", text: "disconnected" }), this.scheduleReconnect(n);
806
+ }
807
+ }, "callback");
808
+ if (this.grpcErrorHandler && process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = (u) => {
809
+ var m, p;
810
+ ((m = u.message) != null && m.includes("UNAUTHENTICATED") || (p = u.message) != null && p.includes("authentication")) && (this.stopped = !0, this.warn(`Caught gRPC auth error: ${u.message}`), this.status({
811
+ fill: "red",
812
+ shape: "dot",
813
+ text: "auth expired — re-authorize"
814
+ }), this.cleanup());
815
+ }, process.on("uncaughtException", this.grpcErrorHandler), this.config.subscribeType === "EARLIEST")
816
+ this.client.subscribeFromEarliestEvent(
817
+ c,
818
+ g,
819
+ d
820
+ );
821
+ else if (this.config.subscribeType === "CUSTOM" && this.config.replayId) {
822
+ const u = parseInt(this.config.replayId, 10);
823
+ this.client.subscribeFromReplayId(
824
+ c,
825
+ g,
826
+ d,
827
+ u
828
+ );
829
+ } else
830
+ this.client.subscribe(c, g, d);
831
+ this.status({
832
+ fill: "green",
833
+ shape: "dot",
834
+ text: `subscribed: ${c}`
835
+ }), this.reconnectAttempt = 0;
836
+ } catch (e) {
837
+ this.status({
838
+ fill: "red",
839
+ shape: "dot",
840
+ text: e instanceof Error ? e.message : String(e)
841
+ }), this.error(
842
+ `Streaming subscription failed: ${e instanceof Error ? e.message : String(e)}`
843
+ ), this.scheduleReconnect(n);
753
844
  }
754
- const a = (await import("salesforce-pubsub-api-client")).default;
755
- this.client = new a({
756
- authType: "user-supplied",
757
- accessToken: e,
758
- instanceUrl: s
759
- }), await this.client.connect();
760
- const l = this.config.numRequested || null, d = this.config.channelName, c = /* @__PURE__ */ f((g, u, p) => {
761
- if (u === "event" || u === "lastevent")
762
- this.send({
763
- payload: (p == null ? void 0 : p.payload) ?? p,
764
- replayId: p == null ? void 0 : p.replayId,
765
- channel: d,
766
- topic: d
767
- });
768
- else if (u === "error") {
769
- const w = p instanceof Error ? p.message : String(p ?? "stream error");
770
- this.warn(`Streaming error: ${w}`), this.status({ fill: "red", shape: "dot", text: w }), this.scheduleReconnect(n);
771
- } else u === "end" && (this.log("Streaming subscription ended"), this.status({ fill: "red", shape: "dot", text: "disconnected" }), this.scheduleReconnect(n));
772
- }, "callback");
773
- if (this.config.subscribeType === "EARLIEST")
774
- this.client.subscribeFromEarliestEvent(
775
- d,
776
- c,
777
- l
778
- );
779
- else if (this.config.subscribeType === "CUSTOM" && this.config.replayId) {
780
- const g = parseInt(this.config.replayId, 10);
781
- this.client.subscribeFromReplayId(
782
- d,
783
- c,
784
- l,
785
- g
786
- );
787
- } else
788
- this.client.subscribe(d, c, l);
789
- this.status({
790
- fill: "green",
791
- shape: "dot",
792
- text: `subscribed: ${d}`
793
- }), this.reconnectAttempt = 0;
794
- } catch (e) {
795
- this.status({
845
+ }
846
+ scheduleReconnect(n) {
847
+ if (this.stopped) return;
848
+ if (this.reconnectAttempt++, this.reconnectAttempt > this.maxReconnectAttempts) {
849
+ this.error(
850
+ `Streaming: max reconnect attempts (${this.maxReconnectAttempts}) reached. Giving up.`
851
+ ), this.status({
796
852
  fill: "red",
797
853
  shape: "dot",
798
- text: e instanceof Error ? e.message : String(e)
799
- }), this.error(
800
- `Streaming subscription failed: ${e instanceof Error ? e.message : String(e)}`
801
- ), this.scheduleReconnect(n);
854
+ text: "reconnect failed re-deploy to retry"
855
+ });
856
+ return;
802
857
  }
803
- }
804
- scheduleReconnect(n) {
805
- this.reconnectAttempt++;
806
858
  const e = Math.min(
807
859
  1e3 * Math.pow(2, this.reconnectAttempt),
808
860
  this.maxReconnectDelay
809
861
  );
810
862
  this.log(
811
- `Scheduling reconnect in ${e}ms (attempt ${this.reconnectAttempt})`
863
+ `Scheduling reconnect in ${e}ms (attempt ${this.reconnectAttempt}/${this.maxReconnectAttempts})`
812
864
  ), this.status({
813
865
  fill: "green",
814
866
  shape: "dot",
@@ -820,7 +872,7 @@ const gt = h(
820
872
  async cleanup() {
821
873
  var n, e;
822
874
  try {
823
- this.client && (await ((e = (n = this.client).close) == null ? void 0 : e.call(n)), this.client = null);
875
+ this.grpcErrorHandler && (process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = null), this.client && (await ((e = (n = this.client).close) == null ? void 0 : e.call(n)), this.client = null);
824
876
  } catch {
825
877
  }
826
878
  }
@@ -830,12 +882,12 @@ const gt = h(
830
882
  await this.cleanup();
831
883
  }
832
884
  };
833
- f(I, "SalesforceStreaming"), i(I, "type", "salesforce-streaming"), i(I, "category", "salesforce"), i(I, "color", "#FFFFFF"), i(I, "inputs", 0), i(I, "outputs", 1), i(I, "configSchema", gt), i(I, "outputsSchema", mt);
834
- let j = I;
885
+ f($, "SalesforceStreaming"), i($, "type", "salesforce-streaming"), i($, "category", "salesforce"), i($, "color", "#FFFFFF"), i($, "inputs", 0), i($, "outputs", 1), i($, "configSchema", gt), i($, "outputsSchema", mt);
886
+ let v = $;
835
887
  const yt = h(
836
888
  {
837
889
  name: t.String({ default: "", "x-nrg-form": { icon: "tag" } }),
838
- connection: t.NodeRef($, {
890
+ connection: t.NodeRef(w, {
839
891
  "x-nrg-form": { icon: "cloud" }
840
892
  }),
841
893
  method: t.Union(
@@ -853,20 +905,23 @@ const yt = h(
853
905
  icon: "link",
854
906
  typedInputTypes: ["str", "msg"]
855
907
  }
856
- })
908
+ }),
909
+ emitError: t.Boolean({ default: !1 }),
910
+ emitComplete: t.Boolean({ default: !1 }),
911
+ emitStatus: t.Boolean({ default: !1 })
857
912
  },
858
913
  { $id: "salesforce-apex:config" }
859
- ), bt = h(
914
+ ), xt = h(
860
915
  {
861
916
  payload: t.Any()
862
917
  },
863
918
  { $id: "salesforce-apex:input" }
864
- ), xt = h(
919
+ ), bt = h(
865
920
  {
866
921
  payload: t.Any()
867
922
  },
868
923
  { $id: "salesforce-apex:output" }
869
- ), x = class x extends F {
924
+ ), T = class T extends A {
870
925
  async input(o) {
871
926
  const n = this.config.connection;
872
927
  if (!n) {
@@ -876,10 +931,10 @@ const yt = h(
876
931
  try {
877
932
  const e = this.config.method;
878
933
  this.status({ fill: "green", shape: "dot", text: `${e}...` });
879
- const s = await n.getConnection(), a = await this.config.path.resolve(o);
934
+ const s = await n.getConnection(), r = await this.config.path.resolve(o);
880
935
  let l;
881
936
  const d = e.toLowerCase();
882
- d === "get" || d === "delete" ? l = await s.apex[d](a) : l = await s.apex[d](a, o.payload), this.status({ fill: "green", shape: "dot", text: `${e} done` }), this.send({ ...o, payload: l });
937
+ d === "get" || d === "delete" ? l = await s.apex[d](r) : l = await s.apex[d](r, o.payload), this.status({ fill: "green", shape: "dot", text: `${e} done` }), this.send({ ...o, payload: l });
883
938
  } catch (e) {
884
939
  this.status({
885
940
  fill: "red",
@@ -892,22 +947,22 @@ const yt = h(
892
947
  }
893
948
  }
894
949
  };
895
- f(x, "SalesforceApex"), i(x, "type", "salesforce-apex"), i(x, "category", "salesforce"), i(x, "color", "#FFFFFF"), i(x, "inputs", 1), i(x, "outputs", 1), i(x, "configSchema", yt), i(x, "inputSchema", bt), i(x, "outputsSchema", xt);
896
- let v = x;
897
- const Tt = K({
950
+ f(T, "SalesforceApex"), i(T, "type", "salesforce-apex"), i(T, "category", "salesforce"), i(T, "color", "#FFFFFF"), i(T, "inputs", 1), i(T, "outputs", 1), i(T, "configSchema", yt), i(T, "inputSchema", xt), i(T, "outputsSchema", bt);
951
+ let N = T;
952
+ const Tt = Y({
898
953
  nodes: [
899
- $,
900
- O,
954
+ w,
901
955
  R,
902
956
  S,
903
- E,
957
+ O,
904
958
  j,
905
- v
959
+ v,
960
+ N
906
961
  ]
907
962
  });
908
- var U = Tt;
909
- U && typeof U == "object" && Array.isArray(U.nodes) && (U = Y(U.nodes));
963
+ var E = Tt;
964
+ E && typeof E == "object" && Array.isArray(E.nodes) && (E = G(E.nodes));
910
965
  export {
911
- U as default
966
+ E as default
912
967
  };
913
968
  //# sourceMappingURL=index.mjs.map