@unboundcx/sdk 4.13.81 → 4.13.84

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.js CHANGED
@@ -26,6 +26,7 @@ import { CobrowseService } from './services/cobrowse.js';
26
26
  import { MessageTemplatesService } from './services/messageTemplates.js';
27
27
  import { ExternalOAuthService } from './services/externalOAuth.js';
28
28
  import { GoogleCalendarService } from './services/googleCalendar.js';
29
+ import { FormsService } from './services/forms.js';
29
30
  import { DriveService } from './services/drive.js';
30
31
  import { EnrollService } from './services/enroll.js';
31
32
  import { PhoneNumbersService } from './services/phoneNumbers.js';
@@ -125,6 +126,7 @@ class UnboundSDK extends BaseSDK {
125
126
  this.messageTemplates = new MessageTemplatesService(this);
126
127
  this.externalOAuth = new ExternalOAuthService(this);
127
128
  this.googleCalendar = new GoogleCalendarService(this);
129
+ this.forms = new FormsService(this);
128
130
  this.drive = new DriveService(this);
129
131
  this.enroll = new EnrollService(this);
130
132
  this.phoneNumbers = new PhoneNumbersService(this);
@@ -326,6 +328,8 @@ export { MessageTemplatesService } from './services/messageTemplates.js';
326
328
  export { WebchatVisitorService } from './services/webchat/VisitorService.js';
327
329
  export { ExternalOAuthService } from './services/externalOAuth.js';
328
330
  export { GoogleCalendarService } from './services/googleCalendar.js';
331
+ export { FormsService } from './services/forms.js';
332
+ export { FormsPublicService } from './services/forms/PublicService.js';
329
333
  export { DriveService } from './services/drive.js';
330
334
  export { EnrollService } from './services/enroll.js';
331
335
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.13.81",
3
+ "version": "4.13.84",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,57 @@
1
+ import { internalRequest } from '../../base.js';
2
+
3
+ // Public, unauthenticated forms surface -- `sdk.forms.public`. Mirrors
4
+ // WebchatVisitorService.js: the sdk instance backing this only needs
5
+ // `namespace` (or a custom `baseURL`) set at construction, never
6
+ // `sdk.token`. POSTs `forceFetch` (HTTP-only, no NATS transport) since
7
+ // these are one-shot fetches from a customer page / marketing site, same
8
+ // as every other visitor-facing call.
9
+ //
10
+ // Wire shape matches `POST /f/:publicKey` (app1-api webhooks service,
11
+ // forms-v2-precheck.md §4.1): plain form fields go at the top level of the
12
+ // body (fieldKey -> value, arrays allowed), and everything the server
13
+ // treats as a *control* field (not a form value) is sent with a leading
14
+ // underscore -- the same convention formSubmit.js/formSubmitPublicKey.js
15
+ // already split on for the legacy `_token` field.
16
+ export class FormsPublicService {
17
+ constructor(sdk) {
18
+ this.sdk = sdk;
19
+ }
20
+
21
+ /**
22
+ * Submit a public form by its publicKey (D1 -- every form has its own
23
+ * publicKey; no tracking-code/_token needed for this path). Legacy
24
+ * hosted-fields forms keep using the `/webhooks/form/:formId` +
25
+ * `_token` path (unchanged, not exposed here).
26
+ * @param {string} publicKey
27
+ * @param {Object} fields - fieldKey -> value (arrays kept as arrays).
28
+ * @param {Object} [options]
29
+ * @param {Object} [options.context] - Client-observed context (utm/referrer/
30
+ * landingUrl/etc, D12) to merge with what the server infers from the
31
+ * request itself -- sent as the `_context` control field.
32
+ * @param {string} [options.captchaToken] - Turnstile/etc response token
33
+ * (D10); sent as `_captchaToken`. Ignored server-side until a captcha
34
+ * provider is configured for the form/account.
35
+ * @param {string} [options.idempotencyKey] - Per-render dedupe token
36
+ * (D10); sent as `_idempotencyKey`.
37
+ * @returns {Promise<{ok:boolean, message?:string}>}
38
+ */
39
+ async submit(publicKey, fields, { context, captchaToken, idempotencyKey } = {}) {
40
+ this.sdk.validateParams(
41
+ { publicKey },
42
+ { publicKey: { type: 'string', required: true } },
43
+ );
44
+ const body = { ...(fields || {}) };
45
+ if (idempotencyKey) body._idempotencyKey = idempotencyKey;
46
+ if (captchaToken) body._captchaToken = captchaToken;
47
+ if (context) body._context = context;
48
+
49
+ return internalRequest(
50
+ this.sdk,
51
+ `/f/${publicKey}`,
52
+ 'POST',
53
+ { body },
54
+ true,
55
+ );
56
+ }
57
+ }
@@ -0,0 +1,46 @@
1
+ import { internalRequest } from '../../base.js';
2
+
3
+ // Agent-authenticated `formsAccountSettings` singleton -- `sdk.forms.settings`
4
+ // (defaultRegion, turnstileSiteKey, turnstileSecretRef; plan §6.5's
5
+ // account-settings page, `/app/setup/forms/account-settings`).
6
+ //
7
+ // GAP (forms-v2 P2, see plans/forms-v2-progress/P2.md): same as
8
+ // SubmissionsService.js -- the server-side singleton get/set controller +
9
+ // route are not built yet (no phase in forms-v2-precheck.md §9 owns this
10
+ // file explicitly). `/forms/settings` is P2's proposed path, chosen to
11
+ // mirror the client route name (`forms/account-settings`) rather than the
12
+ // generic `/object/:objectName` shape, since `formsAccountSettings` is a
13
+ // fixed-id singleton with no `id` the client ever knows (same shape as
14
+ // `chatAccountSettings`/`aiAccountSettings`) -- not a normal CRUD object.
15
+ // Whichever phase builds the backend (P5, alongside the account-settings
16
+ // page per §9) should implement exactly this path/method pair, or bump
17
+ // the SDK with a corrected one.
18
+ export class FormsSettingsService {
19
+ constructor(sdk) {
20
+ this.sdk = sdk;
21
+ }
22
+
23
+ /**
24
+ * @returns {Promise<{defaultRegion?:string, turnstileSiteKey?:string, turnstileSecretRef?:string}>}
25
+ * `turnstileSecretRef` is a reference/handle only -- the raw secret
26
+ * never round-trips to the client.
27
+ */
28
+ async get() {
29
+ return internalRequest(this.sdk, '/forms/settings', 'GET');
30
+ }
31
+
32
+ /**
33
+ * Merge-patch the singleton row.
34
+ * @param {Object} patch
35
+ * @param {string} [patch.defaultRegion]
36
+ * @param {string} [patch.turnstileSiteKey]
37
+ * @param {string} [patch.turnstileSecret] - Plaintext; server stores only
38
+ * `turnstileSecretRef` and never echoes the raw value back.
39
+ * @returns {Promise<Object>}
40
+ */
41
+ async set(patch) {
42
+ return internalRequest(this.sdk, '/forms/settings', 'PUT', {
43
+ body: { ...(patch || {}) },
44
+ });
45
+ }
46
+ }
@@ -0,0 +1,80 @@
1
+ import { internalRequest } from '../../base.js';
2
+
3
+ // Agent-authenticated formSubmissions actions -- `sdk.forms.submissions`.
4
+ // Normal agent-token path (no forceFetch, no authHeaders), same as any
5
+ // other authenticated service method (e.g. WebchatWidgetsService.get()).
6
+ //
7
+ // GAP (forms-v2 P2, see plans/forms-v2-progress/P2.md): the server-side
8
+ // routes these call do NOT exist yet. forms-v2-precheck.md §9 gates the
9
+ // Quarantine/reprocess UI behind P5, but never assigns an owner file for
10
+ // the *backend* controllers -- adding them here to app1-api's
11
+ // `objects/routes.js` (the `/:objectName/merge`-style precedent for a
12
+ // custom per-object action route) is outside P2's file-ownership map, so
13
+ // P2 only forward-declares the wire contract below. Whichever phase wires
14
+ // the server (P5 for reprocess/markNotSpam per plan §8, or earlier if
15
+ // needed) must implement these exact paths/methods, or bump the SDK with
16
+ // a corrected path.
17
+ export class FormsSubmissionsService {
18
+ constructor(sdk) {
19
+ this.sdk = sdk;
20
+ }
21
+
22
+ /**
23
+ * Re-run the pipeline for an existing submission from its stored
24
+ * rawFields (marks the new submission's `reprocessedFromId`).
25
+ * @param {string} id - formSubmissions id.
26
+ * @returns {Promise<Object>}
27
+ */
28
+ async reprocess(id) {
29
+ this.sdk.validateParams(
30
+ { id },
31
+ { id: { type: 'string', required: true } },
32
+ );
33
+ return internalRequest(
34
+ this.sdk,
35
+ `/object/formSubmissions/${id}/reprocess`,
36
+ 'POST',
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Clear a submission's spam status (Quarantine "Not spam" action, D10).
42
+ * @param {string} id - formSubmissions id.
43
+ * @returns {Promise<Object>}
44
+ */
45
+ async markNotSpam(id) {
46
+ this.sdk.validateParams(
47
+ { id },
48
+ { id: { type: 'string', required: true } },
49
+ );
50
+ return internalRequest(
51
+ this.sdk,
52
+ `/object/formSubmissions/${id}/mark-not-spam`,
53
+ 'POST',
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Resolve a submission flagged `identityConflict`/`review` (D16).
59
+ * @param {string} id - formSubmissions id.
60
+ * @param {string} choice - Which candidate record to keep/link; shape is
61
+ * whatever the Review queue UI (P4) settles on -- documented here as a
62
+ * passthrough until that's built.
63
+ * @returns {Promise<Object>}
64
+ */
65
+ async resolveReview(id, choice) {
66
+ this.sdk.validateParams(
67
+ { id, choice },
68
+ {
69
+ id: { type: 'string', required: true },
70
+ choice: { type: 'string', required: true },
71
+ },
72
+ );
73
+ return internalRequest(
74
+ this.sdk,
75
+ `/object/formSubmissions/${id}/resolve-review`,
76
+ 'POST',
77
+ { body: { choice } },
78
+ );
79
+ }
80
+ }
@@ -0,0 +1,15 @@
1
+ import { FormsPublicService } from './forms/PublicService.js';
2
+ import { FormsSubmissionsService } from './forms/SubmissionsService.js';
3
+ import { FormsSettingsService } from './forms/SettingsService.js';
4
+
5
+ // Forms v2 (forms-v2-plan.md §7 / forms-v2-precheck.md §5) -- `sdk.forms`.
6
+ // `public` needs no agent auth (VisitorService pattern, publicKey-scoped);
7
+ // `submissions`/`settings` are normal agent-token calls.
8
+ export class FormsService {
9
+ constructor(sdk) {
10
+ this.sdk = sdk;
11
+ this.public = new FormsPublicService(sdk);
12
+ this.submissions = new FormsSubmissionsService(sdk);
13
+ this.settings = new FormsSettingsService(sdk);
14
+ }
15
+ }
@@ -88,9 +88,10 @@ export class ReportingAgentsService {
88
88
  }
89
89
 
90
90
  /**
91
- * Per-agent per-local-day timesheet rows (net paid hours).
91
+ * Per-agent per-local-day timesheet rows (net paid hours), plus one
92
+ * additive-sum row per agent (`agents`) for grouped totals.
92
93
  * @param {Object} params - { from, to, userIds, teamIds }
93
- * @returns {Promise<Object>} { columns, rows }
94
+ * @returns {Promise<Object>} { columns, rows, agents }
94
95
  * @example
95
96
  * await sdk.reporting.agents.timesheet({ from, to, userIds: ['u1'] });
96
97
  */
@@ -107,13 +108,26 @@ export class ReportingAgentsService {
107
108
  }
108
109
 
109
110
  /**
110
- * CSV export of any of the four views above.
111
- * @param {Object} params - { view: 'summary'|'states'|'interactions'|'timesheet', from, to, userId, userIds, queueIds, teamIds, groupBy }
111
+ * CSV export of any of the four views above. For view: 'timesheet', pass
112
+ * `totals: true` to get one additive-sum row per agent instead of the
113
+ * flat per-agent-per-day rows.
114
+ * @param {Object} params - { view: 'summary'|'states'|'interactions'|'timesheet', from, to, userId, userIds, queueIds, teamIds, groupBy, totals }
112
115
  * @returns {Promise<Object>} raw CSV response (transport-dependent)
113
116
  * @example
114
117
  * await sdk.reporting.agents.export({ view: 'timesheet', from, to });
118
+ * await sdk.reporting.agents.export({ view: 'timesheet', from, to, totals: true });
115
119
  */
116
- async export({ view, from, to, userId, userIds, queueIds, teamIds, groupBy } = {}) {
120
+ async export({
121
+ view,
122
+ from,
123
+ to,
124
+ userId,
125
+ userIds,
126
+ queueIds,
127
+ teamIds,
128
+ groupBy,
129
+ totals,
130
+ } = {}) {
117
131
  this.sdk.validateParams(
118
132
  { from, to },
119
133
  { from: { type: 'string', required: true }, to: { type: 'string', required: true } },
@@ -127,6 +141,7 @@ export class ReportingAgentsService {
127
141
  queueIds,
128
142
  teamIds,
129
143
  groupBy,
144
+ totals: totals ? '1' : undefined,
130
145
  format: 'csv',
131
146
  });
132
147
  return internalRequest(this.sdk, `/reporting/agents/export${qs}`, 'GET', { httpOnly: true });