@pixelated-tech/components 3.14.4 → 3.15.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.
Files changed (130) hide show
  1. package/dist/components/admin/site-health/site-health-core-web-vitals.integration.js +21 -8
  2. package/dist/components/admin/site-health/site-health-github.integration.js +6 -6
  3. package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +36 -16
  4. package/dist/components/admin/site-health/site-health-template.js +10 -6
  5. package/dist/components/config/config.types.js +12 -0
  6. package/dist/components/general/markdown.js +35 -0
  7. package/dist/components/general/nerdjoke.js +2 -4
  8. package/dist/components/general/proxy-handler.js +2 -2
  9. package/dist/components/general/sitemap.js +2 -4
  10. package/dist/components/general/smartfetch.js +211 -0
  11. package/dist/components/general/tiles.js +1 -1
  12. package/dist/components/general/urlbuilder.js +74 -0
  13. package/dist/components/integrations/contentful.delivery.js +24 -20
  14. package/dist/components/integrations/contentful.management.js +188 -151
  15. package/dist/components/integrations/flickr.js +15 -22
  16. package/dist/components/integrations/gemini-api.client.js +22 -21
  17. package/dist/components/integrations/gemini-api.server.js +50 -46
  18. package/dist/components/integrations/google.reviews.functions.js +19 -5
  19. package/dist/components/integrations/googleplaces.js +33 -9
  20. package/dist/components/integrations/gravatar.functions.js +15 -7
  21. package/dist/components/integrations/hubspot.components.js +8 -10
  22. package/dist/components/integrations/instagram.functions.js +9 -4
  23. package/dist/components/integrations/lipsum.js +6 -10
  24. package/dist/components/integrations/loremipsum.js +21 -21
  25. package/dist/components/integrations/socialcard.js +14 -8
  26. package/dist/components/integrations/spotify.functions.js +7 -4
  27. package/dist/components/integrations/wordpress.functions.js +17 -19
  28. package/dist/components/integrations/yelp.js +6 -7
  29. package/dist/components/shoppingcart/ebay.functions.js +69 -53
  30. package/dist/components/shoppingcart/shoppingcart.components.js +1 -1
  31. package/dist/components/sitebuilder/config/google-fonts.js +13 -6
  32. package/dist/components/sitebuilder/form/formbuilder.js +1 -1
  33. package/dist/components/sitebuilder/form/formengine.js +37 -10
  34. package/dist/components/sitebuilder/form/formsubmit.js +205 -0
  35. package/dist/components/sitebuilder/page/components/SaveLoadSection.js +24 -12
  36. package/dist/config/pixelated.config.json.enc +1 -1
  37. package/dist/data/form.json +7 -0
  38. package/dist/index.js +4 -2
  39. package/dist/index.server.js +3 -1
  40. package/dist/scripts/pixelated-eslint-plugin.js +51 -0
  41. package/dist/types/components/admin/site-health/site-health-core-web-vitals.integration.d.ts.map +1 -1
  42. package/dist/types/components/admin/site-health/site-health-github.integration.d.ts.map +1 -1
  43. package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -1
  44. package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -1
  45. package/dist/types/components/config/config.types.d.ts +11 -0
  46. package/dist/types/components/config/config.types.d.ts.map +1 -1
  47. package/dist/types/components/general/markdown.d.ts +12 -0
  48. package/dist/types/components/general/markdown.d.ts.map +1 -1
  49. package/dist/types/components/general/nerdjoke.d.ts.map +1 -1
  50. package/dist/types/components/general/proxy-handler.d.ts.map +1 -1
  51. package/dist/types/components/general/sitemap.d.ts.map +1 -1
  52. package/dist/types/components/general/smartfetch.d.ts +85 -0
  53. package/dist/types/components/general/smartfetch.d.ts.map +1 -0
  54. package/dist/types/components/general/tiles.d.ts.map +1 -1
  55. package/dist/types/components/general/urlbuilder.d.ts +64 -0
  56. package/dist/types/components/general/urlbuilder.d.ts.map +1 -0
  57. package/dist/types/components/integrations/contentful.delivery.d.ts.map +1 -1
  58. package/dist/types/components/integrations/contentful.management.d.ts.map +1 -1
  59. package/dist/types/components/integrations/flickr.d.ts.map +1 -1
  60. package/dist/types/components/integrations/gemini-api.client.d.ts.map +1 -1
  61. package/dist/types/components/integrations/gemini-api.server.d.ts +1 -1
  62. package/dist/types/components/integrations/gemini-api.server.d.ts.map +1 -1
  63. package/dist/types/components/integrations/google.reviews.functions.d.ts.map +1 -1
  64. package/dist/types/components/integrations/googleplaces.d.ts.map +1 -1
  65. package/dist/types/components/integrations/gravatar.functions.d.ts.map +1 -1
  66. package/dist/types/components/integrations/hubspot.components.d.ts.map +1 -1
  67. package/dist/types/components/integrations/instagram.functions.d.ts.map +1 -1
  68. package/dist/types/components/integrations/lipsum.d.ts.map +1 -1
  69. package/dist/types/components/integrations/loremipsum.d.ts.map +1 -1
  70. package/dist/types/components/integrations/socialcard.d.ts.map +1 -1
  71. package/dist/types/components/integrations/spotify.functions.d.ts.map +1 -1
  72. package/dist/types/components/integrations/wordpress.functions.d.ts.map +1 -1
  73. package/dist/types/components/integrations/yelp.d.ts.map +1 -1
  74. package/dist/types/components/shoppingcart/ebay.functions.d.ts.map +1 -1
  75. package/dist/types/components/sitebuilder/config/google-fonts.d.ts.map +1 -1
  76. package/dist/types/components/sitebuilder/form/formengine.d.ts +4 -4
  77. package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -1
  78. package/dist/types/components/sitebuilder/form/{formutils.d.ts → formengineutilities.d.ts} +1 -1
  79. package/dist/types/components/sitebuilder/form/formengineutilities.d.ts.map +1 -0
  80. package/dist/types/components/sitebuilder/form/formsubmit.d.ts +70 -0
  81. package/dist/types/components/sitebuilder/form/formsubmit.d.ts.map +1 -0
  82. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -1
  83. package/dist/types/index.d.ts +4 -2
  84. package/dist/types/index.server.d.ts +3 -1
  85. package/dist/types/scripts/pixelated-eslint-plugin.d.ts +21 -0
  86. package/dist/types/stories/admin/contentful-migration.stories.d.ts +43 -0
  87. package/dist/types/stories/admin/contentful-migration.stories.d.ts.map +1 -1
  88. package/dist/types/stories/general/text-generation.stories.d.ts +116 -0
  89. package/dist/types/stories/general/text-generation.stories.d.ts.map +1 -0
  90. package/dist/types/stories/integrations/google.reviews.stories.d.ts +52 -0
  91. package/dist/types/stories/integrations/google.reviews.stories.d.ts.map +1 -1
  92. package/dist/types/stories/integrations/gravatar.stories.d.ts.map +1 -1
  93. package/dist/types/stories/integrations/instagram.stories.d.ts +38 -0
  94. package/dist/types/stories/integrations/instagram.stories.d.ts.map +1 -1
  95. package/dist/types/stories/sitebuilder/form-engine.stories.d.ts +13 -7
  96. package/dist/types/stories/sitebuilder/form-engine.stories.d.ts.map +1 -1
  97. package/dist/types/stories/sitebuilder/form.honeypot.stories.d.ts +0 -19
  98. package/dist/types/stories/sitebuilder/form.honeypot.stories.d.ts.map +1 -1
  99. package/dist/types/test/test-utils.d.ts +2 -0
  100. package/dist/types/test/test-utils.d.ts.map +1 -1
  101. package/dist/types/tests/formengineutilities.test.d.ts +2 -0
  102. package/dist/types/tests/formengineutilities.test.d.ts.map +1 -0
  103. package/dist/types/tests/google-apis.test.d.ts +2 -0
  104. package/dist/types/tests/google-apis.test.d.ts.map +1 -0
  105. package/dist/types/tests/google-fonts.test.d.ts +2 -0
  106. package/dist/types/tests/google-fonts.test.d.ts.map +1 -0
  107. package/dist/types/tests/site-health-core-web-vitals.test.d.ts +2 -0
  108. package/dist/types/tests/site-health-core-web-vitals.test.d.ts.map +1 -0
  109. package/dist/types/tests/smartfetch.test.d.ts +2 -0
  110. package/dist/types/tests/smartfetch.test.d.ts.map +1 -0
  111. package/dist/types/tests/social-media-apis.test.d.ts +7 -0
  112. package/dist/types/tests/social-media-apis.test.d.ts.map +1 -0
  113. package/dist/types/tests/specialized-apis.test.d.ts +7 -0
  114. package/dist/types/tests/specialized-apis.test.d.ts.map +1 -0
  115. package/dist/types/tests/urlbuilder.test.d.ts +2 -0
  116. package/dist/types/tests/urlbuilder.test.d.ts.map +1 -0
  117. package/dist/types/tests/useFormSubmit.test.d.ts +2 -0
  118. package/dist/types/tests/useFormSubmit.test.d.ts.map +1 -0
  119. package/package.json +6 -6
  120. package/dist/components/sitebuilder/form/formemailer.js +0 -119
  121. package/dist/types/components/sitebuilder/form/formemailer.d.ts +0 -3
  122. package/dist/types/components/sitebuilder/form/formemailer.d.ts.map +0 -1
  123. package/dist/types/components/sitebuilder/form/formutils.d.ts.map +0 -1
  124. package/dist/types/stories/integrations/lipsum.stories.d.ts +0 -38
  125. package/dist/types/stories/integrations/lipsum.stories.d.ts.map +0 -1
  126. package/dist/types/stories/integrations/loremipsum.stories.d.ts +0 -46
  127. package/dist/types/stories/integrations/loremipsum.stories.d.ts.map +0 -1
  128. package/dist/types/tests/formemailer.honeypot.test.d.ts +0 -2
  129. package/dist/types/tests/formemailer.honeypot.test.d.ts.map +0 -1
  130. /package/dist/components/sitebuilder/form/{formutils.js → formengineutilities.js} +0 -0
@@ -1,4 +1,6 @@
1
1
  import PropTypes from "prop-types";
2
+ import { smartFetch } from '../general/smartfetch';
3
+ import { buildUrl } from '../general/urlbuilder';
2
4
  const debug = false;
3
5
  const ctfQSParams = "?fm=webp&q=50";
4
6
  /* ========== CALL CONTENTFUL DELIVERY API ========== */
@@ -15,11 +17,7 @@ export async function callContentfulDeliveryAPI(props) {
15
17
  if (debug)
16
18
  console.log("Calling Contentful Delivery API:", props.full_url);
17
19
  try {
18
- const response = await fetch(props.full_url);
19
- if (!response.ok) {
20
- throw new Error(`Response status: ${response.status}`);
21
- }
22
- const json = await response.json();
20
+ const json = await smartFetch(props.full_url);
23
21
  return json;
24
22
  }
25
23
  catch (error) {
@@ -60,11 +58,11 @@ getContentfulEntries.propTypes = {
60
58
  };
61
59
  export async function getContentfulEntries(props) {
62
60
  const { base_url, space_id, environment, delivery_access_token } = props.apiProps;
63
- // const full_url = base_url + "/spaces/" + space_id + "/environments/" + environment + "/content_types/" + contentType + "?access_token=" + access_token ;
64
- const full_url = base_url +
65
- "/spaces/" + space_id +
66
- "/environments/" + environment +
67
- "/entries?access_token=" + delivery_access_token;
61
+ const full_url = buildUrl({
62
+ baseUrl: base_url,
63
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries'],
64
+ params: { access_token: delivery_access_token }
65
+ });
68
66
  return await callContentfulDeliveryAPI({ full_url });
69
67
  }
70
68
  /*
@@ -124,11 +122,14 @@ getContentfulContentType.propTypes = {
124
122
  };
125
123
  export async function getContentfulContentType(props) {
126
124
  const { base_url, space_id, environment, access_token } = props.apiProps;
127
- const full_url = base_url +
128
- "/spaces/" + space_id +
129
- "/environments/" + environment +
130
- "/content_types/" + props.contentType +
131
- "?access_token=" + access_token;
125
+ if (!base_url || !space_id || !environment) {
126
+ throw new Error('Contentful API properties not configured: base_url, space_id, or environment');
127
+ }
128
+ const full_url = buildUrl({
129
+ baseUrl: base_url,
130
+ pathSegments: ['spaces', space_id, 'environments', environment, 'content_types', props.contentType],
131
+ params: { access_token }
132
+ });
132
133
  return await callContentfulDeliveryAPI({ full_url });
133
134
  }
134
135
  /* ========== GET CONTENTFUL ENTRY BY ENTRY ID ========== */
@@ -152,11 +153,14 @@ getContentfulEntryByEntryID.propTypes = {
152
153
  };
153
154
  export async function getContentfulEntryByEntryID(props) {
154
155
  const { base_url, space_id, environment, delivery_access_token } = props.apiProps;
155
- const full_url = base_url +
156
- "/spaces/" + space_id +
157
- "/environments/" + environment +
158
- "/entries/" + props.entry_id +
159
- "?access_token=" + delivery_access_token;
156
+ if (!base_url || !space_id || !environment) {
157
+ throw new Error('Contentful API properties not configured: base_url, space_id, or environment');
158
+ }
159
+ const full_url = buildUrl({
160
+ baseUrl: base_url,
161
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', props.entry_id],
162
+ params: { access_token: delivery_access_token }
163
+ });
160
164
  return await callContentfulDeliveryAPI({ full_url });
161
165
  }
162
166
  /* ========== GET CONTENTFUL CARD BY FIELD ========== */
@@ -3,22 +3,27 @@
3
3
  *
4
4
  * Provides reusable CRUD operations for any Contentful content type
5
5
  */
6
+ import { smartFetch } from '../general/smartfetch';
7
+ import { buildUrl } from '../general/urlbuilder';
6
8
  /**
7
9
  * List all entries of a specific content type
8
10
  */
9
11
  export async function listEntries(contentType, config) {
10
- const { space_id, delivery_access_token, environment = 'master' } = config;
12
+ const { space_id, management_access_token, environment = 'master' } = config;
11
13
  try {
12
- const response = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries?content_type=${contentType}`, {
13
- headers: {
14
- 'Authorization': `Bearer ${delivery_access_token}`,
15
- 'Content-Type': 'application/json',
16
- },
14
+ const url = buildUrl({
15
+ baseUrl: 'https://api.contentful.com',
16
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries'],
17
+ params: { content_type: contentType }
18
+ });
19
+ const data = await smartFetch(url, {
20
+ requestInit: {
21
+ headers: {
22
+ 'Authorization': `Bearer ${management_access_token}`,
23
+ 'Content-Type': 'application/json',
24
+ },
25
+ }
17
26
  });
18
- if (!response.ok) {
19
- throw new Error(`Contentful API error: ${response.status}`);
20
- }
21
- const data = await response.json();
22
27
  const entries = data.items || [];
23
28
  return {
24
29
  success: true,
@@ -37,30 +42,32 @@ export async function listEntries(contentType, config) {
37
42
  * Get a single entry by ID
38
43
  */
39
44
  export async function getEntryById(entryId, config) {
40
- const { space_id, delivery_access_token, environment = 'master' } = config;
45
+ const { space_id, management_access_token, environment = 'master' } = config;
41
46
  try {
42
- const response = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}`, {
43
- headers: {
44
- 'Authorization': `Bearer ${delivery_access_token}`,
45
- 'Content-Type': 'application/json',
46
- },
47
+ const url = buildUrl({
48
+ baseUrl: 'https://api.contentful.com',
49
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', entryId]
47
50
  });
48
- if (!response.ok) {
49
- if (response.status === 404) {
50
- return {
51
- success: false,
52
- message: 'Entry not found.',
53
- };
51
+ const entry = await smartFetch(url, {
52
+ requestInit: {
53
+ headers: {
54
+ 'Authorization': `Bearer ${management_access_token}`,
55
+ 'Content-Type': 'application/json',
56
+ },
54
57
  }
55
- throw new Error(`Contentful API error: ${response.status}`);
56
- }
57
- const entry = await response.json();
58
+ });
58
59
  return {
59
60
  success: true,
60
61
  entry,
61
62
  };
62
63
  }
63
64
  catch (error) {
65
+ if (error.status === 404) {
66
+ return {
67
+ success: false,
68
+ message: 'Entry not found.',
69
+ };
70
+ }
64
71
  return {
65
72
  success: false,
66
73
  message: `Failed to get entry: ${error}`,
@@ -71,22 +78,25 @@ export async function getEntryById(entryId, config) {
71
78
  * Search for entries by field value
72
79
  */
73
80
  export async function searchEntriesByField(contentType, fieldName, fieldValue, config) {
74
- const { space_id, delivery_access_token, environment = 'master' } = config;
81
+ const { space_id, management_access_token, environment = 'master' } = config;
75
82
  try {
76
- const response = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries?content_type=${contentType}&fields.${fieldName}=${encodeURIComponent(fieldValue)}`, {
77
- headers: {
78
- 'Authorization': `Bearer ${delivery_access_token}`,
79
- 'Content-Type': 'application/json',
80
- },
83
+ const url = buildUrl({
84
+ baseUrl: 'https://api.contentful.com',
85
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries'],
86
+ params: { content_type: contentType, [`fields.${fieldName}`]: fieldValue }
81
87
  });
82
- if (!response.ok) {
83
- throw new Error(`Contentful API error: ${response.status}`);
84
- }
85
- const data = await response.json();
86
- const entries = data.items || [];
88
+ const entries = await smartFetch(url, {
89
+ requestInit: {
90
+ headers: {
91
+ 'Authorization': `Bearer ${management_access_token}`,
92
+ 'Content-Type': 'application/json',
93
+ },
94
+ }
95
+ });
96
+ const items = entries.items || [];
87
97
  return {
88
98
  success: true,
89
- entries,
99
+ entries: items,
90
100
  };
91
101
  }
92
102
  catch (error) {
@@ -101,43 +111,50 @@ export async function searchEntriesByField(contentType, fieldName, fieldValue, c
101
111
  * Create a new entry
102
112
  */
103
113
  export async function createEntry(contentType, fields, config, autoPublish = true) {
104
- const { space_id, delivery_access_token, environment = 'master' } = config;
114
+ const { space_id, management_access_token, environment = 'master' } = config;
105
115
  try {
106
116
  // Convert fields to Contentful format (with 'en-US' locale)
107
117
  const contentfulFields = {};
108
118
  for (const [key, value] of Object.entries(fields)) {
109
119
  contentfulFields[key] = { 'en-US': value };
110
120
  }
111
- const createResponse = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries`, {
112
- method: 'POST',
113
- headers: {
114
- 'Authorization': `Bearer ${delivery_access_token}`,
115
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
116
- 'X-Contentful-Content-Type': contentType,
117
- },
118
- body: JSON.stringify({
119
- fields: contentfulFields,
120
- }),
121
+ const url = buildUrl({
122
+ baseUrl: 'https://api.contentful.com',
123
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries']
121
124
  });
122
- if (!createResponse.ok) {
123
- const error = await createResponse.json();
124
- throw new Error(`Create failed: ${JSON.stringify(error)}`);
125
- }
126
- const newEntry = await createResponse.json();
127
- // Publish if requested
128
- if (autoPublish) {
129
- await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${newEntry.sys.id}/published`, {
130
- method: 'PUT',
125
+ const data = await smartFetch(url, {
126
+ requestInit: {
127
+ method: 'POST',
131
128
  headers: {
132
- 'Authorization': `Bearer ${delivery_access_token}`,
133
- 'X-Contentful-Version': newEntry.sys.version.toString(),
129
+ 'Authorization': `Bearer ${management_access_token}`,
130
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
131
+ 'X-Contentful-Content-Type': contentType,
134
132
  },
133
+ body: JSON.stringify({
134
+ fields: contentfulFields,
135
+ }),
136
+ }
137
+ });
138
+ // Publish if requested
139
+ if (autoPublish) {
140
+ const publishUrl = buildUrl({
141
+ baseUrl: 'https://api.contentful.com',
142
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', data.sys.id, 'published']
143
+ });
144
+ await smartFetch(publishUrl, {
145
+ requestInit: {
146
+ method: 'PUT',
147
+ headers: {
148
+ 'Authorization': `Bearer ${management_access_token}`,
149
+ 'X-Contentful-Version': data.sys.version.toString(),
150
+ },
151
+ }
135
152
  });
136
153
  }
137
154
  return {
138
155
  success: true,
139
156
  message: 'Entry created successfully.',
140
- entryId: newEntry.sys.id,
157
+ entryId: data.sys.id,
141
158
  };
142
159
  }
143
160
  catch (error) {
@@ -151,7 +168,7 @@ export async function createEntry(contentType, fields, config, autoPublish = tru
151
168
  * Update an existing entry
152
169
  */
153
170
  export async function updateEntry(entryId, fields, config, autoPublish = true) {
154
- const { space_id, delivery_access_token, environment = 'master' } = config;
171
+ const { space_id, management_access_token, environment = 'master' } = config;
155
172
  try {
156
173
  // Get current entry to get version
157
174
  const getResponse = await getEntryById(entryId, config);
@@ -167,30 +184,35 @@ export async function updateEntry(entryId, fields, config, autoPublish = true) {
167
184
  for (const [key, value] of Object.entries(fields)) {
168
185
  contentfulFields[key] = { 'en-US': value };
169
186
  }
170
- const updateResponse = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}`, {
171
- method: 'PUT',
172
- headers: {
173
- 'Authorization': `Bearer ${delivery_access_token}`,
174
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
175
- 'X-Contentful-Version': currentEntry.sys.version.toString(),
176
- },
177
- body: JSON.stringify({
178
- fields: contentfulFields,
179
- }),
180
- });
181
- if (!updateResponse.ok) {
182
- const error = await updateResponse.json();
183
- throw new Error(`Update failed: ${JSON.stringify(error)}`);
184
- }
185
- const updatedEntry = await updateResponse.json();
186
- // Publish if requested
187
- if (autoPublish) {
188
- await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}/published`, {
187
+ const updatedEntry = await smartFetch(buildUrl({
188
+ baseUrl: 'https://api.contentful.com',
189
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', entryId],
190
+ }), {
191
+ requestInit: {
189
192
  method: 'PUT',
190
193
  headers: {
191
- 'Authorization': `Bearer ${delivery_access_token}`,
192
- 'X-Contentful-Version': updatedEntry.sys.version.toString(),
194
+ 'Authorization': `Bearer ${management_access_token}`,
195
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
196
+ 'X-Contentful-Version': currentEntry.sys.version.toString(),
193
197
  },
198
+ body: JSON.stringify({
199
+ fields: contentfulFields,
200
+ }),
201
+ }
202
+ });
203
+ // Publish if requested
204
+ if (autoPublish) {
205
+ await smartFetch(buildUrl({
206
+ baseUrl: 'https://api.contentful.com',
207
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', entryId, 'published'],
208
+ }), {
209
+ requestInit: {
210
+ method: 'PUT',
211
+ headers: {
212
+ 'Authorization': `Bearer ${management_access_token}`,
213
+ 'X-Contentful-Version': updatedEntry.sys.version.toString(),
214
+ },
215
+ }
194
216
  });
195
217
  }
196
218
  return {
@@ -210,7 +232,7 @@ export async function updateEntry(entryId, fields, config, autoPublish = true) {
210
232
  * Delete an entry (unpublish first, then delete)
211
233
  */
212
234
  export async function deleteEntry(entryId, config) {
213
- const { space_id, delivery_access_token, environment = 'master' } = config;
235
+ const { space_id, management_access_token, environment = 'master' } = config;
214
236
  try {
215
237
  // Get current entry to get version
216
238
  const getResponse = await getEntryById(entryId, config);
@@ -222,24 +244,31 @@ export async function deleteEntry(entryId, config) {
222
244
  }
223
245
  const entry = getResponse.entry;
224
246
  // Unpublish first
225
- await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entry.sys.id}/published`, {
226
- method: 'PUT',
227
- headers: {
228
- 'Authorization': `Bearer ${delivery_access_token}`,
229
- 'X-Contentful-Version': entry.sys.version.toString(),
230
- },
247
+ await smartFetch(buildUrl({
248
+ baseUrl: 'https://api.contentful.com',
249
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', entry.sys.id, 'published'],
250
+ }), {
251
+ requestInit: {
252
+ method: 'PUT',
253
+ headers: {
254
+ 'Authorization': `Bearer ${management_access_token}`,
255
+ 'X-Contentful-Version': entry.sys.version.toString(),
256
+ },
257
+ }
231
258
  });
232
259
  // Delete the entry
233
- const deleteResponse = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}`, {
234
- method: 'DELETE',
235
- headers: {
236
- 'Authorization': `Bearer ${delivery_access_token}`,
237
- 'X-Contentful-Version': (entry.sys.version + 1).toString(),
238
- },
260
+ await smartFetch(buildUrl({
261
+ baseUrl: 'https://api.contentful.com',
262
+ pathSegments: ['spaces', space_id, 'environments', environment, 'entries', entryId],
263
+ }), {
264
+ requestInit: {
265
+ method: 'DELETE',
266
+ headers: {
267
+ 'Authorization': `Bearer ${management_access_token}`,
268
+ 'X-Contentful-Version': (entry.sys.version + 1).toString(),
269
+ },
270
+ }
239
271
  });
240
- if (!deleteResponse.ok) {
241
- throw new Error(`Delete failed: ${deleteResponse.status}`);
242
- }
243
272
  return {
244
273
  success: true,
245
274
  message: 'Entry deleted successfully.',
@@ -257,16 +286,18 @@ export async function deleteEntry(entryId, config) {
257
286
  */
258
287
  export async function validateContentfulCredentials(credentials) {
259
288
  try {
260
- const response = await fetch(`https://api.contentful.com/spaces/${credentials.spaceId}`, {
261
- method: 'GET',
262
- headers: {
263
- 'Authorization': `Bearer ${credentials.accessToken}`,
264
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
265
- },
289
+ await smartFetch(buildUrl({
290
+ baseUrl: 'https://api.contentful.com',
291
+ pathSegments: ['spaces', credentials.spaceId],
292
+ }), {
293
+ requestInit: {
294
+ method: 'GET',
295
+ headers: {
296
+ 'Authorization': `Bearer ${credentials.accessToken}`,
297
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
298
+ },
299
+ }
266
300
  });
267
- if (!response.ok) {
268
- return { valid: false, error: 'Failed to access space' };
269
- }
270
301
  return { valid: true };
271
302
  }
272
303
  catch (error) {
@@ -279,42 +310,46 @@ export async function validateContentfulCredentials(credentials) {
279
310
  export async function getContentTypes(credentials) {
280
311
  const { spaceId, accessToken } = credentials;
281
312
  // First get space info to find the default environment
282
- const spaceResponse = await fetch(`https://api.contentful.com/spaces/${spaceId}`, {
283
- method: 'GET',
284
- headers: {
285
- 'Authorization': `Bearer ${accessToken}`,
286
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
287
- },
313
+ await smartFetch(buildUrl({
314
+ baseUrl: 'https://api.contentful.com',
315
+ pathSegments: ['spaces', spaceId],
316
+ }), {
317
+ requestInit: {
318
+ method: 'GET',
319
+ headers: {
320
+ 'Authorization': `Bearer ${accessToken}`,
321
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
322
+ },
323
+ }
288
324
  });
289
- if (!spaceResponse.ok) {
290
- throw new Error('Failed to access space');
291
- }
292
325
  // Try different environment names - Contentful uses 'master' for older spaces, 'main' for newer ones
293
326
  const environmentsToTry = ['master', 'main'];
294
- let contentTypesResponse = null;
327
+ let contentTypesData = null;
295
328
  let lastError = null;
296
329
  for (const env of environmentsToTry) {
297
330
  try {
298
- const response = await fetch(`https://api.contentful.com/spaces/${spaceId}/environments/${env}/content_types`, {
299
- method: 'GET',
300
- headers: {
301
- 'Authorization': `Bearer ${accessToken}`,
302
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
303
- },
331
+ const data = await smartFetch(buildUrl({
332
+ baseUrl: 'https://api.contentful.com',
333
+ pathSegments: ['spaces', spaceId, 'environments', env, 'content_types'],
334
+ }), {
335
+ requestInit: {
336
+ method: 'GET',
337
+ headers: {
338
+ 'Authorization': `Bearer ${accessToken}`,
339
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
340
+ },
341
+ }
304
342
  });
305
- if (response.ok) {
306
- contentTypesResponse = response;
307
- break;
308
- }
343
+ contentTypesData = data;
344
+ break;
309
345
  }
310
346
  catch (error) {
311
347
  lastError = error;
312
348
  }
313
349
  }
314
- if (!contentTypesResponse) {
350
+ if (!contentTypesData) {
315
351
  throw new Error(`Failed to fetch content types: ${lastError}`);
316
352
  }
317
- const contentTypesData = await contentTypesResponse.json();
318
353
  return contentTypesData.items || [];
319
354
  }
320
355
  /**
@@ -324,32 +359,34 @@ export async function migrateContentType(sourceCredentials, destCredentials, con
324
359
  try {
325
360
  // Get content type from source
326
361
  const sourceEnv = sourceCredentials.environment || 'master';
327
- const sourceResponse = await fetch(`https://api.contentful.com/spaces/${sourceCredentials.spaceId}/environments/${sourceEnv}/content_types/${contentTypeId}`, {
328
- method: 'GET',
329
- headers: {
330
- 'Authorization': `Bearer ${sourceCredentials.accessToken}`,
331
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
332
- },
362
+ const contentType = await smartFetch(buildUrl({
363
+ baseUrl: 'https://api.contentful.com',
364
+ pathSegments: ['spaces', sourceCredentials.spaceId, 'environments', sourceEnv, 'content_types', contentTypeId],
365
+ }), {
366
+ requestInit: {
367
+ method: 'GET',
368
+ headers: {
369
+ 'Authorization': `Bearer ${sourceCredentials.accessToken}`,
370
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
371
+ },
372
+ }
333
373
  });
334
- if (!sourceResponse.ok) {
335
- throw new Error('Failed to fetch content type from source');
336
- }
337
- const contentType = await sourceResponse.json();
338
374
  // Create content type in destination
339
375
  const destEnv = destCredentials.environment || 'master';
340
- const createResponse = await fetch(`https://api.contentful.com/spaces/${destCredentials.spaceId}/environments/${destEnv}/content_types`, {
341
- method: 'POST',
342
- headers: {
343
- 'Authorization': `Bearer ${destCredentials.accessToken}`,
344
- 'Content-Type': 'application/vnd.contentful.management.v1+json',
345
- 'X-Contentful-Version': '1',
346
- },
347
- body: JSON.stringify(contentType),
376
+ await smartFetch(buildUrl({
377
+ baseUrl: 'https://api.contentful.com',
378
+ pathSegments: ['spaces', destCredentials.spaceId, 'environments', destEnv, 'content_types'],
379
+ }), {
380
+ requestInit: {
381
+ method: 'POST',
382
+ headers: {
383
+ 'Authorization': `Bearer ${destCredentials.accessToken}`,
384
+ 'Content-Type': 'application/vnd.contentful.management.v1+json',
385
+ 'X-Contentful-Version': '1',
386
+ },
387
+ body: JSON.stringify(contentType),
388
+ }
348
389
  });
349
- if (!createResponse.ok) {
350
- const errorData = await createResponse.json();
351
- throw new Error(`Failed to create content type: ${errorData.message}`);
352
- }
353
390
  return { success: true };
354
391
  }
355
392
  catch (error) {
@@ -3,6 +3,8 @@ import { mergeDeep } from '../general/utilities';
3
3
  import { hashCode } from '../general/utilities';
4
4
  import { CacheManager } from '../general/cache-manager';
5
5
  import { getDomain } from '../general/utilities';
6
+ import { smartFetch } from '../general/smartfetch';
7
+ import { buildUrl } from '../general/urlbuilder';
6
8
  // Flickr API base URL - non-secret configuration
7
9
  const FLICKR_API_BASE_URL = 'https://api.flickr.com/services/rest/?';
8
10
  const defaultFlickr = {
@@ -25,13 +27,11 @@ const defaultFlickr = {
25
27
  };
26
28
  // Utility to build the final Flickr API URL, using proxy if available
27
29
  function buildFlickrApiUrl(flickr) {
28
- let baseUrl = flickr.baseURL;
29
- let queryParams = '';
30
- Object.keys(flickr.urlProps).forEach((prop) => {
31
- const value = flickr.urlProps[prop];
32
- queryParams += (queryParams.length === 0) ? prop + '=' + value : '&' + prop + '=' + value;
30
+ // Use buildUrl to construct the Flickr REST API URL from parameters
31
+ const apiUrl = buildUrl({
32
+ baseUrl: flickr.baseURL,
33
+ params: flickr.urlProps,
33
34
  });
34
- const apiUrl = baseUrl + queryParams;
35
35
  // Prefer flickr.proxyURL, then globalConfig.proxyUrl, else direct
36
36
  if (flickr.proxyURL) {
37
37
  return flickr.proxyURL + encodeURIComponent(apiUrl);
@@ -99,18 +99,16 @@ export function GetFlickrData(props) {
99
99
  });
100
100
  const fetchFlickrData = async () => {
101
101
  const cacheKey = hashCode(myURL);
102
- let cached = flickrCache.get(cacheKey);
103
- if (cached) {
104
- if (debug)
105
- console.log('Flickr cache hit:', cacheKey);
106
- return cached;
107
- }
108
102
  try {
109
- const response = await fetch(myURL);
110
- if (!response.ok) {
111
- throw new Error(`HTTP error! Status: ${response.status}`);
103
+ const jsonData = await smartFetch(myURL, {
104
+ cache: flickrCache,
105
+ cacheKey,
106
+ debug,
107
+ });
108
+ // Check if Flickr API returned an error response
109
+ if (jsonData.stat === 'fail') {
110
+ throw new Error(`Flickr API error: ${jsonData.message || 'Unknown error'}`);
112
111
  }
113
- const jsonData = await response.json();
114
112
  let myFlickrImages = [];
115
113
  if (jsonData.photos) {
116
114
  // photos for tags - flickr.photos.search
@@ -121,12 +119,11 @@ export function GetFlickrData(props) {
121
119
  myFlickrImages = jsonData.photoset.photo;
122
120
  }
123
121
  else {
124
- console.log('Error fetching Flickr images');
122
+ throw new Error('No photos or photoset found in Flickr API response');
125
123
  }
126
124
  myFlickrImages.sort((a, b) => {
127
125
  return new Date(b.datetaken).getTime() - new Date(a.datetaken).getTime();
128
126
  }); // b - a for reverse sort
129
- flickrCache.set(cacheKey, myFlickrImages);
130
127
  if (debug)
131
128
  console.log('Flickr Cards:', myFlickrImages);
132
129
  return myFlickrImages;
@@ -134,10 +131,6 @@ export function GetFlickrData(props) {
134
131
  catch (err) {
135
132
  console.log('Error fetching Flickr data:', err);
136
133
  }
137
- finally {
138
- if (debug)
139
- console.log('Flickr data fetch completed');
140
- }
141
134
  };
142
135
  return fetchFlickrData();
143
136
  }