@mcpher/gas-fakes 1.2.19 → 1.2.21

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.
@@ -0,0 +1,84 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeItemResponse } from './fakeitemresponse.js';
3
+
4
+ export const newFakeFormResponse = (...args) => {
5
+ return Proxies.guard(new FakeFormResponse(...args));
6
+ };
7
+
8
+ /**
9
+ * @class FakeFormResponse
10
+ * @see https://developers.google.com/apps-script/reference/forms/form-response
11
+ */
12
+ export class FakeFormResponse {
13
+ /**
14
+ *
15
+ * @param {import('./fakeform.js').FakeForm} form the parent form
16
+ * @param {object} resource the response resource from the Forms API
17
+ */
18
+ constructor(form, resource) {
19
+ this.__form = form;
20
+ this.__resource = resource;
21
+ }
22
+
23
+ /**
24
+ * Gets the email address of the respondent.
25
+ * @returns {string} the respondent's email
26
+ */
27
+ getRespondentEmail() {
28
+ return this.__resource.respondentEmail || '';
29
+ }
30
+
31
+ /**
32
+ * Gets the unique ID for this form response.
33
+ * @returns {string} the unique ID
34
+ */
35
+ getId() {
36
+ return this.__resource.responseId;
37
+ }
38
+
39
+ /**
40
+ * Gets the date and time the response was submitted.
41
+ * @returns {Date} the submission timestamp
42
+ */
43
+ getTimestamp() {
44
+ return new Date(this.__resource.lastSubmittedTime);
45
+ }
46
+
47
+ /**
48
+ * Gets all item responses contained in the form response.
49
+ * @returns {import('./fakeitemresponse.js').FakeItemResponse[]} an array of item responses
50
+ */
51
+ getItemResponses() {
52
+ if (!this.__resource.answers) {
53
+ return [];
54
+ }
55
+
56
+ // Create a map to group answers by their parent form item. This is crucial for grid items,
57
+ // where each row is a separate answer in the API response but should be consolidated
58
+ // into a single ItemResponse in Apps Script.
59
+ const groupedAnswers = new Map();
60
+
61
+ for (const [questionId, answer] of Object.entries(this.__resource.answers)) {
62
+ const item = this.__form.getItemById(questionId);
63
+
64
+ if (item) {
65
+ const itemId = item.getId(); // Use the unique item ID as the key.
66
+ if (!groupedAnswers.has(itemId)) {
67
+ // Store the item itself along with an array for its answers.
68
+ groupedAnswers.set(itemId, { item, answers: [] });
69
+ }
70
+ // Add the raw answer object from the API response to the item's answer list.
71
+ // This correctly groups all row answers for a grid under the same parent item.
72
+ groupedAnswers.get(itemId).answers.push(answer);
73
+ }
74
+ }
75
+
76
+ // Now, create one FakeItemResponse for each grouped item.
77
+ const itemResponses = Array.from(groupedAnswers.values()).map(({ item, answers }) => {
78
+ return newFakeItemResponse(item, answers);
79
+ });
80
+
81
+ // Finally, sort the responses based on the item's index in the form.
82
+ return itemResponses.sort((a, b) => a.getItem().getIndex() - b.getItem().getIndex());
83
+ }
84
+ }
@@ -0,0 +1,105 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeFormItem } from './fakeformitem.js';
3
+ import { registerFormItem } from './formitemregistry.js';
4
+ import { signatureArgs } from '../../support/helpers.js';
5
+ import { Utils } from '../../support/utils.js';
6
+ import { ItemType } from '../enums/formsenums.js';
7
+
8
+ export const newFakeGridItem = (...args) => {
9
+ return Proxies.guard(new FakeGridItem(...args));
10
+ };
11
+
12
+ /**
13
+ * @class FakeGridItem
14
+ * A fake for the GridItem class in Apps Script.
15
+ * @see https://developers.google.com/apps-script/reference/forms/grid-item
16
+ */
17
+ export class FakeGridItem extends FakeFormItem {
18
+ constructor(form, itemId) {
19
+ super(form, itemId);
20
+ }
21
+
22
+ /**
23
+ * Gets the values for every column in the grid.
24
+ * @returns {string[]} an array of column values
25
+ */
26
+ getColumns() {
27
+ const choiceQuestion = this.__resource.questionGroupItem?.grid?.columns;
28
+ if (!choiceQuestion || !choiceQuestion.options) {
29
+ return [];
30
+ }
31
+ return choiceQuestion.options.map(option => option.value);
32
+ }
33
+
34
+ /**
35
+ * Gets the values for every row in the grid.
36
+ * @returns {string[]} an array of row values
37
+ */
38
+ getRows() {
39
+ const questions = this.__resource.questionGroupItem?.questions;
40
+ if (!questions) {
41
+ return [];
42
+ }
43
+ return questions.map(question => question.rowQuestion?.title || null).filter(f=>f);
44
+ }
45
+
46
+ /**
47
+ * Sets the columns of the grid based on an array of values.
48
+ * @param {string[]} columns an array of column values
49
+ * @returns {FakeGridItem} this item, for chaining
50
+ */
51
+ setColumns(columns) {
52
+ const { nargs, matchThrow } = signatureArgs(arguments, 'GridItem.setColumns');
53
+ if (nargs !== 1 || !Utils.is.array(columns) || !columns.every(Utils.is.string)) {
54
+ matchThrow('Invalid arguments: expected a string array.');
55
+ }
56
+ if (columns.length === 0) {
57
+ throw new Error('The array of columns cannot be empty.');
58
+ }
59
+
60
+ const updatedResource = JSON.parse(JSON.stringify(this.__resource));
61
+ updatedResource.questionGroupItem.grid.columns.options = columns.map(c => ({ value: c }));
62
+
63
+ const updateRequest = Forms.newRequest().setUpdateItem({
64
+ item: updatedResource,
65
+ location: { index: this.getIndex() },
66
+ updateMask: 'questionGroupItem.grid.columns.options',
67
+ });
68
+
69
+ return this.__update(updateRequest);
70
+ }
71
+
72
+ /**
73
+ * Sets the rows of the grid based on an array of values.
74
+ * @param {string[]} rows an array of row values
75
+ * @returns {FakeGridItem} this item, for chaining
76
+ */
77
+ setRows(rows) {
78
+ const { nargs, matchThrow } = signatureArgs(arguments, 'GridItem.setRows');
79
+ if (nargs !== 1 || !Utils.is.array(rows) || !rows.every(Utils.is.string)) {
80
+ matchThrow('Invalid arguments: expected a string array.');
81
+ }
82
+ if (rows.length === 0) {
83
+ throw new Error('The array of rows cannot be empty.');
84
+ }
85
+
86
+ const updatedResource = JSON.parse(JSON.stringify(this.__resource));
87
+ updatedResource.questionGroupItem.questions = rows.map(r => ({
88
+ rowQuestion: { title: r },
89
+ }));
90
+
91
+ const updateRequest = Forms.newRequest().setUpdateItem({
92
+ item: updatedResource,
93
+ location: { index: this.getIndex() },
94
+ updateMask: 'questionGroupItem.questions',
95
+ });
96
+
97
+ return this.__update(updateRequest);
98
+ }
99
+
100
+ toString() {
101
+ return 'GridItem';
102
+ }
103
+ }
104
+
105
+ registerFormItem(ItemType.GRID, newFakeGridItem);
@@ -0,0 +1,56 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeFormItem } from './fakeformitem.js';
3
+
4
+ export const newFakeItemResponse = (...args) => {
5
+ return Proxies.guard(new FakeItemResponse(...args));
6
+ };
7
+
8
+ /**
9
+ * @class FakeItemResponse
10
+ * @see https://developers.google.com/apps-script/reference/forms/item-response
11
+ */
12
+ export class FakeItemResponse {
13
+ /**
14
+ *
15
+ * @param {import('./fakeformitem.js').FakeFormItem} item the item this is a response to
16
+ * @param {object[]} answers an array of answer objects from the Forms API response
17
+ */
18
+ constructor(item, answers) {
19
+ this.__item = item;
20
+ this.__answers = answers; // This is now an array of answer objects
21
+ }
22
+
23
+ /**
24
+ * Gets the Item object for the question that this response answers.
25
+ */
26
+ getItem() {
27
+ return this.__item;
28
+ }
29
+
30
+ /**
31
+ * Gets the ID of the item this response is for. Note: This is a custom method for gas-fakes.
32
+ * @returns {string} the item's ID
33
+ */
34
+ getId() {
35
+ return this.__item.getId();
36
+ }
37
+
38
+ /**
39
+ * Gets the answer to the question as a string.
40
+ * @returns {string} the response
41
+ */
42
+ getResponse() {
43
+ // Flatten the 'textAnswers.answers' arrays from all answer objects.
44
+ // This correctly combines all row answers for a grid item.
45
+ const allTextAnswers = this.__answers.flatMap(
46
+ (answer) => answer?.textAnswers?.answers || []
47
+ );
48
+
49
+ if (allTextAnswers.length === 0) {
50
+ return '';
51
+ }
52
+
53
+ // For items like grids, there can be multiple answer values. The live script joins them with a comma.
54
+ return allTextAnswers.map(a => a.value).join(',');
55
+ }
56
+ }
@@ -0,0 +1,124 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeFormItem } from './fakeformitem.js';
3
+ import { newFakeChoice } from './fakechoice.js';
4
+ import { registerFormItem } from './formitemregistry.js';
5
+ import { ItemType } from '../enums/formsenums.js';
6
+
7
+ export const newFakeListItem = (...args) => {
8
+ return Proxies.guard(new FakeListItem(...args));
9
+ };
10
+
11
+ /**
12
+ * @class FakeListItem
13
+ * @see https://developers.google.com/apps-script/reference/forms/list-item
14
+ */
15
+ export class FakeListItem extends FakeFormItem {
16
+ constructor(...args) {
17
+ super(...args);
18
+ }
19
+
20
+ /**
21
+ * Creates a new choice for this item.
22
+ * @param {string} value The value for the new choice.
23
+ * @param {import('./pagebreakitem.js').FakePageBreakItem | import('../formapp.js').PageNavigationType} navigation The navigation action.
24
+ * @returns {import('./fakechoice.js').FakeChoice} The new choice.
25
+ */
26
+ createChoice(value, navigation) {
27
+ // In the real API, this creates a Choice object that is not yet attached.
28
+ // For the fake, we can create and return a representation of it.
29
+ if (navigation) {
30
+ let navType;
31
+ let pageId;
32
+ if (typeof navigation.getId === 'function') {
33
+ // It's a PageBreakItem object
34
+ navType = 'GO_TO_PAGE';
35
+ pageId = navigation.getId();
36
+ } else {
37
+ // It's a PageNavigationType enum value
38
+ navType = navigation.toString().toUpperCase();
39
+ }
40
+ return newFakeChoice(value, navType, pageId, this.__form, this.getType());
41
+ }
42
+
43
+ return newFakeChoice(value, null, null, this.__form, this.getType());
44
+ }
45
+
46
+ /**
47
+ * Gets the choices for this item.
48
+ * @returns {import('./fakechoice.js').FakeChoice[]} The choices.
49
+ */
50
+ getChoices() {
51
+ const options = this.__resource.questionItem?.question?.choiceQuestion?.options || [];
52
+ return options.map(option => {
53
+ let navType = null;
54
+ let pageId = null;
55
+
56
+ // Translate from API format back to Apps Script format.
57
+ if (option.goToSectionId) {
58
+ navType = 'GO_TO_PAGE';
59
+ pageId = option.goToSectionId;
60
+ } else if (option.goToAction) {
61
+ switch (option.goToAction) {
62
+ case 'NEXT_SECTION': navType = 'CONTINUE'; break;
63
+ case 'RESTART_FORM': navType = 'RESTART'; break;
64
+ case 'SUBMIT_FORM': navType = 'SUBMIT'; break;
65
+ }
66
+ }
67
+ return newFakeChoice(option.value, navType, pageId, this.__form, this.getType());
68
+ });
69
+ }
70
+ /**
71
+ * Sets the choices for the item.
72
+ * @param {import('./fakechoice.js').FakeChoice[]} choices The choices to set.
73
+ * @returns {FakeListItem} The item, for chaining.
74
+ */
75
+ setChoices(choices) {
76
+ // The Forms API expects an array of {value: string}, not FakeChoice objects.
77
+ // We need to map the array of FakeChoice objects to the correct format.
78
+ const options = choices.map(choice => {
79
+ const option = { value: choice.getValue() };
80
+ // The FakeChoice object stores these as internal properties.
81
+ // We need to translate from Apps Script enums to the Forms API enums.
82
+ if (choice.__navType) {
83
+ const navType = choice.__navType.toUpperCase();
84
+ switch (navType) {
85
+ case 'GO_TO_PAGE':
86
+ // For navigating to a specific page, you ONLY set the goToSectionId.
87
+ // The pageId is the itemId of the PageBreakItem.
88
+ option.goToSectionId = choice.__pageId;
89
+ break;
90
+ case 'CONTINUE':
91
+ option.goToAction = 'NEXT_SECTION';
92
+ break;
93
+ default:
94
+ option.goToAction = navType; // For RESTART_FORM, SUBMIT_FORM
95
+ break;
96
+ }
97
+ }
98
+ return option;
99
+ });
100
+ const updateRequest = {
101
+ updateItem: {
102
+ item: {
103
+ // The item payload should contain the questionItem directly,
104
+ // not nested within another 'question' object.
105
+ questionItem: { question: { choiceQuestion: { type: 'DROP_DOWN', options } } }
106
+ },
107
+ location: { index: this.getIndex() },
108
+ updateMask: 'questionItem.question.choiceQuestion',
109
+ },
110
+ };
111
+ return this.__update(updateRequest);
112
+ }
113
+
114
+ /**
115
+ * Returns the string "ListItem" to identify the class.
116
+ * @returns {string} The string "ListItem".
117
+ */
118
+ toString() {
119
+ return 'ListItem';
120
+ }
121
+ }
122
+
123
+ // Register the factory function for this item type.
124
+ registerFormItem(ItemType.LIST, newFakeListItem);
@@ -0,0 +1,25 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeChoiceItem } from './fakechoiceitem.js';
3
+ import { registerFormItem } from './formitemregistry.js';
4
+ import { ItemType } from '../enums/formsenums.js';
5
+
6
+ export const newFakeMultipleChoiceItem = (form, itemId) => {
7
+ return Proxies.guard(new FakeMultipleChoiceItem(form, itemId));
8
+ };
9
+
10
+ /**
11
+ * @class FakeMultipleChoiceItem
12
+ * A fake for the MultipleChoiceItem class in Apps Script.
13
+ * @see https://developers.google.com/apps-script/reference/forms/multiple-choice-item
14
+ */
15
+ export class FakeMultipleChoiceItem extends FakeChoiceItem {
16
+ constructor(form, itemId) {
17
+ super(form, itemId);
18
+ }
19
+ toString() {
20
+ return 'MultipleChoiceItem';
21
+ }
22
+ }
23
+
24
+ // Register the factory function for this item type.
25
+ registerFormItem(ItemType.MULTIPLE_CHOICE, newFakeMultipleChoiceItem);
@@ -0,0 +1,54 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeFormItem } from './fakeformitem.js';
3
+ import { registerFormItem } from './formitemregistry.js';
4
+ import { ItemType, PageNavigationType } from '../enums/formsenums.js';
5
+
6
+ export const newFakePageBreakItem = (...args) => {
7
+ return Proxies.guard(new FakePageBreakItem(...args));
8
+ };
9
+
10
+ /**
11
+ * @class FakePageBreakItem
12
+ * @see https://developers.google.com/apps-script/reference/forms/page-break-item
13
+ */
14
+ export class FakePageBreakItem extends FakeFormItem {
15
+ constructor(...args) {
16
+ super(...args);
17
+ }
18
+
19
+ /**
20
+ * Sets the page to navigate to when the user advances past this page.
21
+ * @param {FakePageBreakItem | import('../formapp.js').PageNavigationType} navigation The navigation action.
22
+ * @returns {FakePageBreakItem} The item, for chaining.
23
+ */
24
+ setGoToPage(navigation) {
25
+ // There is no public Forms API endpoint to set the navigation for a PageBreakItem.
26
+ // This method is therefore not implementable in the fake environment.
27
+ throw new Error('setGoToPage is not supported for PageBreakItems via the public Google Forms API.');
28
+ }
29
+
30
+ /**
31
+ * Gets the page-break item that this page break navigates to.
32
+ * @returns {FakePageBreakItem | null} The page-break item, or null if the page does not navigate to a specific page.
33
+ */
34
+ getGoToPage() {
35
+ // The API does not support setting a specific page destination for a page break.
36
+ return null;
37
+ }
38
+
39
+ getPageNavigationType() {
40
+ // Since navigation cannot be set via the API, the navigation type will always be the default.
41
+ return PageNavigationType.CONTINUE;
42
+ }
43
+
44
+ /**
45
+ * Returns the string "PageBreakItem" to identify the class.
46
+ * @returns {string} The string "PageBreakItem".
47
+ */
48
+ toString() {
49
+ return 'PageBreakItem';
50
+ }
51
+ }
52
+
53
+ // Register the factory function for this item type.
54
+ registerFormItem(ItemType.PAGE_BREAK, newFakePageBreakItem);
@@ -0,0 +1,121 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeFormItem } from './fakeformitem.js';
3
+ import { registerFormItem } from './formitemregistry.js';
4
+ import { ItemType } from '../enums/formsenums.js';
5
+ import { signatureArgs } from '../../support/helpers.js';
6
+ import { Utils } from '../../support/utils.js';
7
+ const { is } = Utils;
8
+
9
+ export const newFakeScaleItem = (...args) => {
10
+ return Proxies.guard(new FakeScaleItem(...args));
11
+ };
12
+
13
+ /**
14
+ * @class FakeScaleItem
15
+ * A fake for the ScaleItem class in Apps Script.
16
+ * @see https://developers.google.com/apps-script/reference/forms/scale-item
17
+ */
18
+ export class FakeScaleItem extends FakeFormItem {
19
+ constructor(form, itemId) {
20
+ super(form, itemId);
21
+ }
22
+
23
+ /**
24
+ * Gets the lower bound of the scale.
25
+ * @returns {Integer} the lower bound
26
+ */
27
+ getLowerBound() {
28
+ return this.__resource.questionItem.question.scaleQuestion.low || 0;
29
+ }
30
+
31
+ /**
32
+ * Gets the upper bound of the scale.
33
+ * @returns {Integer} the upper bound
34
+ */
35
+ getUpperBound() {
36
+ return this.__resource.questionItem.question.scaleQuestion.high;
37
+ }
38
+
39
+ /**
40
+ * Gets the label for the scale's lower bound.
41
+ * @returns {string} the label for the lower bound
42
+ */
43
+ getLeftLabel() {
44
+ return this.__resource.questionItem.question.scaleQuestion.lowLabel || '';
45
+ }
46
+
47
+ /**
48
+ * Gets the label for the scale's upper bound.
49
+ * @returns {string} the label for the upper bound
50
+ */
51
+ getRightLabel() {
52
+ return this.__resource.questionItem.question.scaleQuestion.highLabel || '';
53
+ }
54
+
55
+ /**
56
+ * Sets the scale's bounds and, optionally, labels.
57
+ * @param {Integer} lower the lower bound
58
+ * @param {Integer} upper the upper bound
59
+ * @returns {FakeScaleItem} this item, for chaining
60
+ */
61
+ setBounds(lower, upper) {
62
+ const { nargs, matchThrow } = signatureArgs(arguments, 'ScaleItem.setBounds');
63
+ if (nargs !== 2 || !is.number(lower) || !is.number(upper)) {
64
+ matchThrow('Invalid arguments: expected two numbers.');
65
+ }
66
+
67
+ // Truncate decimals as per documentation.
68
+ const lowerInt = Math.trunc(lower);
69
+ const upperInt = Math.trunc(upper);
70
+
71
+ // Validate bounds as per documentation.
72
+ if (lowerInt !== 0 && lowerInt !== 1) {
73
+ throw new Error('The lower bound must be 0 or 1.');
74
+ }
75
+ if (upperInt < 3 || upperInt > 10) {
76
+ throw new Error('The upper bound must be between 3 and 10, inclusive.');
77
+ }
78
+ const updatedResource = JSON.parse(JSON.stringify(this.__resource));
79
+ updatedResource.questionItem.question.scaleQuestion.low = lowerInt;
80
+ updatedResource.questionItem.question.scaleQuestion.high = upperInt;
81
+
82
+ const updateRequest = Forms.newRequest().setUpdateItem({
83
+ item: updatedResource,
84
+ location: { index: this.getIndex() },
85
+ updateMask: 'questionItem.question.scaleQuestion',
86
+ });
87
+
88
+ return this.__update(updateRequest);
89
+ }
90
+
91
+ /**
92
+ * Sets the labels for the scale's lower and upper bounds.
93
+ * @param {string} lower the label for the lower bound
94
+ * @param {string} upper the label for the upper bound
95
+ * @returns {FakeScaleItem} this item, for chaining
96
+ */
97
+ setLabels(lower, upper) {
98
+ const { nargs, matchThrow } = signatureArgs(arguments, 'ScaleItem.setLabels');
99
+ if (nargs !== 2 || !is.string(lower) || !is.string(upper)) {
100
+ matchThrow('Invalid arguments: expected two strings.');
101
+ }
102
+
103
+ const updatedResource = JSON.parse(JSON.stringify(this.__resource));
104
+ updatedResource.questionItem.question.scaleQuestion.lowLabel = lower;
105
+ updatedResource.questionItem.question.scaleQuestion.highLabel = upper;
106
+
107
+ const updateRequest = Forms.newRequest().setUpdateItem({
108
+ item: updatedResource,
109
+ location: { index: this.getIndex() },
110
+ updateMask: 'questionItem.question.scaleQuestion',
111
+ });
112
+
113
+ return this.__update(updateRequest);
114
+ }
115
+
116
+ toString() {
117
+ return 'ScaleItem';
118
+ }
119
+ }
120
+
121
+ registerFormItem(ItemType.SCALE, newFakeScaleItem);
@@ -0,0 +1,25 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeFormItem } from './fakeformitem.js';
3
+ import { registerFormItem } from './formitemregistry.js';
4
+ import { ItemType } from '../enums/formsenums.js';
5
+
6
+ export const newFakeSectionHeaderItem = (...args) => {
7
+ return Proxies.guard(new FakeSectionHeaderItem(...args));
8
+ };
9
+
10
+ /**
11
+ * @class FakeSectionHeaderItem
12
+ * A fake for the SectionHeaderItem class in Apps Script.
13
+ * @see https://developers.google.com/apps-script/reference/forms/section-header-item
14
+ */
15
+ export class FakeSectionHeaderItem extends FakeFormItem {
16
+ constructor(form, itemId) {
17
+ super(form, itemId);
18
+ }
19
+
20
+ toString() {
21
+ return 'SectionHeaderItem';
22
+ }
23
+ }
24
+
25
+ registerFormItem(ItemType.SECTION_HEADER, newFakeSectionHeaderItem);
@@ -0,0 +1,20 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakeFormItem } from './fakeformitem.js';
3
+
4
+ export const newFakeTextItem = (...args) => {
5
+ return Proxies.guard(new FakeTextItem(...args));
6
+ };
7
+
8
+ /**
9
+ * @class FakeTextItem
10
+ * @see https://developers.google.com/apps-script/reference/forms/text-item
11
+ */
12
+ export class FakeTextItem extends FakeFormItem {
13
+ constructor(...args) {
14
+ super(...args);
15
+ }
16
+
17
+ toString() {
18
+ return 'TextItem';
19
+ }
20
+ }
@@ -2,5 +2,10 @@
2
2
  // with the formitemRegistry. By importing them here, we trigger their
3
3
  // registration code.
4
4
 
5
- import './fakecheckboxitem.js';
5
+ import './fakecheckboxitem.js'
6
+ import './fakegriditem.js';
7
+ import './fakecheckboxgriditem.js';
8
+ import './fakescaleitem.js';
9
+ import './fakepagebreakitem.js';
10
+ import './fakelistitem.js';
6
11
  // Add other item types here as they are implemented (e.g., './faketextitem.js')
@@ -12,7 +12,7 @@ import { getFormsApiClient } from '../services/advforms/formsapis.js';
12
12
 
13
13
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
14
14
 
15
- export const sxForms = async (Auth, { prop, method, params, options = {} }) => {
15
+ export const sxForms = async (Auth, { prop, subProp, method, params, options = {} }) => {
16
16
 
17
17
  const apiClient = getFormsApiClient();
18
18
 
@@ -24,7 +24,11 @@ export const sxForms = async (Auth, { prop, method, params, options = {} }) => {
24
24
  let error;
25
25
 
26
26
  try {
27
- const callish = apiClient[prop];
27
+ // Access the base property (e.g., 'forms'), then the sub-property if it exists (e.g., 'responses').
28
+ let callish = apiClient[prop];
29
+ if (subProp) {
30
+ callish = callish[subProp];
31
+ }
28
32
  response = await callish[method](params, options);
29
33
  } catch (err) {
30
34
  error = err;
@@ -35,14 +39,14 @@ export const sxForms = async (Auth, { prop, method, params, options = {} }) => {
35
39
 
36
40
  if (isRetryable && i < maxRetries - 1) {
37
41
  const jitter = Math.floor(Math.random() * 1000);
38
- syncWarn(`Retryable error on Forms API call ${prop}.${method} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
42
+ syncWarn(`Retryable error on Forms API call ${prop}${subProp ? '.' + subProp : ''}.${method} (status: ${response?.status}). Retrying in ${delay + jitter}ms...`);
39
43
  await sleep(delay + jitter);
40
44
  delay *= 2;
41
45
  continue;
42
46
  }
43
47
 
44
48
  if (error || isRetryable) {
45
- syncError(`Failed in sxForms for ${prop}.${method}`, error);
49
+ syncError(`Failed in sxForms for ${prop}${subProp ? '.' + subProp : ''}.${method}`, error);
46
50
  return { data: null, response: responseSyncify(response) };
47
51
  }
48
52
  return { data: response.data, response: responseSyncify(response) };
@@ -151,8 +151,8 @@ const fxGeneric = ({
151
151
  if (method === "get") {
152
152
  return register(resourceId, cacher, result, false, otherParams);
153
153
  }
154
-
155
- if (resourceId) {
154
+
155
+ else if (resourceId) {
156
156
  cacher.clear(resourceId);
157
157
  }
158
158
  return result;