@bonsae/node-red-salesforce 0.4.1 → 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 H = (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 r = (a, o, n) => H(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 e, ConfigNode as Q, IONode as k, defineModule as Y } from "@bonsae/nrg/server";
9
- import K from "jsforce";
10
- import N from "node:crypto";
11
- var V = q(import.meta.url), Ae = 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
- ), B = 600 * 1e3, U = /* @__PURE__ */ new Map();
52
- function Z() {
53
- return N.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 N.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 = N.randomUUID(), n = Z(), t = D(n);
62
- U.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 [s, i] of U)
71
- Date.now() - i.timestamp > B && U.delete(s);
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 = U.get(a);
77
- return !o || (U.delete(a), Date.now() - o.timestamp > B) ? 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: s,
97
+ nodeId: o,
98
98
  loginUrl: i,
99
- clientId: l,
100
- callbackUrl: d
101
- } = n.body;
102
- if (!s || !i || !l) {
103
- t.status(400).json({ error: "nodeId, loginUrl, and clientId are required" });
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: s,
108
- clientId: l,
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
109
  loginUrl: i,
110
- callbackUrl: c
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({
119
+ n.json({
120
120
  authorizationUrl: `${i}/services/oauth2/authorize?${m.toString()}`
121
121
  });
122
- } catch (s) {
122
+ } catch (o) {
123
123
  a.log.error(
124
- `salesforce-connection: auth/start error: ${s instanceof Error ? s.message : String(s)}`
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: s, state: i, 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 (!s || !i) {
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(i);
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: s,
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 (s) {
202
+ } catch (o) {
203
203
  a.log.error(
204
- `salesforce-connection: auth/callback error: ${s instanceof Error ? s.message : String(s)}`
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 s = a.nodes.getCredentials(n.params.nodeId), i = !!(s != null && s.accessToken && (s != null && s.instanceUrl));
210
- t.json({
209
+ const o = a.nodes.getCredentials(t.params.nodeId), i = !!(o != null && o.accessToken && (o != null && o.instanceUrl));
210
+ n.json({
211
211
  authenticated: i,
212
- instanceUrl: i ? s.instanceUrl : void 0
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
+ });
228
+ }
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
+ );
222
388
  }
223
- f(oe, "initRoutes");
224
- const L = class L extends Q {
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
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"), r(L, "type", "salesforce-connection"), r(L, "configSchema", W), r(L, "credentialsSchema", X);
268
- let $ = L;
269
- const re = 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({
@@ -283,56 +453,56 @@ const re = h(
283
453
  statusPort: e.Boolean({ default: !1 })
284
454
  },
285
455
  { $id: "salesforce-soql:config" }
286
- ), se = h(
456
+ ), he = p(
287
457
  {
288
458
  payload: e.Any()
289
459
  },
290
460
  { $id: "salesforce-soql:input" }
291
- ), ie = h(
461
+ ), pe = p(
292
462
  {
293
463
  payload: e.Array(e.Any()),
294
464
  totalSize: e.Number(),
295
465
  done: e.Boolean()
296
466
  },
297
467
  { $id: "salesforce-soql:output" }
298
- ), y = class y extends k {
299
- async input(o) {
300
- const n = this.config.connection;
301
- if (!n) {
302
- 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);
303
473
  return;
304
474
  }
305
475
  try {
306
476
  this.status({ fill: "green", shape: "dot", text: "querying..." });
307
- const t = await n.getConnection(), s = await this.config.query.resolve(o), i = await t.query(s);
477
+ const n = await t.getConnection(), o = await this.config.query.resolve(s), i = await n.query(o);
308
478
  this.status({
309
479
  fill: "green",
310
480
  shape: "dot",
311
481
  text: `${i.totalSize} records`
312
482
  }), this.send({
313
- ...o,
483
+ ...s,
314
484
  payload: i.records,
315
485
  totalSize: i.totalSize,
316
486
  done: i.done
317
487
  });
318
- } catch (t) {
488
+ } catch (n) {
319
489
  this.status({
320
490
  fill: "red",
321
491
  shape: "dot",
322
- text: t instanceof Error ? t.message : String(t)
492
+ text: n instanceof Error ? n.message : String(n)
323
493
  }), this.error(
324
- `SOQL query failed: ${t instanceof Error ? t.message : String(t)}`,
325
- o
494
+ `SOQL query failed: ${n instanceof Error ? n.message : String(n)}`,
495
+ s
326
496
  );
327
497
  }
328
498
  }
329
499
  };
330
- f(y, "SalesforceSoql"), r(y, "type", "salesforce-soql"), r(y, "category", "salesforce"), r(y, "color", "#FFFFFF"), r(y, "configSchema", re), r(y, "inputSchema", se), r(y, "outputsSchema", ie);
331
- let E = y;
332
- 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(
333
503
  {
334
504
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
335
- connection: e.NodeRef($, {
505
+ connection: e.NodeRef(w, {
336
506
  "x-nrg-form": { icon: "cloud" }
337
507
  }),
338
508
  operation: e.Union(
@@ -381,66 +551,66 @@ const ae = h(
381
551
  }
382
552
  }
383
553
  }
384
- ), ce = h(
554
+ ), ge = p(
385
555
  {
386
556
  payload: e.Any()
387
557
  },
388
558
  { $id: "salesforce-dml:input" }
389
- ), le = h(
559
+ ), me = p(
390
560
  {
391
561
  payload: e.Any()
392
562
  },
393
563
  { $id: "salesforce-dml:output" }
394
- ), x = class x extends k {
395
- async input(o) {
396
- const n = this.config.connection;
397
- if (!n) {
398
- 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);
399
569
  return;
400
570
  }
401
571
  try {
402
- const t = this.config.operation;
403
- this.status({ fill: "green", shape: "dot", text: `${t}...` });
404
- const s = await n.getConnection(), i = await this.config.sObjectType.resolve(o), l = s.sobject(i), d = await this.config.record.resolve(o) ?? o.payload;
405
- let c;
406
- 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) {
407
577
  case "create":
408
- c = await l.create(d);
578
+ l = await c.create(u);
409
579
  break;
410
580
  case "read":
411
- c = await l.retrieve(d);
581
+ l = await c.retrieve(u);
412
582
  break;
413
583
  case "update":
414
- c = await l.update(d);
584
+ l = await c.update(u);
415
585
  break;
416
586
  case "delete":
417
- c = await l.destroy(d);
587
+ l = await c.destroy(u);
418
588
  break;
419
589
  case "upsert":
420
- c = await l.upsert(d, this.config.externalIdField);
590
+ l = await c.upsert(u, this.config.externalIdField);
421
591
  break;
422
592
  default:
423
- throw new Error(`Unknown operation: ${t}`);
593
+ throw new Error(`Unknown operation: ${n}`);
424
594
  }
425
- this.status({ fill: "green", shape: "dot", text: `${t} done` }), this.send({ ...o, payload: c });
426
- } catch (t) {
595
+ this.status({ fill: "green", shape: "dot", text: `${n} done` }), this.send({ ...s, payload: l });
596
+ } catch (n) {
427
597
  this.status({
428
598
  fill: "red",
429
599
  shape: "dot",
430
- text: t instanceof Error ? t.message : String(t)
600
+ text: n instanceof Error ? n.message : String(n)
431
601
  }), this.error(
432
- `DML ${this.config.operation} failed: ${t instanceof Error ? t.message : String(t)}`,
433
- o
602
+ `DML ${this.config.operation} failed: ${n instanceof Error ? n.message : String(n)}`,
603
+ s
434
604
  );
435
605
  }
436
606
  }
437
607
  };
438
- f(x, "SalesforceDml"), r(x, "type", "salesforce-dml"), r(x, "category", "salesforce"), r(x, "color", "#FFFFFF"), r(x, "configSchema", ae), r(x, "inputSchema", ce), r(x, "outputsSchema", le);
439
- let C = x;
440
- 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(
441
611
  {
442
612
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
443
- connection: e.NodeRef($, {
613
+ connection: e.NodeRef(w, {
444
614
  "x-nrg-form": { icon: "cloud" }
445
615
  }),
446
616
  operation: e.Union(
@@ -449,6 +619,7 @@ const de = h(
449
619
  e.Literal("update"),
450
620
  e.Literal("upsert"),
451
621
  e.Literal("delete"),
622
+ e.Literal("hardDelete"),
452
623
  e.Literal("query")
453
624
  ],
454
625
  { default: "insert", "x-nrg-form": { icon: "database" } }
@@ -459,6 +630,12 @@ const de = h(
459
630
  typedInputTypes: ["str", "msg"]
460
631
  }
461
632
  }),
633
+ query: e.TypedInput({
634
+ "x-nrg-form": {
635
+ icon: "search",
636
+ typedInputTypes: ["str", "msg", "jsonata"]
637
+ }
638
+ }),
462
639
  externalIdField: e.Optional(
463
640
  e.String({
464
641
  default: "",
@@ -497,7 +674,7 @@ const de = h(
497
674
  "x-nrg-form": { icon: "hourglass" }
498
675
  }),
499
676
  errorPort: e.Boolean({ default: !1 }),
500
- completePort: e.Boolean({ default: !0 }),
677
+ completePort: e.Boolean({ default: !1 }),
501
678
  statusPort: e.Boolean({ default: !1 })
502
679
  },
503
680
  {
@@ -514,119 +691,99 @@ const de = h(
514
691
  }
515
692
  }
516
693
  }
517
- ), ue = h(
694
+ ), xe = p(
518
695
  {
519
- payload: e.Any()
696
+ payload: e.Any({
697
+ description: "Records array, CSV string, readable stream (ingest) or SOQL string (query)"
698
+ })
520
699
  },
521
700
  { $id: "salesforce-bulk:input" }
522
- );
523
- h(
701
+ ), we = p(
524
702
  {
525
- payload: e.Array(e.Any())
703
+ payload: e.Any({
704
+ description: "Query: individual record. Ingest: { successfulResults, failedResults, unprocessedRecords }"
705
+ })
526
706
  },
527
707
  { $id: "salesforce-bulk:output" }
528
- );
529
- const he = h(
530
- {},
531
- { $id: "salesforce-bulk:record-output" }
532
- ), pe = h(
533
- {},
534
- { $id: "salesforce-bulk:job-created-output" }
535
- ), fe = {
536
- record: he,
537
- jobCreated: pe
538
- }, b = class b extends k {
539
- sendRecord(o, n) {
540
- this.sendToPort("record", { ...o, payload: n });
541
- }
542
- sendJobCreated(o, n) {
543
- this.sendToPort("jobCreated", { ...o, payload: n });
544
- }
545
- async input(o) {
546
- const n = this.config.connection;
547
- if (!n) {
548
- this.error("No Salesforce connection configured", o);
549
- return;
550
- }
708
+ ), I = class I extends A {
709
+ async input(s) {
551
710
  try {
552
- const t = this.config.operation;
553
- this.status({
554
- fill: "green",
555
- shape: "dot",
556
- text: `bulk ${t}...`
557
- });
558
- const s = await n.getConnection(), i = await this.config.sObjectType.resolve(o);
559
- let l = 0;
560
- if (t === "query") {
561
- const d = await s.bulk2.query(o.payload, {
562
- pollTimeout: this.config.pollTimeout,
563
- pollInterval: this.config.pollInterval,
564
- columnDelimiter: this.config.columnDelimiter,
565
- lineEnding: this.config.lineEnding
566
- });
567
- await new Promise((c, g) => {
568
- d.on("data", (u) => {
569
- l++, this.sendRecord(o, u);
570
- }), d.on("end", () => c()), d.on("error", g);
571
- }), 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({
572
733
  fill: "green",
573
734
  shape: "dot",
574
- text: `bulk ${t}: ${l} records`
575
- }), this.sendToPort("complete", {
576
- ...o,
577
- payload: { operation: t, sObjectType: i, totalRecords: l }
578
- });
579
- } else {
580
- const d = o.payload, c = s.bulk2.createJob({
581
- operation: t,
582
- object: i,
583
- columnDelimiter: this.config.columnDelimiter,
584
- lineEnding: this.config.lineEnding,
585
- ...t === "upsert" && this.config.externalIdField ? { externalIdFieldName: this.config.externalIdField } : {},
586
- ...this.config.assignmentRuleId ? { assignmentRuleId: this.config.assignmentRuleId } : {}
735
+ text: `query: ${i} records...`
587
736
  });
588
- await c.open(), this.sendJobCreated(o, {
589
- jobId: c.id,
590
- operation: t,
591
- sObjectType: i,
592
- state: "Open"
593
- }), await c.uploadData(d), await c.close(), await c.poll(this.config.pollInterval, this.config.pollTimeout);
594
- const g = await c.getAllResults(), u = g.successfulResults ?? [], m = g.failedResults ?? [], p = g.unprocessedRecords ?? [];
595
- l = u.length + m.length + p.length;
596
- for (const R of u)
597
- this.sendRecord(o, R);
598
- for (const R of m)
599
- this.sendRecord(o, R);
600
- const S = u.length, M = m.length;
601
- this.status({
602
- fill: M > 0 ? "red" : "green",
603
- shape: "dot",
604
- text: `bulk ${t}: ${l} records`
605
- }), this.sendToPort("complete", {
606
- ...o,
607
- payload: {
608
- jobId: c.id,
609
- operation: t,
610
- sObjectType: i,
611
- totalRecords: l,
612
- successCount: S,
613
- failureCount: M,
614
- unprocessedCount: p.length
615
- }
616
- });
617
- }
618
- } catch (t) {
619
- const s = t instanceof Error ? t.message : String(t);
620
- this.status({ fill: "red", shape: "dot", text: s }), this.error(`Bulk ${this.config.operation} failed: ${s}`, o);
621
- }
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
+ });
622
779
  }
623
780
  };
624
- f(b, "SalesforceBulk"), r(b, "type", "salesforce-bulk"), r(b, "category", "salesforce"), r(b, "color", "#FFFFFF"), r(b, "configSchema", de), r(b, "inputSchema", ue), r(b, "outputsSchema", fe);
625
- let O = b;
626
- const ge = 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(
627
784
  {
628
785
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
629
- connection: e.NodeRef($, {
786
+ connection: e.NodeRef(w, {
630
787
  "x-nrg-form": { icon: "cloud" }
631
788
  }),
632
789
  sObjectType: e.TypedInput({
@@ -640,12 +797,12 @@ const ge = h(
640
797
  statusPort: e.Boolean({ default: !1 })
641
798
  },
642
799
  { $id: "salesforce-describe:config" }
643
- ), me = h(
800
+ ), Te = p(
644
801
  {
645
802
  payload: e.Any()
646
803
  },
647
804
  { $id: "salesforce-describe:input" }
648
- ), ye = h(
805
+ ), $e = p(
649
806
  {
650
807
  payload: e.Object({
651
808
  name: e.String(),
@@ -655,22 +812,22 @@ const ge = h(
655
812
  })
656
813
  },
657
814
  { $id: "salesforce-describe:output" }
658
- ), T = class T extends k {
659
- async input(o) {
660
- const n = this.config.connection;
661
- if (!n) {
662
- 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);
663
820
  return;
664
821
  }
665
822
  try {
666
823
  this.status({ fill: "green", shape: "dot", text: "describing..." });
667
- const t = await n.getConnection(), s = await this.config.sObjectType.resolve(o), i = await t.sobject(s).describe();
824
+ const n = await t.getConnection(), o = await this.config.sObjectType.resolve(s), i = await n.sobject(o).describe();
668
825
  this.status({
669
826
  fill: "green",
670
827
  shape: "dot",
671
828
  text: `${i.name}: ${i.fields.length} fields`
672
829
  }), this.send({
673
- ...o,
830
+ ...s,
674
831
  payload: {
675
832
  name: i.name,
676
833
  fields: i.fields,
@@ -678,24 +835,24 @@ const ge = h(
678
835
  recordTypeInfos: i.recordTypeInfos
679
836
  }
680
837
  });
681
- } catch (t) {
838
+ } catch (n) {
682
839
  this.status({
683
840
  fill: "red",
684
841
  shape: "dot",
685
- text: t instanceof Error ? t.message : String(t)
842
+ text: n instanceof Error ? n.message : String(n)
686
843
  }), this.error(
687
- `Describe failed: ${t instanceof Error ? t.message : String(t)}`,
688
- o
844
+ `Describe failed: ${n instanceof Error ? n.message : String(n)}`,
845
+ s
689
846
  );
690
847
  }
691
848
  }
692
849
  };
693
- f(T, "SalesforceDescribe"), r(T, "type", "salesforce-describe"), r(T, "category", "salesforce"), r(T, "color", "#FFFFFF"), r(T, "configSchema", ge), r(T, "inputSchema", me), r(T, "outputsSchema", ye);
694
- let P = T;
695
- const xe = 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(
696
853
  {
697
854
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
698
- connection: e.NodeRef($, {
855
+ connection: e.NodeRef(w, {
699
856
  "x-nrg-form": { icon: "cloud" }
700
857
  }),
701
858
  channelName: e.String({
@@ -740,7 +897,7 @@ const xe = h(
740
897
  }
741
898
  }
742
899
  }
743
- ), be = h(
900
+ ), Se = p(
744
901
  {
745
902
  payload: e.Any(),
746
903
  replayId: e.Any(),
@@ -748,7 +905,7 @@ const xe = h(
748
905
  topic: e.String()
749
906
  },
750
907
  { $id: "salesforce-streaming:output" }
751
- ), w = class w extends k {
908
+ ), L = class L extends A {
752
909
  constructor() {
753
910
  super(...arguments);
754
911
  r(this, "client", null);
@@ -759,46 +916,46 @@ const xe = h(
759
916
  r(this, "stopped", !1);
760
917
  }
761
918
  async created() {
762
- const n = this.config.connection;
763
- if (!n) {
919
+ const t = this.config.connection;
920
+ if (!t) {
764
921
  this.status({ fill: "red", shape: "dot", text: "no connection" }), this.error("No Salesforce connection configured");
765
922
  return;
766
923
  }
767
- await this.subscribe(n);
924
+ await this.subscribe(t);
768
925
  }
769
- async subscribe(n) {
926
+ async subscribe(t) {
770
927
  if (!this.stopped)
771
928
  try {
772
929
  this.status({ fill: "green", shape: "dot", text: "connecting..." });
773
- let t;
930
+ let n;
774
931
  try {
775
- t = await n.getConnection(), await t.identity();
932
+ n = await t.getConnection(), await n.identity();
776
933
  } catch {
777
934
  this.status({ fill: "red", shape: "dot", text: "auth expired" }), this.error("Salesforce token expired. Re-authorize the connection.");
778
935
  return;
779
936
  }
780
- const s = n.getAccessToken(), i = n.getInstanceUrl();
781
- if (!s || !i) {
937
+ const o = n.accessToken, i = n.instanceUrl;
938
+ if (!o || !i) {
782
939
  this.status({ fill: "red", shape: "dot", text: "not authorized" }), this.error("Salesforce connection not authorized");
783
940
  return;
784
941
  }
785
- const l = (await import("salesforce-pubsub-api-client")).default;
786
- this.client = new l({
942
+ const c = (await import("salesforce-pubsub-api-client")).default;
943
+ this.client = new c({
787
944
  authType: "user-supplied",
788
- accessToken: s,
945
+ accessToken: o,
789
946
  instanceUrl: i
790
947
  }), await this.client.connect();
791
- 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) => {
792
949
  if (m === "event" || m === "lastevent")
793
950
  this.send({
794
- payload: (p == null ? void 0 : p.payload) ?? p,
795
- replayId: p == null ? void 0 : p.replayId,
796
- channel: c,
797
- 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
798
955
  });
799
956
  else if (m === "error") {
800
- const S = p instanceof Error ? p.message : String(p ?? "stream error");
801
- 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")) {
802
959
  this.stopped = !0, this.status({
803
960
  fill: "red",
804
961
  shape: "dot",
@@ -808,51 +965,51 @@ const xe = h(
808
965
  ), this.cleanup();
809
966
  return;
810
967
  }
811
- this.status({ fill: "red", shape: "dot", text: S }), this.scheduleReconnect(n);
968
+ this.status({ fill: "red", shape: "dot", text: N }), this.scheduleReconnect(t);
812
969
  } else if (m === "end") {
813
970
  if (this.stopped) return;
814
- 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);
815
972
  }
816
973
  }, "callback");
817
- if (this.grpcErrorHandler && process.removeListener("uncaughtException", this.grpcErrorHandler), this.grpcErrorHandler = (u) => {
818
- var m, p;
819
- ((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({
820
977
  fill: "red",
821
978
  shape: "dot",
822
979
  text: "auth expired — re-authorize"
823
980
  }), this.cleanup());
824
981
  }, process.on("uncaughtException", this.grpcErrorHandler), this.config.subscribeType === "EARLIEST")
825
982
  this.client.subscribeFromEarliestEvent(
826
- c,
827
- g,
828
- d
983
+ l,
984
+ h,
985
+ u
829
986
  );
830
987
  else if (this.config.subscribeType === "CUSTOM" && this.config.replayId) {
831
- const u = parseInt(this.config.replayId, 10);
988
+ const f = parseInt(this.config.replayId, 10);
832
989
  this.client.subscribeFromReplayId(
833
- c,
834
- g,
835
- d,
836
- u
990
+ l,
991
+ h,
992
+ u,
993
+ f
837
994
  );
838
995
  } else
839
- this.client.subscribe(c, g, d);
996
+ this.client.subscribe(l, h, u);
840
997
  this.status({
841
998
  fill: "green",
842
999
  shape: "dot",
843
- text: `subscribed: ${c}`
1000
+ text: `subscribed: ${l}`
844
1001
  }), this.reconnectAttempt = 0;
845
- } catch (t) {
1002
+ } catch (n) {
846
1003
  this.status({
847
1004
  fill: "red",
848
1005
  shape: "dot",
849
- text: t instanceof Error ? t.message : String(t)
1006
+ text: n instanceof Error ? n.message : String(n)
850
1007
  }), this.error(
851
- `Streaming subscription failed: ${t instanceof Error ? t.message : String(t)}`
852
- ), this.scheduleReconnect(n);
1008
+ `Streaming subscription failed: ${n instanceof Error ? n.message : String(n)}`
1009
+ ), this.scheduleReconnect(t);
853
1010
  }
854
1011
  }
855
- scheduleReconnect(n) {
1012
+ scheduleReconnect(t) {
856
1013
  if (this.stopped) return;
857
1014
  if (this.reconnectAttempt++, this.reconnectAttempt > this.maxReconnectAttempts) {
858
1015
  this.error(
@@ -864,24 +1021,24 @@ const xe = h(
864
1021
  });
865
1022
  return;
866
1023
  }
867
- const t = Math.min(
1024
+ const n = Math.min(
868
1025
  1e3 * Math.pow(2, this.reconnectAttempt),
869
1026
  this.maxReconnectDelay
870
1027
  );
871
1028
  this.log(
872
- `Scheduling reconnect in ${t}ms (attempt ${this.reconnectAttempt}/${this.maxReconnectAttempts})`
1029
+ `Scheduling reconnect in ${n}ms (attempt ${this.reconnectAttempt}/${this.maxReconnectAttempts})`
873
1030
  ), this.status({
874
1031
  fill: "green",
875
1032
  shape: "dot",
876
- text: `reconnecting in ${Math.round(t / 1e3)}s`
1033
+ text: `reconnecting in ${Math.round(n / 1e3)}s`
877
1034
  }), this.setTimeout(async () => {
878
- await this.cleanup(), await this.subscribe(n);
879
- }, t);
1035
+ await this.cleanup(), await this.subscribe(t);
1036
+ }, n);
880
1037
  }
881
1038
  async cleanup() {
882
- var n, t;
1039
+ var t, n;
883
1040
  try {
884
- 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);
885
1042
  } catch {
886
1043
  }
887
1044
  }
@@ -889,14 +1046,19 @@ const xe = h(
889
1046
  await this.cleanup();
890
1047
  }
891
1048
  };
892
- f(w, "SalesforceStreaming"), r(w, "type", "salesforce-streaming"), r(w, "category", "salesforce"), r(w, "color", "#FFFFFF"), r(w, "configSchema", xe), r(w, "outputsSchema", be);
893
- let j = w;
894
- const Te = 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(
895
1052
  {
896
1053
  name: e.String({ default: "", "x-nrg-form": { icon: "tag" } }),
897
- connection: e.NodeRef($, {
1054
+ connection: e.NodeRef(w, {
898
1055
  "x-nrg-form": { icon: "cloud" }
899
1056
  }),
1057
+ apexType: e.Union(
1058
+ [e.Literal("rest"), e.Literal("invocable")],
1059
+ { default: "rest", "x-nrg-form": { icon: "cog" } }
1060
+ ),
1061
+ // REST fields
900
1062
  method: e.Union(
901
1063
  [
902
1064
  e.Literal("GET"),
@@ -913,63 +1075,325 @@ const Te = h(
913
1075
  typedInputTypes: ["str", "msg"]
914
1076
  }
915
1077
  }),
1078
+ // Invocable field
1079
+ actionName: e.String({
1080
+ default: "",
1081
+ "x-nrg-form": { icon: "bolt" }
1082
+ }),
916
1083
  errorPort: e.Boolean({ default: !1 }),
917
1084
  completePort: e.Boolean({ default: !1 }),
918
1085
  statusPort: e.Boolean({ default: !1 })
919
1086
  },
920
- { $id: "salesforce-apex:config" }
921
- ), Ie = 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(
922
1124
  {
923
- 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 })
924
1158
  },
925
- { $id: "salesforce-apex:input" }
926
- ), $e = h(
1159
+ { $id: "salesforce-apex-code:config" }
1160
+ ), ve = p(
927
1161
  {
928
- payload: e.Any()
1162
+ classPrefix: e.String({ default: "NRG_" })
929
1163
  },
930
- { $id: "salesforce-apex:output" }
931
- ), I = class I extends k {
932
- 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
+ }
933
1346
  const n = this.config.connection;
934
1347
  if (!n) {
935
- this.error("No Salesforce connection configured", o);
1348
+ this.error("No Salesforce connection configured", t);
936
1349
  return;
937
1350
  }
938
1351
  try {
939
- const t = this.config.method;
940
- this.status({ fill: "green", shape: "dot", text: `${t}...` });
941
- const s = await n.getConnection(), i = await this.config.path.resolve(o);
942
- let l;
943
- const d = t.toLowerCase();
944
- d === "get" || d === "delete" ? l = await s.apex[d](i) : l = await s.apex[d](i, o.payload), this.status({ fill: "green", shape: "dot", text: `${t} done` }), this.send({ ...o, payload: l });
945
- } catch (t) {
946
- this.status({
947
- fill: "red",
948
- shape: "dot",
949
- text: t instanceof Error ? t.message : String(t)
950
- }), this.error(
951
- `Apex ${this.config.method} failed: ${t instanceof Error ? t.message : String(t)}`,
952
- o
953
- );
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());
954
1376
  }
1377
+ this.deployed = !1;
955
1378
  }
956
1379
  };
957
- f(I, "SalesforceApex"), r(I, "type", "salesforce-apex"), r(I, "category", "salesforce"), r(I, "color", "#FFFFFF"), r(I, "configSchema", Te), r(I, "inputSchema", Ie), r(I, "outputsSchema", $e);
958
- let v = I;
959
- const we = 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 = _({
960
1383
  nodes: [
961
- $,
962
- E,
963
- C,
964
- O,
965
- P,
1384
+ w,
1385
+ U,
1386
+ k,
966
1387
  j,
967
- v
1388
+ M,
1389
+ H,
1390
+ B,
1391
+ q
968
1392
  ]
969
1393
  });
970
- var F = we;
971
- 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));
972
1396
  export {
973
- F as default
1397
+ C as default
974
1398
  };
975
1399
  //# sourceMappingURL=index.mjs.map