@bonsae/node-red-salesforce 0.4.0 → 0.5.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
- var z = Object.defineProperty;
2
- var q = (a, o, n) => o in a ? z(a, o, { enumerable: !0, configurable: !0, writable: !0, value: n }) : a[o] = n;
3
- var f = (a, o) => z(a, "name", { value: o, configurable: !0 });
4
- var i = (a, o, n) => q(a, typeof o != "symbol" ? o + "" : o, n);
5
- import { fileURLToPath as B } 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 e, ConfigNode as Q, IONode as k, defineModule as Y } from "@bonsae/nrg/server";
9
- import K from "jsforce";
10
- import M from "node:crypto";
11
- var V = B(import.meta.url), ke = J(V);
12
- const W = h(
1
+ var D = Object.defineProperty;
2
+ var J = (a, s, t) => s in a ? D(a, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[s] = t;
3
+ var d = (a, s) => D(a, "name", { value: s, configurable: !0 });
4
+ var r = (a, s, t) => J(a, typeof s != "symbol" ? s + "" : s, t);
5
+ import { fileURLToPath as Q } from "url";
6
+ import { dirname as X } from "path";
7
+ import { registerTypes as K } from "@bonsae/nrg/server";
8
+ import { defineSchema as p, SchemaType as e, ConfigNode as Z, IONode as A, defineModule as _ } from "@bonsae/nrg/server";
9
+ import V from "jsforce";
10
+ import z from "node:crypto";
11
+ var W = Q(import.meta.url), Be = X(W);
12
+ const ee = p(
13
13
  {
14
14
  name: e.String({ default: "" }),
15
15
  loginUrl: e.String({
@@ -41,152 +41,152 @@ const W = h(
41
41
  )
42
42
  },
43
43
  { $id: "salesforce-connection:config" }
44
- ), X = h(
44
+ ), te = p(
45
45
  {
46
46
  accessToken: e.String({ default: "", format: "password" }),
47
47
  refreshToken: e.String({ default: "", format: "password" }),
48
48
  instanceUrl: e.String({ default: "" })
49
49
  },
50
50
  { $id: "salesforce-connection:credentials" }
51
- ), H = 600 * 1e3, E = /* @__PURE__ */ new Map();
52
- function Z() {
53
- return M.randomBytes(32).toString("base64url");
51
+ ), G = 600 * 1e3, O = /* @__PURE__ */ new Map();
52
+ function ne() {
53
+ return z.randomBytes(32).toString("base64url");
54
54
  }
55
- f(Z, "generateCodeVerifier");
56
- function D(a) {
57
- return M.createHash("sha256").update(a).digest("base64url");
55
+ d(ne, "generateCodeVerifier");
56
+ function se(a) {
57
+ return z.createHash("sha256").update(a).digest("base64url");
58
58
  }
59
- f(D, "generateCodeChallenge");
60
- function _(a) {
61
- const o = M.randomUUID(), n = Z(), t = D(n);
62
- E.set(o, {
63
- codeVerifier: n,
59
+ d(se, "generateCodeChallenge");
60
+ function oe(a) {
61
+ const s = z.randomUUID(), t = ne(), n = se(t);
62
+ O.set(s, {
63
+ codeVerifier: t,
64
64
  nodeId: a.nodeId,
65
65
  clientId: a.clientId,
66
66
  loginUrl: a.loginUrl,
67
67
  callbackUrl: a.callbackUrl,
68
68
  timestamp: Date.now()
69
69
  });
70
- for (const [r, s] of E)
71
- Date.now() - s.timestamp > H && E.delete(r);
72
- return { state: o, codeChallenge: t };
70
+ for (const [o, i] of O)
71
+ Date.now() - i.timestamp > G && O.delete(o);
72
+ return { state: s, codeChallenge: n };
73
73
  }
74
- f(_, "createAuthState");
75
- function ee(a) {
76
- const o = E.get(a);
77
- return !o || (E.delete(a), Date.now() - o.timestamp > H) ? null : o;
74
+ d(oe, "createAuthState");
75
+ function ie(a) {
76
+ const s = O.get(a);
77
+ return !s || (O.delete(a), Date.now() - s.timestamp > G) ? null : s;
78
78
  }
79
- f(ee, "consumeAuthState");
80
- function te(a) {
79
+ d(ie, "consumeAuthState");
80
+ function re(a) {
81
81
  return a.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
82
82
  }
83
- f(te, "escapeHtml");
84
- function A(a, o = !0) {
85
- const n = o ? "<script>setTimeout(function(){window.close()},3000)</script>" : "";
86
- return `<html><body><h2>Authorization Failed</h2><p>${te(a)}</p>${n}</body></html>`;
83
+ d(re, "escapeHtml");
84
+ function F(a, s = !0) {
85
+ const t = s ? "<script>setTimeout(function(){window.close()},3000)</script>" : "";
86
+ return `<html><body><h2>Authorization Failed</h2><p>${re(a)}</p>${t}</body></html>`;
87
87
  }
88
- f(A, "errorPage");
89
- function ne(a) {
90
- const o = (a.settings.httpAdminRoot || "").replace(
88
+ d(F, "errorPage");
89
+ function ae(a) {
90
+ const s = (a.settings.httpAdminRoot || "").replace(
91
91
  /\/$/,
92
92
  ""
93
93
  );
94
- a.httpAdmin.post("/salesforce/auth/start", (n, t) => {
94
+ a.httpAdmin.post("/salesforce/auth/start", (t, n) => {
95
95
  try {
96
96
  const {
97
- nodeId: r,
98
- loginUrl: s,
99
- clientId: l,
100
- callbackUrl: d
101
- } = n.body;
102
- if (!r || !s || !l) {
103
- t.status(400).json({ error: "nodeId, loginUrl, and clientId are required" });
97
+ nodeId: o,
98
+ loginUrl: i,
99
+ clientId: c,
100
+ callbackUrl: u
101
+ } = t.body;
102
+ if (!o || !i || !c) {
103
+ n.status(400).json({ error: "nodeId, loginUrl, and clientId are required" });
104
104
  return;
105
105
  }
106
- const c = d || `${n.protocol}://${n.get("host")}${o}/salesforce/auth/callback`, { state: g, codeChallenge: u } = _({
107
- nodeId: r,
108
- clientId: l,
109
- loginUrl: s,
110
- callbackUrl: c
106
+ const l = u || `${t.protocol}://${t.get("host")}${s}/salesforce/auth/callback`, { state: h, codeChallenge: f } = oe({
107
+ nodeId: o,
108
+ clientId: c,
109
+ loginUrl: i,
110
+ callbackUrl: l
111
111
  }), m = new URLSearchParams({
112
112
  response_type: "code",
113
- client_id: l,
114
- redirect_uri: c,
115
- state: g,
116
- code_challenge: u,
113
+ client_id: c,
114
+ redirect_uri: l,
115
+ state: h,
116
+ code_challenge: f,
117
117
  code_challenge_method: "S256"
118
118
  });
119
- t.json({
120
- authorizationUrl: `${s}/services/oauth2/authorize?${m.toString()}`
119
+ n.json({
120
+ authorizationUrl: `${i}/services/oauth2/authorize?${m.toString()}`
121
121
  });
122
- } catch (r) {
122
+ } catch (o) {
123
123
  a.log.error(
124
- `salesforce-connection: auth/start error: ${r instanceof Error ? r.message : String(r)}`
125
- ), t.status(500).json({ error: "Failed to start authorization" });
124
+ `salesforce-connection: auth/start error: ${o instanceof Error ? o.message : String(o)}`
125
+ ), n.status(500).json({ error: "Failed to start authorization" });
126
126
  }
127
- }), a.httpAdmin.get("/salesforce/auth/callback", async (n, t) => {
127
+ }), a.httpAdmin.get("/salesforce/auth/callback", async (t, n) => {
128
128
  try {
129
- const { code: r, state: s, error: l, error_description: d } = n.query;
130
- if (l) {
129
+ const { code: o, state: i, error: c, error_description: u } = t.query;
130
+ if (c) {
131
131
  a.log.error(
132
- `salesforce-connection: OAuth error: ${l} - ${d}`
133
- ), t.status(400).send(A(String(d || l)));
132
+ `salesforce-connection: OAuth error: ${c} - ${u}`
133
+ ), n.status(400).send(F(String(u || c)));
134
134
  return;
135
135
  }
136
- if (!r || !s) {
137
- t.status(400).send(A("Missing code or state parameter"));
136
+ if (!o || !i) {
137
+ n.status(400).send(F("Missing code or state parameter"));
138
138
  return;
139
139
  }
140
- const c = ee(s);
141
- if (!c) {
142
- t.status(400).send(
143
- A(
140
+ const l = ie(i);
141
+ if (!l) {
142
+ n.status(400).send(
143
+ F(
144
144
  "Invalid or expired authorization state. Please try again."
145
145
  )
146
146
  );
147
147
  return;
148
148
  }
149
- const g = await fetch(
150
- `${c.loginUrl}/services/oauth2/token`,
149
+ const h = await fetch(
150
+ `${l.loginUrl}/services/oauth2/token`,
151
151
  {
152
152
  method: "POST",
153
153
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
154
154
  body: new URLSearchParams({
155
155
  grant_type: "authorization_code",
156
- code: r,
157
- client_id: c.clientId,
158
- redirect_uri: c.callbackUrl,
159
- code_verifier: c.codeVerifier
156
+ code: o,
157
+ client_id: l.clientId,
158
+ redirect_uri: l.callbackUrl,
159
+ code_verifier: l.codeVerifier
160
160
  })
161
161
  }
162
162
  );
163
- if (!g.ok) {
164
- const p = await g.text();
163
+ if (!h.ok) {
164
+ const g = await h.text();
165
165
  a.log.error(
166
- `salesforce-connection: Token exchange failed: ${p}`
167
- ), t.status(500).send(
168
- A(
166
+ `salesforce-connection: Token exchange failed: ${g}`
167
+ ), n.status(500).send(
168
+ F(
169
169
  "Token exchange failed. Check the Node-RED logs for details."
170
170
  )
171
171
  );
172
172
  return;
173
173
  }
174
- const u = await g.json();
175
- a.nodes.addCredentials(c.nodeId, {
176
- accessToken: u.access_token,
177
- refreshToken: u.refresh_token,
178
- instanceUrl: u.instance_url
174
+ const f = await h.json();
175
+ a.nodes.addCredentials(l.nodeId, {
176
+ accessToken: f.access_token,
177
+ refreshToken: f.refresh_token,
178
+ instanceUrl: f.instance_url
179
179
  }), a.log.info(
180
- `salesforce-connection: Successfully authorized node ${c.nodeId} for ${u.instance_url}`
180
+ `salesforce-connection: Successfully authorized node ${l.nodeId} for ${f.instance_url}`
181
181
  );
182
182
  const m = JSON.stringify({
183
183
  type: "salesforce-auth-success",
184
- nodeId: c.nodeId,
185
- accessToken: u.access_token,
186
- refreshToken: u.refresh_token,
187
- instanceUrl: u.instance_url
184
+ nodeId: l.nodeId,
185
+ accessToken: f.access_token,
186
+ refreshToken: f.refresh_token,
187
+ instanceUrl: f.instance_url
188
188
  });
189
- t.send(`<!DOCTYPE html>
189
+ n.send(`<!DOCTYPE html>
190
190
  <html>
191
191
  <body>
192
192
  <h2>Authorization Successful</h2>
@@ -199,77 +199,247 @@ function ne(a) {
199
199
  </script>
200
200
  </body>
201
201
  </html>`);
202
- } catch (r) {
202
+ } catch (o) {
203
203
  a.log.error(
204
- `salesforce-connection: auth/callback error: ${r instanceof Error ? r.message : String(r)}`
205
- ), t.status(500).send(A("An unexpected error occurred."));
204
+ `salesforce-connection: auth/callback error: ${o instanceof Error ? o.message : String(o)}`
205
+ ), n.status(500).send(F("An unexpected error occurred."));
206
206
  }
207
- }), a.httpAdmin.get("/salesforce/auth/status/:nodeId", (n, t) => {
207
+ }), a.httpAdmin.get("/salesforce/auth/status/:nodeId", (t, n) => {
208
208
  try {
209
- const r = a.nodes.getCredentials(n.params.nodeId), s = !!(r != null && r.accessToken && (r != null && r.instanceUrl));
210
- t.json({
211
- authenticated: s,
212
- instanceUrl: s ? r.instanceUrl : void 0
209
+ const o = a.nodes.getCredentials(t.params.nodeId), i = !!(o != null && o.accessToken && (o != null && o.instanceUrl));
210
+ n.json({
211
+ authenticated: i,
212
+ instanceUrl: i ? o.instanceUrl : void 0
213
213
  });
214
214
  } catch {
215
- t.json({ authenticated: !1 });
215
+ n.json({ authenticated: !1 });
216
216
  }
217
217
  });
218
218
  }
219
- f(ne, "initAuthRoutes");
220
- function oe(a) {
221
- ne(a);
219
+ d(ae, "initAuthRoutes");
220
+ function Y(a, s) {
221
+ const t = a.nodes.getCredentials(s);
222
+ if (!(t != null && t.accessToken) || !(t != null && t.instanceUrl))
223
+ throw new Error("Connection not authenticated");
224
+ return new V.Connection({
225
+ instanceUrl: t.instanceUrl,
226
+ accessToken: t.accessToken
227
+ });
222
228
  }
223
- f(oe, "initRoutes");
224
- const L = class L extends Q {
229
+ d(Y, "getConnection");
230
+ const b = class b {
231
+ constructor(s) {
232
+ r(this, "conn");
233
+ this.conn = s;
234
+ }
235
+ // --- Apex REST ---
236
+ async invoke(s, t) {
237
+ const n = this.conn.version || "62.0", i = (await this.conn.request({
238
+ method: "POST",
239
+ url: `/services/data/v${n}/actions/custom/apex/${s}`,
240
+ body: JSON.stringify({
241
+ inputs: [{ payload: JSON.stringify(t) }]
242
+ }),
243
+ headers: { "Content-Type": "application/json" }
244
+ }))[0];
245
+ if (!i.isSuccess) {
246
+ const c = i.errors.map((u) => u.message).join("; ");
247
+ throw new Error(`Invocable action failed: ${c}`);
248
+ }
249
+ return i;
250
+ }
251
+ async post(s, t) {
252
+ return await this.conn.apex.post(
253
+ s,
254
+ t
255
+ );
256
+ }
257
+ async get(s) {
258
+ return await this.conn.apex.get(s);
259
+ }
260
+ async put(s, t) {
261
+ return await this.conn.apex.put(
262
+ s,
263
+ t
264
+ );
265
+ }
266
+ async patch(s, t) {
267
+ return await this.conn.apex.patch(
268
+ s,
269
+ t
270
+ );
271
+ }
272
+ async delete(s) {
273
+ return await this.conn.apex.delete(s);
274
+ }
275
+ // --- Tooling API ---
276
+ async queryApexClassesByName(s) {
277
+ const t = s.map((i) => `'${i}'`).join(","), n = await this.conn.tooling.query(
278
+ `SELECT Id, Name, Body FROM ApexClass WHERE Name IN (${t})`
279
+ ), o = /* @__PURE__ */ new Map();
280
+ for (const i of n.records)
281
+ o.set(i.Name, {
282
+ Id: i.Id,
283
+ Name: i.Name,
284
+ Body: i.Body
285
+ });
286
+ return o;
287
+ }
288
+ async createApexClass(s, t) {
289
+ return this.withRetry(async () => {
290
+ var o;
291
+ const n = await this.conn.tooling.create("ApexClass", {
292
+ Name: s,
293
+ Body: t
294
+ });
295
+ if (!n.success) {
296
+ const i = (o = n.errors) == null ? void 0 : o.map((c) => c.message).join("; ");
297
+ throw new Error(`Apex create failed: ${i}`);
298
+ }
299
+ return { id: n.id };
300
+ }, `create ${s}`);
301
+ }
302
+ async deleteApexClass(s) {
303
+ await this.withRetry(
304
+ () => this.conn.tooling.destroy("ApexClass", s),
305
+ `delete ${s}`
306
+ );
307
+ }
308
+ async queryApexRestAndInvocableClasses() {
309
+ var o, i;
310
+ const s = await this.conn.tooling.query(
311
+ "SELECT Name, Body FROM ApexClass ORDER BY Name"
312
+ ), t = [], n = [];
313
+ for (const c of s.records) {
314
+ if ((o = c.Body) != null && o.includes("@RestResource")) {
315
+ const u = c.Body.match(
316
+ /@RestResource\s*\(\s*urlMapping\s*=\s*'([^']+)'/
317
+ );
318
+ t.push({ name: c.Name, urlMapping: u ? u[1] : void 0 });
319
+ }
320
+ (i = c.Body) != null && i.includes("@InvocableMethod") && n.push({ name: c.Name });
321
+ }
322
+ return { rest: t, invocable: n };
323
+ }
324
+ // --- Streaming ---
325
+ async queryStreamingChannels() {
326
+ const s = await this.conn.describeGlobal(), t = [];
327
+ for (const n of s.sobjects)
328
+ n.name.endsWith("__e") ? t.push({
329
+ value: `/event/${n.name}`,
330
+ label: `${n.label} (${n.name})`,
331
+ group: "Platform Events"
332
+ }) : n.name.endsWith("ChangeEvent") && t.push({
333
+ value: `/data/${n.name}`,
334
+ label: `${n.label} (${n.name})`,
335
+ group: "Change Data Capture"
336
+ });
337
+ return t.push({
338
+ value: "/data/ChangeEvents",
339
+ label: "All Change Events",
340
+ group: "Change Data Capture"
341
+ }), t;
342
+ }
343
+ // --- Retry ---
344
+ async withRetry(s, t) {
345
+ for (let n = 1; n <= b.MAX_RETRIES; n++)
346
+ try {
347
+ return await s();
348
+ } catch (o) {
349
+ if (n === b.MAX_RETRIES) throw o;
350
+ const i = b.RETRY_DELAY_MS * n;
351
+ console.warn(
352
+ `[SalesforceClient] ${t} failed (attempt ${n}/${b.MAX_RETRIES}), retrying in ${i}ms...`
353
+ ), await new Promise((c) => setTimeout(c, i));
354
+ }
355
+ throw new Error("unreachable");
356
+ }
357
+ };
358
+ d(b, "SalesforceClient"), r(b, "MAX_RETRIES", 3), r(b, "RETRY_DELAY_MS", 1e3);
359
+ let R = b;
360
+ function ce(a) {
361
+ a.httpAdmin.get(
362
+ "/salesforce/list-apex-classes/:nodeId",
363
+ async (s, t) => {
364
+ try {
365
+ const n = Y(a, s.params.nodeId), o = new R(n);
366
+ t.json(await o.queryApexRestAndInvocableClasses());
367
+ } catch (n) {
368
+ const o = n instanceof Error ? n.message : String(n);
369
+ t.status(500).json({ error: o });
370
+ }
371
+ }
372
+ );
373
+ }
374
+ d(ce, "initApexRoutes");
375
+ function le(a) {
376
+ a.httpAdmin.get(
377
+ "/salesforce/list-streaming-channels/:nodeId",
378
+ async (s, t) => {
379
+ try {
380
+ const n = Y(a, s.params.nodeId), o = new R(n);
381
+ t.json(await o.queryStreamingChannels());
382
+ } catch (n) {
383
+ const o = n instanceof Error ? n.message : String(n);
384
+ t.status(500).json({ error: o });
385
+ }
386
+ }
387
+ );
388
+ }
389
+ d(le, "initStreamingRoutes");
390
+ function ue(a) {
391
+ ae(a), ce(a), le(a);
392
+ }
393
+ d(ue, "initRoutes");
394
+ const v = class v extends Z {
225
395
  constructor() {
226
396
  super(...arguments);
227
- i(this, "conn", null);
397
+ r(this, "conn", null);
228
398
  }
229
- static async registered(n) {
230
- oe(n);
399
+ static async registered(t) {
400
+ ue(t);
231
401
  }
232
402
  async getConnection() {
233
403
  if (this.conn) return this.conn;
234
- const n = this.credentials;
235
- if (!(n != null && n.accessToken) || !(n != null && n.instanceUrl))
404
+ const t = this.credentials;
405
+ if (!(t != null && t.accessToken) || !(t != null && t.instanceUrl))
236
406
  throw new Error(
237
407
  "Salesforce connection not authorized. Please authorize in the node configuration."
238
408
  );
239
- return this.conn = new K.Connection({
409
+ return this.conn = new V.Connection({
240
410
  oauth2: {
241
411
  clientId: this.config.clientId,
242
412
  loginUrl: this.config.loginUrl
243
413
  },
244
- instanceUrl: n.instanceUrl,
245
- accessToken: n.accessToken,
246
- refreshToken: n.refreshToken,
414
+ instanceUrl: t.instanceUrl,
415
+ accessToken: t.accessToken,
416
+ refreshToken: t.refreshToken,
247
417
  version: this.config.apiVersion
248
- }), this.conn.on("refresh", (t) => {
418
+ }), this.conn.on("refresh", (n) => {
249
419
  this.RED.nodes.addCredentials(this.id, {
250
420
  ...this.credentials,
251
- accessToken: t
421
+ accessToken: n
252
422
  });
253
423
  }), this.conn;
254
424
  }
255
425
  getAccessToken() {
256
- var n;
257
- return (n = this.credentials) == null ? void 0 : n.accessToken;
426
+ var t;
427
+ return (t = this.credentials) == null ? void 0 : t.accessToken;
258
428
  }
259
429
  getInstanceUrl() {
260
- var n;
261
- return (n = this.credentials) == null ? void 0 : n.instanceUrl;
430
+ var t;
431
+ return (t = this.credentials) == null ? void 0 : t.instanceUrl;
262
432
  }
263
433
  async closed() {
264
434
  this.conn = null;
265
435
  }
266
436
  };
267
- f(L, "SalesforceConnection"), i(L, "type", "salesforce-connection"), i(L, "configSchema", W), i(L, "credentialsSchema", X);
268
- let $ = L;
269
- const ie = h(
437
+ d(v, "SalesforceConnection"), r(v, "type", "salesforce-connection"), r(v, "configSchema", ee), r(v, "credentialsSchema", te);
438
+ let w = v;
439
+ const de = p(
270
440
  {
271
441
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
272
- connection: e.NodeRef($, {
442
+ connection: e.NodeRef(w, {
273
443
  "x-nrg-form": { icon: "cloud" }
274
444
  }),
275
445
  query: e.TypedInput({
@@ -277,59 +447,62 @@ const ie = h(
277
447
  icon: "search",
278
448
  typedInputTypes: ["str", "msg", "flow", "global"]
279
449
  }
280
- })
450
+ }),
451
+ errorPort: e.Boolean({ default: !1 }),
452
+ completePort: e.Boolean({ default: !1 }),
453
+ statusPort: e.Boolean({ default: !1 })
281
454
  },
282
455
  { $id: "salesforce-soql:config" }
283
- ), re = h(
456
+ ), he = p(
284
457
  {
285
458
  payload: e.Any()
286
459
  },
287
460
  { $id: "salesforce-soql:input" }
288
- ), se = h(
461
+ ), pe = p(
289
462
  {
290
463
  payload: e.Array(e.Any()),
291
464
  totalSize: e.Number(),
292
465
  done: e.Boolean()
293
466
  },
294
467
  { $id: "salesforce-soql:output" }
295
- ), y = class y extends k {
296
- async input(o) {
297
- const n = this.config.connection;
298
- if (!n) {
299
- this.error("No Salesforce connection configured", o);
468
+ ), T = class T extends A {
469
+ async input(s) {
470
+ const t = this.config.connection;
471
+ if (!t) {
472
+ this.error("No Salesforce connection configured", s);
300
473
  return;
301
474
  }
302
475
  try {
303
476
  this.status({ fill: "green", shape: "dot", text: "querying..." });
304
- const t = await n.getConnection(), r = await this.config.query.resolve(o), s = await t.query(r);
477
+ const n = await t.getConnection(), o = await this.config.query.resolve(s), i = await n.query(o);
305
478
  this.status({
306
479
  fill: "green",
307
480
  shape: "dot",
308
- text: `${s.totalSize} records`
481
+ text: `${i.totalSize} records`
309
482
  }), this.send({
310
- ...o,
311
- payload: s.records,
312
- totalSize: s.totalSize,
313
- done: s.done
483
+ ...s,
484
+ payload: i.records,
485
+ totalSize: i.totalSize,
486
+ done: i.done
314
487
  });
315
- } catch (t) {
488
+ } catch (n) {
316
489
  this.status({
317
490
  fill: "red",
318
491
  shape: "dot",
319
- text: t instanceof Error ? t.message : String(t)
492
+ text: n instanceof Error ? n.message : String(n)
320
493
  }), this.error(
321
- `SOQL query failed: ${t instanceof Error ? t.message : String(t)}`,
322
- o
494
+ `SOQL query failed: ${n instanceof Error ? n.message : String(n)}`,
495
+ s
323
496
  );
324
497
  }
325
498
  }
326
499
  };
327
- f(y, "SalesforceSoql"), i(y, "type", "salesforce-soql"), i(y, "category", "salesforce"), i(y, "color", "#FFFFFF"), i(y, "configSchema", ie), i(y, "inputSchema", re), i(y, "outputsSchema", se);
328
- let C = y;
329
- const ae = h(
500
+ d(T, "SalesforceSoql"), r(T, "type", "salesforce-soql"), r(T, "category", "salesforce"), r(T, "color", "#FFFFFF"), r(T, "configSchema", de), r(T, "inputSchema", he), r(T, "outputsSchema", pe);
501
+ let U = T;
502
+ const fe = p(
330
503
  {
331
504
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
332
- connection: e.NodeRef($, {
505
+ connection: e.NodeRef(w, {
333
506
  "x-nrg-form": { icon: "cloud" }
334
507
  }),
335
508
  operation: e.Union(
@@ -360,9 +533,9 @@ const ae = h(
360
533
  "x-nrg-form": { icon: "key" }
361
534
  })
362
535
  ),
363
- emitError: e.Boolean({ default: !1 }),
364
- emitComplete: e.Boolean({ default: !1 }),
365
- emitStatus: e.Boolean({ default: !1 })
536
+ errorPort: e.Boolean({ default: !1 }),
537
+ completePort: e.Boolean({ default: !1 }),
538
+ statusPort: e.Boolean({ default: !1 })
366
539
  },
367
540
  {
368
541
  $id: "salesforce-dml:config",
@@ -378,66 +551,66 @@ const ae = h(
378
551
  }
379
552
  }
380
553
  }
381
- ), ce = h(
554
+ ), ge = p(
382
555
  {
383
556
  payload: e.Any()
384
557
  },
385
558
  { $id: "salesforce-dml:input" }
386
- ), le = h(
559
+ ), me = p(
387
560
  {
388
561
  payload: e.Any()
389
562
  },
390
563
  { $id: "salesforce-dml:output" }
391
- ), x = class x extends k {
392
- async input(o) {
393
- const n = this.config.connection;
394
- if (!n) {
395
- this.error("No Salesforce connection configured", o);
564
+ ), $ = class $ extends A {
565
+ async input(s) {
566
+ const t = this.config.connection;
567
+ if (!t) {
568
+ this.error("No Salesforce connection configured", s);
396
569
  return;
397
570
  }
398
571
  try {
399
- const t = this.config.operation;
400
- this.status({ fill: "green", shape: "dot", text: `${t}...` });
401
- const r = await n.getConnection(), s = await this.config.sObjectType.resolve(o), l = r.sobject(s), d = await this.config.record.resolve(o) ?? o.payload;
402
- let c;
403
- switch (t) {
572
+ const n = this.config.operation;
573
+ this.status({ fill: "green", shape: "dot", text: `${n}...` });
574
+ const o = await t.getConnection(), i = await this.config.sObjectType.resolve(s), c = o.sobject(i), u = await this.config.record.resolve(s) ?? s.payload;
575
+ let l;
576
+ switch (n) {
404
577
  case "create":
405
- c = await l.create(d);
578
+ l = await c.create(u);
406
579
  break;
407
580
  case "read":
408
- c = await l.retrieve(d);
581
+ l = await c.retrieve(u);
409
582
  break;
410
583
  case "update":
411
- c = await l.update(d);
584
+ l = await c.update(u);
412
585
  break;
413
586
  case "delete":
414
- c = await l.destroy(d);
587
+ l = await c.destroy(u);
415
588
  break;
416
589
  case "upsert":
417
- c = await l.upsert(d, this.config.externalIdField);
590
+ l = await c.upsert(u, this.config.externalIdField);
418
591
  break;
419
592
  default:
420
- throw new Error(`Unknown operation: ${t}`);
593
+ throw new Error(`Unknown operation: ${n}`);
421
594
  }
422
- this.status({ fill: "green", shape: "dot", text: `${t} done` }), this.send({ ...o, payload: c });
423
- } catch (t) {
595
+ this.status({ fill: "green", shape: "dot", text: `${n} done` }), this.send({ ...s, payload: l });
596
+ } catch (n) {
424
597
  this.status({
425
598
  fill: "red",
426
599
  shape: "dot",
427
- text: t instanceof Error ? t.message : String(t)
600
+ text: n instanceof Error ? n.message : String(n)
428
601
  }), this.error(
429
- `DML ${this.config.operation} failed: ${t instanceof Error ? t.message : String(t)}`,
430
- o
602
+ `DML ${this.config.operation} failed: ${n instanceof Error ? n.message : String(n)}`,
603
+ s
431
604
  );
432
605
  }
433
606
  }
434
607
  };
435
- f(x, "SalesforceDml"), i(x, "type", "salesforce-dml"), i(x, "category", "salesforce"), i(x, "color", "#FFFFFF"), i(x, "configSchema", ae), i(x, "inputSchema", ce), i(x, "outputsSchema", le);
436
- let R = x;
437
- const de = h(
608
+ d($, "SalesforceDml"), r($, "type", "salesforce-dml"), r($, "category", "salesforce"), r($, "color", "#FFFFFF"), r($, "configSchema", fe), r($, "inputSchema", ge), r($, "outputsSchema", me);
609
+ let k = $;
610
+ const ye = p(
438
611
  {
439
612
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
440
- connection: e.NodeRef($, {
613
+ connection: e.NodeRef(w, {
441
614
  "x-nrg-form": { icon: "cloud" }
442
615
  }),
443
616
  operation: e.Union(
@@ -446,6 +619,7 @@ const de = h(
446
619
  e.Literal("update"),
447
620
  e.Literal("upsert"),
448
621
  e.Literal("delete"),
622
+ e.Literal("hardDelete"),
449
623
  e.Literal("query")
450
624
  ],
451
625
  { default: "insert", "x-nrg-form": { icon: "database" } }
@@ -456,6 +630,12 @@ const de = h(
456
630
  typedInputTypes: ["str", "msg"]
457
631
  }
458
632
  }),
633
+ query: e.TypedInput({
634
+ "x-nrg-form": {
635
+ icon: "search",
636
+ typedInputTypes: ["str", "msg", "jsonata"]
637
+ }
638
+ }),
459
639
  externalIdField: e.Optional(
460
640
  e.String({
461
641
  default: "",
@@ -493,9 +673,9 @@ const de = h(
493
673
  minimum: 5e3,
494
674
  "x-nrg-form": { icon: "hourglass" }
495
675
  }),
496
- emitError: e.Boolean({ default: !1 }),
497
- emitComplete: e.Boolean({ default: !0 }),
498
- emitStatus: e.Boolean({ default: !1 })
676
+ errorPort: e.Boolean({ default: !1 }),
677
+ completePort: e.Boolean({ default: !1 }),
678
+ statusPort: e.Boolean({ default: !1 })
499
679
  },
500
680
  {
501
681
  $id: "salesforce-bulk:config",
@@ -511,119 +691,99 @@ const de = h(
511
691
  }
512
692
  }
513
693
  }
514
- ), ue = h(
694
+ ), xe = p(
515
695
  {
516
- payload: e.Any()
696
+ payload: e.Any({
697
+ description: "Records array, CSV string, readable stream (ingest) or SOQL string (query)"
698
+ })
517
699
  },
518
700
  { $id: "salesforce-bulk:input" }
519
- );
520
- h(
701
+ ), we = p(
521
702
  {
522
- payload: e.Array(e.Any())
703
+ payload: e.Any({
704
+ description: "Query: individual record. Ingest: { successfulResults, failedResults, unprocessedRecords }"
705
+ })
523
706
  },
524
707
  { $id: "salesforce-bulk:output" }
525
- );
526
- const he = h(
527
- {},
528
- { $id: "salesforce-bulk:record-output" }
529
- ), pe = h(
530
- {},
531
- { $id: "salesforce-bulk:job-created-output" }
532
- ), b = class b extends k {
533
- sendRecord(o, n) {
534
- this.sendToPort(0, { ...o, payload: n });
535
- }
536
- sendJobCreated(o, n) {
537
- this.sendToPort(1, { ...o, payload: n });
538
- }
539
- async input(o) {
540
- const n = this.config.connection;
541
- if (!n) {
542
- this.error("No Salesforce connection configured", o);
543
- return;
544
- }
708
+ ), I = class I extends A {
709
+ async input(s) {
545
710
  try {
546
- const t = this.config.operation;
547
- this.status({
548
- fill: "green",
549
- shape: "dot",
550
- text: `bulk ${t}...`
551
- });
552
- const r = await n.getConnection(), s = await this.config.sObjectType.resolve(o);
553
- let l = 0;
554
- if (t === "query") {
555
- const d = await r.bulk2.query(o.payload, {
556
- pollTimeout: this.config.pollTimeout,
557
- pollInterval: this.config.pollInterval,
558
- columnDelimiter: this.config.columnDelimiter,
559
- lineEnding: this.config.lineEnding
560
- });
561
- await new Promise((c, g) => {
562
- d.on("data", (u) => {
563
- l++, this.sendRecord(o, u);
564
- }), d.on("end", () => c()), d.on("error", g);
565
- }), this.status({
711
+ const t = this.config.connection;
712
+ if (!t)
713
+ throw new Error("No Salesforce connection configured");
714
+ const n = await t.getConnection(), o = this.config.operation;
715
+ o === "query" ? await this.executeQuery(n, s) : await this.executeIngest(n, s, o);
716
+ } catch (t) {
717
+ const n = t instanceof Error ? t.message : String(t);
718
+ throw this.status({ fill: "red", shape: "dot", text: n }), t;
719
+ }
720
+ }
721
+ async executeQuery(s, t) {
722
+ this.status({ fill: "green", shape: "dot", text: "query starting..." });
723
+ const n = await this.config.query.resolve(t), o = await s.bulk2.query(n, {
724
+ pollTimeout: this.config.pollTimeout,
725
+ pollInterval: this.config.pollInterval,
726
+ columnDelimiter: this.config.columnDelimiter,
727
+ lineEnding: this.config.lineEnding
728
+ });
729
+ let i = 0;
730
+ await new Promise((c, u) => {
731
+ o.on("data", (l) => {
732
+ i++, this.send({ ...t, payload: l }), i % 1e3 === 0 && this.status({
566
733
  fill: "green",
567
734
  shape: "dot",
568
- text: `bulk ${t}: ${l} records`
569
- }), this.sendToPort("complete", {
570
- ...o,
571
- payload: { operation: t, sObjectType: s, totalRecords: l }
735
+ text: `query: ${i} records...`
572
736
  });
573
- } else {
574
- const d = o.payload, c = r.bulk2.createJob({
575
- operation: t,
576
- object: s,
577
- columnDelimiter: this.config.columnDelimiter,
578
- lineEnding: this.config.lineEnding,
579
- ...t === "upsert" && this.config.externalIdField ? { externalIdFieldName: this.config.externalIdField } : {},
580
- ...this.config.assignmentRuleId ? { assignmentRuleId: this.config.assignmentRuleId } : {}
581
- });
582
- await c.open(), this.sendJobCreated(o, {
583
- jobId: c.id,
584
- operation: t,
585
- sObjectType: s,
586
- state: "Open"
587
- }), await c.uploadData(d), await c.close(), await c.poll(this.config.pollInterval, this.config.pollTimeout);
588
- const g = await c.getAllResults(), u = g.successfulResults ?? [], m = g.failedResults ?? [], p = g.unprocessedRecords ?? [];
589
- l = u.length + m.length + p.length;
590
- for (const U of u)
591
- this.sendRecord(o, U);
592
- for (const U of m)
593
- this.sendRecord(o, U);
594
- const S = u.length, P = m.length;
595
- this.status({
596
- fill: P > 0 ? "red" : "green",
597
- shape: "dot",
598
- text: `bulk ${t}: ${l} records`
599
- }), this.sendToPort("complete", {
600
- ...o,
601
- payload: {
602
- jobId: c.id,
603
- operation: t,
604
- sObjectType: s,
605
- totalRecords: l,
606
- successCount: S,
607
- failureCount: P,
608
- unprocessedCount: p.length
609
- }
610
- });
611
- }
612
- } catch (t) {
613
- const r = t instanceof Error ? t.message : String(t);
614
- this.status({ fill: "red", shape: "dot", text: r }), this.error(`Bulk ${this.config.operation} failed: ${r}`, o);
615
- }
737
+ }), o.on("end", () => c()), o.on("error", u);
738
+ }), this.status({
739
+ fill: "green",
740
+ shape: "dot",
741
+ text: `query complete: ${i} records`
742
+ });
743
+ }
744
+ async executeIngest(s, t, n) {
745
+ var f, m, g;
746
+ const o = await this.config.sObjectType.resolve(t);
747
+ this.status({
748
+ fill: "green",
749
+ shape: "dot",
750
+ text: `creating ${n} job...`
751
+ });
752
+ const i = s.bulk2.createJob({
753
+ operation: n,
754
+ object: o,
755
+ columnDelimiter: this.config.columnDelimiter,
756
+ lineEnding: this.config.lineEnding,
757
+ ...n === "upsert" && this.config.externalIdField ? { externalIdFieldName: this.config.externalIdField } : {},
758
+ ...this.config.assignmentRuleId ? { assignmentRuleId: this.config.assignmentRuleId } : {}
759
+ });
760
+ await i.open(), this.status({
761
+ fill: "green",
762
+ shape: "dot",
763
+ text: "uploading data..."
764
+ }), await i.uploadData(t.payload), this.status({
765
+ fill: "green",
766
+ shape: "dot",
767
+ text: "processing..."
768
+ }), await i.close(), await i.poll(this.config.pollInterval, this.config.pollTimeout), this.status({
769
+ fill: "green",
770
+ shape: "dot",
771
+ text: "retrieving results..."
772
+ });
773
+ const c = await i.getAllResults(), u = ((f = c.successfulResults) == null ? void 0 : f.length) ?? 0, l = ((m = c.failedResults) == null ? void 0 : m.length) ?? 0, h = u + l + (((g = c.unprocessedRecords) == null ? void 0 : g.length) ?? 0);
774
+ this.send({ ...t, payload: c }), this.status({
775
+ fill: l > 0 ? "red" : "green",
776
+ shape: "dot",
777
+ text: `${n} complete: ${u} ok, ${l} failed, ${h} total`
778
+ });
616
779
  }
617
780
  };
618
- f(b, "SalesforceBulk"), i(b, "type", "salesforce-bulk"), i(b, "category", "salesforce"), i(b, "color", "#FFFFFF"), i(b, "configSchema", de), i(b, "inputSchema", ue), i(b, "outputsSchema", [
619
- he,
620
- pe
621
- ]);
622
- let O = b;
623
- const fe = h(
781
+ d(I, "SalesforceBulk"), r(I, "type", "salesforce-bulk"), r(I, "category", "salesforce"), r(I, "color", "#FFFFFF"), r(I, "configSchema", ye), r(I, "inputSchema", xe), r(I, "outputsSchema", we);
782
+ let j = I;
783
+ const be = p(
624
784
  {
625
785
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
626
- connection: e.NodeRef($, {
786
+ connection: e.NodeRef(w, {
627
787
  "x-nrg-form": { icon: "cloud" }
628
788
  }),
629
789
  sObjectType: e.TypedInput({
@@ -632,17 +792,17 @@ const fe = h(
632
792
  typedInputTypes: ["str", "msg"]
633
793
  }
634
794
  }),
635
- emitError: e.Boolean({ default: !1 }),
636
- emitComplete: e.Boolean({ default: !1 }),
637
- emitStatus: e.Boolean({ default: !1 })
795
+ errorPort: e.Boolean({ default: !1 }),
796
+ completePort: e.Boolean({ default: !1 }),
797
+ statusPort: e.Boolean({ default: !1 })
638
798
  },
639
799
  { $id: "salesforce-describe:config" }
640
- ), ge = h(
800
+ ), Te = p(
641
801
  {
642
802
  payload: e.Any()
643
803
  },
644
804
  { $id: "salesforce-describe:input" }
645
- ), me = h(
805
+ ), $e = p(
646
806
  {
647
807
  payload: e.Object({
648
808
  name: e.String(),
@@ -652,47 +812,47 @@ const fe = h(
652
812
  })
653
813
  },
654
814
  { $id: "salesforce-describe:output" }
655
- ), T = class T extends k {
656
- async input(o) {
657
- const n = this.config.connection;
658
- if (!n) {
659
- this.error("No Salesforce connection configured", o);
815
+ ), S = class S extends A {
816
+ async input(s) {
817
+ const t = this.config.connection;
818
+ if (!t) {
819
+ this.error("No Salesforce connection configured", s);
660
820
  return;
661
821
  }
662
822
  try {
663
823
  this.status({ fill: "green", shape: "dot", text: "describing..." });
664
- const t = await n.getConnection(), r = await this.config.sObjectType.resolve(o), s = await t.sobject(r).describe();
824
+ const n = await t.getConnection(), o = await this.config.sObjectType.resolve(s), i = await n.sobject(o).describe();
665
825
  this.status({
666
826
  fill: "green",
667
827
  shape: "dot",
668
- text: `${s.name}: ${s.fields.length} fields`
828
+ text: `${i.name}: ${i.fields.length} fields`
669
829
  }), this.send({
670
- ...o,
830
+ ...s,
671
831
  payload: {
672
- name: s.name,
673
- fields: s.fields,
674
- childRelationships: s.childRelationships,
675
- recordTypeInfos: s.recordTypeInfos
832
+ name: i.name,
833
+ fields: i.fields,
834
+ childRelationships: i.childRelationships,
835
+ recordTypeInfos: i.recordTypeInfos
676
836
  }
677
837
  });
678
- } catch (t) {
838
+ } catch (n) {
679
839
  this.status({
680
840
  fill: "red",
681
841
  shape: "dot",
682
- text: t instanceof Error ? t.message : String(t)
842
+ text: n instanceof Error ? n.message : String(n)
683
843
  }), this.error(
684
- `Describe failed: ${t instanceof Error ? t.message : String(t)}`,
685
- o
844
+ `Describe failed: ${n instanceof Error ? n.message : String(n)}`,
845
+ s
686
846
  );
687
847
  }
688
848
  }
689
849
  };
690
- f(T, "SalesforceDescribe"), i(T, "type", "salesforce-describe"), i(T, "category", "salesforce"), i(T, "color", "#FFFFFF"), i(T, "configSchema", fe), i(T, "inputSchema", ge), i(T, "outputsSchema", me);
691
- let j = T;
692
- const ye = h(
850
+ d(S, "SalesforceDescribe"), r(S, "type", "salesforce-describe"), r(S, "category", "salesforce"), r(S, "color", "#FFFFFF"), r(S, "configSchema", be), r(S, "inputSchema", Te), r(S, "outputsSchema", $e);
851
+ let M = S;
852
+ const Ie = p(
693
853
  {
694
854
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
695
- connection: e.NodeRef($, {
855
+ connection: e.NodeRef(w, {
696
856
  "x-nrg-form": { icon: "cloud" }
697
857
  }),
698
858
  channelName: e.String({
@@ -719,8 +879,9 @@ const ye = h(
719
879
  maximum: 100,
720
880
  "x-nrg-form": { icon: "sort-numeric-asc" }
721
881
  }),
722
- emitError: e.Boolean({ default: !1 }),
723
- emitStatus: e.Boolean({ default: !1 })
882
+ errorPort: e.Boolean({ default: !1 }),
883
+ completePort: e.Boolean({ default: !1 }),
884
+ statusPort: e.Boolean({ default: !1 })
724
885
  },
725
886
  {
726
887
  $id: "salesforce-streaming:config",
@@ -736,7 +897,7 @@ const ye = h(
736
897
  }
737
898
  }
738
899
  }
739
- ), xe = h(
900
+ ), Se = p(
740
901
  {
741
902
  payload: e.Any(),
742
903
  replayId: e.Any(),
@@ -744,57 +905,57 @@ const ye = h(
744
905
  topic: e.String()
745
906
  },
746
907
  { $id: "salesforce-streaming:output" }
747
- ), w = class w extends k {
908
+ ), L = class L extends A {
748
909
  constructor() {
749
910
  super(...arguments);
750
- i(this, "client", null);
751
- i(this, "reconnectAttempt", 0);
752
- i(this, "maxReconnectDelay", 6e4);
753
- i(this, "maxReconnectAttempts", 10);
754
- i(this, "grpcErrorHandler", null);
755
- i(this, "stopped", !1);
911
+ r(this, "client", null);
912
+ r(this, "reconnectAttempt", 0);
913
+ r(this, "maxReconnectDelay", 6e4);
914
+ r(this, "maxReconnectAttempts", 10);
915
+ r(this, "grpcErrorHandler", null);
916
+ r(this, "stopped", !1);
756
917
  }
757
918
  async created() {
758
- const n = this.config.connection;
759
- if (!n) {
919
+ const t = this.config.connection;
920
+ if (!t) {
760
921
  this.status({ fill: "red", shape: "dot", text: "no connection" }), this.error("No Salesforce connection configured");
761
922
  return;
762
923
  }
763
- await this.subscribe(n);
924
+ await this.subscribe(t);
764
925
  }
765
- async subscribe(n) {
926
+ async subscribe(t) {
766
927
  if (!this.stopped)
767
928
  try {
768
929
  this.status({ fill: "green", shape: "dot", text: "connecting..." });
769
- let t;
930
+ let n;
770
931
  try {
771
- t = await n.getConnection(), await t.identity();
932
+ n = await t.getConnection(), await n.identity();
772
933
  } catch {
773
934
  this.status({ fill: "red", shape: "dot", text: "auth expired" }), this.error("Salesforce token expired. Re-authorize the connection.");
774
935
  return;
775
936
  }
776
- const r = n.getAccessToken(), s = n.getInstanceUrl();
777
- if (!r || !s) {
937
+ const o = n.accessToken, i = n.instanceUrl;
938
+ if (!o || !i) {
778
939
  this.status({ fill: "red", shape: "dot", text: "not authorized" }), this.error("Salesforce connection not authorized");
779
940
  return;
780
941
  }
781
- const l = (await import("salesforce-pubsub-api-client")).default;
782
- this.client = new l({
942
+ const c = (await import("salesforce-pubsub-api-client")).default;
943
+ this.client = new c({
783
944
  authType: "user-supplied",
784
- accessToken: r,
785
- instanceUrl: s
945
+ accessToken: o,
946
+ instanceUrl: i
786
947
  }), await this.client.connect();
787
- const d = this.config.numRequested || null, c = this.config.channelName, g = /* @__PURE__ */ f((u, m, p) => {
948
+ const u = this.config.numRequested || null, l = this.config.channelName, h = /* @__PURE__ */ d((f, m, g) => {
788
949
  if (m === "event" || m === "lastevent")
789
950
  this.send({
790
- payload: (p == null ? void 0 : p.payload) ?? p,
791
- replayId: p == null ? void 0 : p.replayId,
792
- channel: c,
793
- topic: c
951
+ payload: (g == null ? void 0 : g.payload) ?? g,
952
+ replayId: g == null ? void 0 : g.replayId,
953
+ channel: l,
954
+ topic: l
794
955
  });
795
956
  else if (m === "error") {
796
- const S = p instanceof Error ? p.message : String(p ?? "stream error");
797
- if (this.warn(`Streaming error: ${S}`), S.includes("UNAUTHENTICATED") || S.includes("authentication")) {
957
+ const N = g instanceof Error ? g.message : String(g ?? "stream error");
958
+ if (this.warn(`Streaming error: ${N}`), N.includes("UNAUTHENTICATED") || N.includes("authentication")) {
798
959
  this.stopped = !0, this.status({
799
960
  fill: "red",
800
961
  shape: "dot",
@@ -804,51 +965,51 @@ const ye = h(
804
965
  ), this.cleanup();
805
966
  return;
806
967
  }
807
- this.status({ fill: "red", shape: "dot", text: S }), this.scheduleReconnect(n);
968
+ this.status({ fill: "red", shape: "dot", text: N }), this.scheduleReconnect(t);
808
969
  } else if (m === "end") {
809
970
  if (this.stopped) return;
810
- this.log("Streaming subscription ended"), this.status({ fill: "red", shape: "dot", text: "disconnected" }), this.scheduleReconnect(n);
971
+ this.log("Streaming subscription ended"), this.status({ fill: "red", shape: "dot", text: "disconnected" }), this.scheduleReconnect(t);
811
972
  }
812
973
  }, "callback");
813
- if (this.grpcErrorHandler && process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = (u) => {
814
- var m, p;
815
- ((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({
974
+ if (this.grpcErrorHandler && process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = (f) => {
975
+ var m, g;
976
+ ((m = f.message) != null && m.includes("UNAUTHENTICATED") || (g = f.message) != null && g.includes("authentication")) && (this.stopped = !0, this.warn(`Caught gRPC auth error: ${f.message}`), this.status({
816
977
  fill: "red",
817
978
  shape: "dot",
818
979
  text: "auth expired — re-authorize"
819
980
  }), this.cleanup());
820
981
  }, process.on("uncaughtException", this.grpcErrorHandler), this.config.subscribeType === "EARLIEST")
821
982
  this.client.subscribeFromEarliestEvent(
822
- c,
823
- g,
824
- d
983
+ l,
984
+ h,
985
+ u
825
986
  );
826
987
  else if (this.config.subscribeType === "CUSTOM" && this.config.replayId) {
827
- const u = parseInt(this.config.replayId, 10);
988
+ const f = parseInt(this.config.replayId, 10);
828
989
  this.client.subscribeFromReplayId(
829
- c,
830
- g,
831
- d,
832
- u
990
+ l,
991
+ h,
992
+ u,
993
+ f
833
994
  );
834
995
  } else
835
- this.client.subscribe(c, g, d);
996
+ this.client.subscribe(l, h, u);
836
997
  this.status({
837
998
  fill: "green",
838
999
  shape: "dot",
839
- text: `subscribed: ${c}`
1000
+ text: `subscribed: ${l}`
840
1001
  }), this.reconnectAttempt = 0;
841
- } catch (t) {
1002
+ } catch (n) {
842
1003
  this.status({
843
1004
  fill: "red",
844
1005
  shape: "dot",
845
- text: t instanceof Error ? t.message : String(t)
1006
+ text: n instanceof Error ? n.message : String(n)
846
1007
  }), this.error(
847
- `Streaming subscription failed: ${t instanceof Error ? t.message : String(t)}`
848
- ), this.scheduleReconnect(n);
1008
+ `Streaming subscription failed: ${n instanceof Error ? n.message : String(n)}`
1009
+ ), this.scheduleReconnect(t);
849
1010
  }
850
1011
  }
851
- scheduleReconnect(n) {
1012
+ scheduleReconnect(t) {
852
1013
  if (this.stopped) return;
853
1014
  if (this.reconnectAttempt++, this.reconnectAttempt > this.maxReconnectAttempts) {
854
1015
  this.error(
@@ -860,24 +1021,24 @@ const ye = h(
860
1021
  });
861
1022
  return;
862
1023
  }
863
- const t = Math.min(
1024
+ const n = Math.min(
864
1025
  1e3 * Math.pow(2, this.reconnectAttempt),
865
1026
  this.maxReconnectDelay
866
1027
  );
867
1028
  this.log(
868
- `Scheduling reconnect in ${t}ms (attempt ${this.reconnectAttempt}/${this.maxReconnectAttempts})`
1029
+ `Scheduling reconnect in ${n}ms (attempt ${this.reconnectAttempt}/${this.maxReconnectAttempts})`
869
1030
  ), this.status({
870
1031
  fill: "green",
871
1032
  shape: "dot",
872
- text: `reconnecting in ${Math.round(t / 1e3)}s`
1033
+ text: `reconnecting in ${Math.round(n / 1e3)}s`
873
1034
  }), this.setTimeout(async () => {
874
- await this.cleanup(), await this.subscribe(n);
875
- }, t);
1035
+ await this.cleanup(), await this.subscribe(t);
1036
+ }, n);
876
1037
  }
877
1038
  async cleanup() {
878
- var n, t;
1039
+ var t, n;
879
1040
  try {
880
- this.grpcErrorHandler && (process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = null), this.client && (await ((t = (n = this.client).close) == null ? void 0 : t.call(n)), this.client = null);
1041
+ this.grpcErrorHandler && (process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = null), this.client && (await ((n = (t = this.client).close) == null ? void 0 : n.call(t)), this.client = null);
881
1042
  } catch {
882
1043
  }
883
1044
  }
@@ -885,14 +1046,19 @@ const ye = h(
885
1046
  await this.cleanup();
886
1047
  }
887
1048
  };
888
- f(w, "SalesforceStreaming"), i(w, "type", "salesforce-streaming"), i(w, "category", "salesforce"), i(w, "color", "#FFFFFF"), i(w, "configSchema", ye), i(w, "outputsSchema", xe);
889
- let v = w;
890
- const be = h(
1049
+ d(L, "SalesforceStreaming"), r(L, "type", "salesforce-streaming"), r(L, "category", "salesforce"), r(L, "color", "#FFFFFF"), r(L, "configSchema", Ie), r(L, "outputsSchema", Se);
1050
+ let H = L;
1051
+ const Ee = p(
891
1052
  {
892
1053
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
893
- connection: e.NodeRef($, {
1054
+ connection: e.NodeRef(w, {
894
1055
  "x-nrg-form": { icon: "cloud" }
895
1056
  }),
1057
+ apexType: e.Union(
1058
+ [e.Literal("rest"), e.Literal("invocable")],
1059
+ { default: "rest", "x-nrg-form": { icon: "cog" } }
1060
+ ),
1061
+ // REST fields
896
1062
  method: e.Union(
897
1063
  [
898
1064
  e.Literal("GET"),
@@ -909,63 +1075,325 @@ const be = h(
909
1075
  typedInputTypes: ["str", "msg"]
910
1076
  }
911
1077
  }),
912
- emitError: e.Boolean({ default: !1 }),
913
- emitComplete: e.Boolean({ default: !1 }),
914
- emitStatus: e.Boolean({ default: !1 })
1078
+ // Invocable field
1079
+ actionName: e.String({
1080
+ default: "",
1081
+ "x-nrg-form": { icon: "bolt" }
1082
+ }),
1083
+ errorPort: e.Boolean({ default: !1 }),
1084
+ completePort: e.Boolean({ default: !1 }),
1085
+ statusPort: e.Boolean({ default: !1 })
915
1086
  },
916
- { $id: "salesforce-apex:config" }
917
- ), Te = h(
1087
+ { $id: "salesforce-apex-invocation:config" }
1088
+ ), Le = p(
1089
+ { payload: e.Any() },
1090
+ { $id: "salesforce-apex-invocation:input" }
1091
+ ), Re = p(
1092
+ { payload: e.Any() },
1093
+ { $id: "salesforce-apex-invocation:output" }
1094
+ ), E = class E extends A {
1095
+ async input(s) {
1096
+ const t = this.config.connection;
1097
+ if (!t) {
1098
+ this.error("No Salesforce connection configured", s);
1099
+ return;
1100
+ }
1101
+ try {
1102
+ const n = await t.getConnection();
1103
+ if (this.status({ fill: "green", shape: "dot", text: "executing..." }), this.config.apexType === "rest") {
1104
+ const o = await this.config.path.resolve(s), i = this.config.method.toLowerCase();
1105
+ let c;
1106
+ i === "get" || i === "delete" ? c = await n.apex[i](o) : c = await n.apex[i](o, s.payload), this.status({
1107
+ fill: "green",
1108
+ shape: "dot",
1109
+ text: `${this.config.method} done`
1110
+ }), this.send({ ...s, payload: c });
1111
+ } else {
1112
+ const i = await new R(n).invoke(this.config.actionName, s.payload);
1113
+ this.status({ fill: "green", shape: "dot", text: "done" }), this.send({ ...s, payload: i.outputValues });
1114
+ }
1115
+ } catch (n) {
1116
+ const o = n instanceof Error ? n.message : String(n);
1117
+ this.status({ fill: "red", shape: "dot", text: o }), this.error(`Apex failed: ${o}`, s);
1118
+ }
1119
+ }
1120
+ };
1121
+ d(E, "SalesforceApex"), r(E, "type", "salesforce-apex-invocation"), r(E, "category", "salesforce"), r(E, "color", "#FFFFFF"), r(E, "configSchema", Ee), r(E, "inputSchema", Le), r(E, "outputsSchema", Re);
1122
+ let B = E;
1123
+ const Ae = p(
918
1124
  {
919
- payload: e.Any()
1125
+ name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
1126
+ connection: e.NodeRef(w, {
1127
+ "x-nrg-form": { icon: "cloud" }
1128
+ }),
1129
+ apexType: e.Union(
1130
+ [e.Literal("invocable"), e.Literal("rest")],
1131
+ { default: "invocable", "x-nrg-form": { icon: "cog" } }
1132
+ ),
1133
+ className: e.String({
1134
+ default: "",
1135
+ "x-nrg-form": { icon: "file-code-o" }
1136
+ }),
1137
+ urlMapping: e.String({
1138
+ default: "",
1139
+ "x-nrg-form": { icon: "link" }
1140
+ }),
1141
+ httpMethod: e.Union(
1142
+ [
1143
+ e.Literal("HttpGet"),
1144
+ e.Literal("HttpPost"),
1145
+ e.Literal("HttpPut"),
1146
+ e.Literal("HttpPatch"),
1147
+ e.Literal("HttpDelete")
1148
+ ],
1149
+ { default: "HttpPost", "x-nrg-form": { icon: "random" } }
1150
+ ),
1151
+ code: e.String({
1152
+ default: "",
1153
+ "x-nrg-form": { editorLanguage: "java" }
1154
+ }),
1155
+ errorPort: e.Boolean({ default: !1 }),
1156
+ completePort: e.Boolean({ default: !1 }),
1157
+ statusPort: e.Boolean({ default: !1 })
920
1158
  },
921
- { $id: "salesforce-apex:input" }
922
- ), Ie = h(
1159
+ { $id: "salesforce-apex-code:config" }
1160
+ ), ve = p(
923
1161
  {
924
- payload: e.Any()
1162
+ classPrefix: e.String({ default: "NRG_" })
925
1163
  },
926
- { $id: "salesforce-apex:output" }
927
- ), I = class I extends k {
928
- async input(o) {
1164
+ { $id: "salesforce-apex-code:settings" }
1165
+ ), Fe = p(
1166
+ { payload: e.Any() },
1167
+ { $id: "salesforce-apex-code:input" }
1168
+ ), Ce = p(
1169
+ { payload: e.Any() },
1170
+ { $id: "salesforce-apex-code:output" }
1171
+ ), y = class y {
1172
+ constructor(s) {
1173
+ r(this, "pendingDeploys", /* @__PURE__ */ new Map());
1174
+ r(this, "pendingDeletes", /* @__PURE__ */ new Set());
1175
+ r(this, "flushTimer", null);
1176
+ r(this, "connectionProvider");
1177
+ this.connectionProvider = s;
1178
+ }
1179
+ static getInstance(s, t) {
1180
+ return y.instances.has(s) || y.instances.set(
1181
+ s,
1182
+ new y(t)
1183
+ ), y.instances.get(s);
1184
+ }
1185
+ static removeInstance(s) {
1186
+ y.instances.delete(s);
1187
+ }
1188
+ register(s, t) {
1189
+ return this.pendingDeletes.delete(s), new Promise((n, o) => {
1190
+ this.pendingDeploys.set(s, { className: s, body: t, resolve: n, reject: o }), this.scheduleFlush();
1191
+ });
1192
+ }
1193
+ unregister(s) {
1194
+ const t = this.pendingDeploys.get(s);
1195
+ t && (t.reject(new Error("Deploy cancelled — node was removed")), this.pendingDeploys.delete(s)), this.pendingDeletes.add(s), this.scheduleFlush();
1196
+ }
1197
+ scheduleFlush() {
1198
+ this.flushTimer || (this.flushTimer = setTimeout(() => {
1199
+ this.flushTimer = null, this.flush().catch((s) => {
1200
+ console.error("[ApexClassManager] flush error:", s);
1201
+ });
1202
+ }, y.FLUSH_DELAY_MS));
1203
+ }
1204
+ async flush() {
1205
+ const s = new Set(this.pendingDeletes), t = new Map(this.pendingDeploys);
1206
+ if (this.pendingDeletes.clear(), this.pendingDeploys.clear(), s.size === 0 && t.size === 0) return;
1207
+ const n = await this.connectionProvider.getConnection(), o = new R(n), i = [...s, ...t.keys()], c = await o.queryApexClassesByName(i);
1208
+ for (const u of s) {
1209
+ const l = c.get(u);
1210
+ if (l)
1211
+ try {
1212
+ await o.deleteApexClass(l.Id);
1213
+ } catch (h) {
1214
+ console.error(`[ApexClassManager] Failed to delete ${u}:`, h);
1215
+ }
1216
+ }
1217
+ for (const [u, l] of t)
1218
+ try {
1219
+ const h = c.get(u);
1220
+ if (h) {
1221
+ if (h.Body === l.body) {
1222
+ l.resolve({ id: h.Id });
1223
+ continue;
1224
+ }
1225
+ await o.deleteApexClass(h.Id);
1226
+ }
1227
+ const { id: f } = await o.createApexClass(u, l.body);
1228
+ l.resolve({ id: f });
1229
+ } catch (h) {
1230
+ l.reject(h instanceof Error ? h : new Error(String(h)));
1231
+ }
1232
+ }
1233
+ };
1234
+ d(y, "ApexClassManager"), r(y, "instances", /* @__PURE__ */ new Map()), r(y, "FLUSH_DELAY_MS", 500);
1235
+ let P = y;
1236
+ function Oe(a, s) {
1237
+ return `public class ${a} {
1238
+ public class Input {
1239
+ @InvocableVariable(required=true)
1240
+ public String payload;
1241
+ }
1242
+
1243
+ public class Output {
1244
+ @InvocableVariable
1245
+ public String result;
1246
+ }
1247
+
1248
+ @InvocableMethod(label='${a}' description='Generated by NRG')
1249
+ public static List<Output> execute(List<Input> inputs) {
1250
+ Output out = new Output();
1251
+ Object returnValue = run(inputs[0].payload);
1252
+ out.result = returnValue instanceof String
1253
+ ? (String) returnValue
1254
+ : JSON.serialize(returnValue);
1255
+ return new List<Output>{ out };
1256
+ }
1257
+
1258
+ private static Object run(String payload) {
1259
+ ${s}
1260
+ }
1261
+ }`;
1262
+ }
1263
+ d(Oe, "buildInvocableClass");
1264
+ const Ne = {
1265
+ HttpGet: "doGet",
1266
+ HttpPost: "doPost",
1267
+ HttpPut: "doPut",
1268
+ HttpPatch: "doPatch",
1269
+ HttpDelete: "doDelete"
1270
+ }, Pe = {
1271
+ HttpGet: !1,
1272
+ HttpPost: !0,
1273
+ HttpPut: !0,
1274
+ HttpPatch: !0,
1275
+ HttpDelete: !1
1276
+ };
1277
+ function Ue(a, s, t, n) {
1278
+ const o = Ne[t], c = Pe[t] ? ` String payload = RestContext.request.requestBody != null
1279
+ ? RestContext.request.requestBody.toString()
1280
+ : null;` : ` String payload = RestContext.request.params != null
1281
+ ? JSON.serialize(RestContext.request.params)
1282
+ : null;`;
1283
+ return `@RestResource(urlMapping='${s}')
1284
+ global class ${a} {
1285
+ @${t}
1286
+ global static String ${o}() {
1287
+ ${c}
1288
+ Object returnValue = run(payload);
1289
+ return returnValue instanceof String
1290
+ ? (String) returnValue
1291
+ : JSON.serialize(returnValue);
1292
+ }
1293
+
1294
+ private static Object run(String payload) {
1295
+ ${n}
1296
+ }
1297
+ }`;
1298
+ }
1299
+ d(Ue, "buildRestClass");
1300
+ const x = class x extends A {
1301
+ constructor() {
1302
+ super(...arguments);
1303
+ r(this, "deployed", !1);
1304
+ }
1305
+ getFullClassName() {
1306
+ return `${this.settings.classPrefix}${this.config.className}`;
1307
+ }
1308
+ buildApexBody() {
1309
+ const t = this.getFullClassName();
1310
+ return this.config.apexType === "rest" ? Ue(
1311
+ t,
1312
+ this.config.urlMapping,
1313
+ this.config.httpMethod,
1314
+ this.config.code
1315
+ ) : Oe(t, this.config.code);
1316
+ }
1317
+ async created() {
1318
+ const t = this.config.connection;
1319
+ if (!t) {
1320
+ this.status({ fill: "red", shape: "dot", text: "no connection" });
1321
+ return;
1322
+ }
1323
+ if (!this.config.className) {
1324
+ this.status({ fill: "red", shape: "dot", text: "class name required" });
1325
+ return;
1326
+ }
1327
+ const n = P.getInstance(
1328
+ t.id,
1329
+ t
1330
+ );
1331
+ this.status({ fill: "green", shape: "dot", text: "deploying..." }), n.register(this.getFullClassName(), this.buildApexBody()).then(() => {
1332
+ this.deployed = !0, this.status({ fill: "green", shape: "dot", text: "deployed" });
1333
+ }).catch((o) => {
1334
+ const i = o instanceof Error ? o.message : String(o);
1335
+ this.status({ fill: "red", shape: "dot", text: i }), this.error(`Apex deploy failed: ${i}`);
1336
+ });
1337
+ }
1338
+ async input(t) {
1339
+ if (!this.deployed) {
1340
+ this.error(
1341
+ "Apex class not yet deployed — wait for deployment to complete",
1342
+ t
1343
+ );
1344
+ return;
1345
+ }
929
1346
  const n = this.config.connection;
930
1347
  if (!n) {
931
- this.error("No Salesforce connection configured", o);
1348
+ this.error("No Salesforce connection configured", t);
932
1349
  return;
933
1350
  }
934
1351
  try {
935
- const t = this.config.method;
936
- this.status({ fill: "green", shape: "dot", text: `${t}...` });
937
- const r = await n.getConnection(), s = await this.config.path.resolve(o);
938
- let l;
939
- const d = t.toLowerCase();
940
- d === "get" || d === "delete" ? l = await r.apex[d](s) : l = await r.apex[d](s, o.payload), this.status({ fill: "green", shape: "dot", text: `${t} done` }), this.send({ ...o, payload: l });
941
- } catch (t) {
942
- this.status({
943
- fill: "red",
944
- shape: "dot",
945
- text: t instanceof Error ? t.message : String(t)
946
- }), this.error(
947
- `Apex ${this.config.method} failed: ${t instanceof Error ? t.message : String(t)}`,
948
- o
949
- );
1352
+ const o = await n.getConnection(), i = new R(o);
1353
+ if (this.status({ fill: "green", shape: "dot", text: "executing..." }), this.config.apexType === "invocable") {
1354
+ const c = await i.invoke(
1355
+ this.getFullClassName(),
1356
+ t.payload
1357
+ );
1358
+ this.status({ fill: "green", shape: "dot", text: "done" }), this.send({ ...t, payload: c.outputValues });
1359
+ } else {
1360
+ const c = this.config.urlMapping, u = this.config.httpMethod;
1361
+ let l;
1362
+ u === "HttpGet" || u === "HttpDelete" ? l = u === "HttpGet" ? await i.get(c) : await i.delete(c) : l = await i[u === "HttpPut" ? "put" : u === "HttpPatch" ? "patch" : "post"](c, t.payload), this.status({ fill: "green", shape: "dot", text: "done" }), this.send({ ...t, payload: l });
1363
+ }
1364
+ } catch (o) {
1365
+ const i = o instanceof Error ? o.message : String(o);
1366
+ this.status({ fill: "red", shape: "dot", text: i }), this.error(`Apex execution failed: ${i}`, t);
1367
+ }
1368
+ }
1369
+ async closed(t) {
1370
+ if (t) {
1371
+ const n = this.config.connection;
1372
+ n && P.getInstance(
1373
+ n.id,
1374
+ n
1375
+ ).unregister(this.getFullClassName());
950
1376
  }
1377
+ this.deployed = !1;
951
1378
  }
952
1379
  };
953
- f(I, "SalesforceApex"), i(I, "type", "salesforce-apex"), i(I, "category", "salesforce"), i(I, "color", "#FFFFFF"), i(I, "configSchema", be), i(I, "inputSchema", Te), i(I, "outputsSchema", Ie);
954
- let N = I;
955
- const $e = Y({
1380
+ d(x, "SalesforceApexCode"), r(x, "type", "salesforce-apex-code"), r(x, "category", "salesforce"), r(x, "color", "#FFFFFF"), r(x, "configSchema", Ae), r(x, "inputSchema", Fe), r(x, "outputsSchema", Ce), r(x, "settingsSchema", ve);
1381
+ let q = x;
1382
+ const ke = _({
956
1383
  nodes: [
957
- $,
958
- C,
959
- R,
960
- O,
1384
+ w,
1385
+ U,
1386
+ k,
961
1387
  j,
962
- v,
963
- N
1388
+ M,
1389
+ H,
1390
+ B,
1391
+ q
964
1392
  ]
965
1393
  });
966
- var F = $e;
967
- F && typeof F == "object" && Array.isArray(F.nodes) && (F = G(F.nodes));
1394
+ var C = ke;
1395
+ C && typeof C == "object" && Array.isArray(C.nodes) && (C = K(C.nodes));
968
1396
  export {
969
- F as default
1397
+ C as default
970
1398
  };
971
1399
  //# sourceMappingURL=index.mjs.map