@simula/ads 1.1.0 → 1.2.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/dist/index.mjs CHANGED
@@ -50,14 +50,19 @@ const fetchAd = async (request) => {
50
50
  try {
51
51
  const conversationHistory = request.messages;
52
52
  // Normalize theme accent and font to arrays for backend
53
- const normalizedTheme = request.theme ? {
54
- ...request.theme,
55
- accent: request.theme.accent ? (Array.isArray(request.theme.accent) ? request.theme.accent : [request.theme.accent]) : undefined,
56
- font: request.theme.font ? (Array.isArray(request.theme.font) ? request.theme.font : [request.theme.font]) : undefined,
57
- } : undefined;
53
+ // Also handle backward compatibility: prefer 'mode' over 'theme', but support both
54
+ const normalizedTheme = request.theme ? (() => {
55
+ var _a;
56
+ const { theme: themeDeprecated, ...themeRest } = request.theme;
57
+ return {
58
+ ...themeRest,
59
+ mode: (_a = request.theme.mode) !== null && _a !== void 0 ? _a : themeDeprecated, // Prefer 'mode', fallback to 'theme' for backward compatibility
60
+ accent: request.theme.accent ? (Array.isArray(request.theme.accent) ? request.theme.accent : [request.theme.accent]) : undefined,
61
+ font: request.theme.font ? (Array.isArray(request.theme.font) ? request.theme.font : [request.theme.font]) : undefined,
62
+ };
63
+ })() : undefined;
58
64
  const requestBody = {
59
65
  messages: conversationHistory,
60
- types: request.formats,
61
66
  slot_id: request.slotId,
62
67
  theme: normalizedTheme,
63
68
  session_id: request.sessionId,
@@ -210,10 +215,6 @@ const validateInChatAdSlotProps = (props) => {
210
215
  throw new Error(`Invalid message at index ${i}: "content" must be a string`);
211
216
  }
212
217
  });
213
- // Validate formats (optional)
214
- if (props.formats !== undefined) {
215
- validateFormats(props.formats);
216
- }
217
218
  // Validate theme (optional)
218
219
  if (props.theme !== undefined) {
219
220
  validateTheme(props.theme);
@@ -244,50 +245,33 @@ const validateInChatAdSlotProps = (props) => {
244
245
  // Note: trigger validation (Promise check) is skipped because checking instanceof Promise
245
246
  // is unreliable across different Promise implementations and contexts
246
247
  };
247
- /**
248
- * Validates formats - accepts string or string[]
249
- * Throws descriptive errors for invalid formats
250
- */
251
- const validateFormats = (formats) => {
252
- if (!formats)
253
- return;
254
- const validFormatOptions = ['all', 'tips', 'interactive', 'suggestions', 'text', 'highlight', 'visual_banner', 'image_feature'];
255
- // Normalize to array for validation
256
- const formatsArray = Array.isArray(formats) ? formats : [formats];
257
- formatsArray.forEach((format, i) => {
258
- if (typeof format !== 'string') {
259
- throw new Error(`Invalid format type at index ${i}: "${typeof format}". Must be a string. Valid values: ${validFormatOptions.join(', ')}`);
260
- }
261
- if (!validFormatOptions.includes(format)) {
262
- throw new Error(`Invalid format value${Array.isArray(formats) ? ` at index ${i}` : ''}: "${format}". Valid values: ${validFormatOptions.join(', ')}`);
263
- }
264
- });
265
- };
266
248
  /**
267
249
  * Validates theme object
268
250
  * Throws descriptive errors for invalid theme properties
269
251
  */
270
252
  const validateTheme = (theme) => {
253
+ var _a;
271
254
  if (!theme || typeof theme !== 'object') {
272
255
  throw new Error('Invalid "theme": must be an object');
273
256
  }
274
- const validThemeOptions = ['light', 'dark', 'auto'];
257
+ const validModeOptions = ['light', 'dark', 'auto'];
275
258
  const validAccentOptions = ['blue', 'red', 'green', 'yellow', 'purple', 'pink', 'orange', 'neutral', 'gray', 'tan', 'transparent', 'image'];
276
259
  const validFontOptions = ['san-serif', 'serif', 'monospace'];
277
- const validKeys = ['theme', 'accent', 'font', 'width', 'cornerRadius'];
260
+ const validKeys = ['mode', 'theme', 'accent', 'font', 'width', 'cornerRadius']; // 'theme' kept for backward compatibility
278
261
  // Check for invalid top-level keys
279
262
  Object.keys(theme).forEach(key => {
280
263
  if (!validKeys.includes(key)) {
281
264
  throw new Error(`Invalid theme parameter "${key}". Valid parameters: ${validKeys.join(', ')}`);
282
265
  }
283
266
  });
284
- // Validate theme value
285
- if (theme.theme !== undefined) {
286
- if (typeof theme.theme !== 'string') {
287
- throw new Error(`Invalid theme type "${typeof theme.theme}". Must be a string. Valid values: ${validThemeOptions.join(', ')}`);
267
+ // Validate mode value (prefer 'mode' over 'theme' for backward compatibility)
268
+ const modeValue = (_a = theme.mode) !== null && _a !== void 0 ? _a : theme.theme;
269
+ if (modeValue !== undefined) {
270
+ if (typeof modeValue !== 'string') {
271
+ throw new Error(`Invalid mode/theme type "${typeof modeValue}". Must be a string. Valid values: ${validModeOptions.join(', ')}`);
288
272
  }
289
- if (!validThemeOptions.includes(theme.theme)) {
290
- throw new Error(`Invalid theme value "${theme.theme}". Valid values: ${validThemeOptions.join(', ')}`);
273
+ if (!validModeOptions.includes(modeValue)) {
274
+ throw new Error(`Invalid mode/theme value "${modeValue}". Valid values: ${validModeOptions.join(', ')}`);
291
275
  }
292
276
  }
293
277
  // Validate accent value(s)
@@ -1587,7 +1571,10 @@ const getFontStyles = (font = 'san-serif') => {
1587
1571
  };
1588
1572
 
1589
1573
  const createInChatAdSlotCSS = (theme = {}) => {
1590
- const { theme: themeMode = 'light', accent = 'blue', font = 'san-serif', width = 'auto', } = theme;
1574
+ var _a, _b;
1575
+ // Backward compatibility: prefer 'mode' over 'theme', but support both
1576
+ const themeMode = (_b = (_a = theme.mode) !== null && _a !== void 0 ? _a : theme.theme) !== null && _b !== void 0 ? _b : 'light';
1577
+ const { accent = 'blue', font = 'san-serif', width = 'auto', } = theme;
1591
1578
  // If accent or font is an array, use the first value for styling
1592
1579
  Array.isArray(accent) ? accent[0] : accent;
1593
1580
  const effectiveFont = Array.isArray(font) ? font[0] : font;
@@ -1742,9 +1729,8 @@ const hasValidMessages = (messages) => {
1742
1729
  const InChatAdSlot = (props) => {
1743
1730
  // Validate props early
1744
1731
  validateInChatAdSlotProps(props);
1745
- const { messages, trigger, formats: formatsRaw = ['all'], theme = {}, debounceMs = 0, charDesc, onImpression, onClick, onError, } = props;
1746
- // Normalize formats to array (similar to theme.accent and theme.font)
1747
- const formats = Array.isArray(formatsRaw) ? formatsRaw : [formatsRaw];
1732
+ const { messages, trigger, formats, // Deprecated: ignored for backward compatibility
1733
+ theme = {}, debounceMs = 0, charDesc, onImpression, onClick, onError, } = props;
1748
1734
  const { apiKey, sessionId } = useSimula();
1749
1735
  // Generate a stable slotId for this component instance
1750
1736
  const slotId = useMemo(() => `slot-${v4()}`, []);
@@ -1876,7 +1862,6 @@ const InChatAdSlot = (props) => {
1876
1862
  }
1877
1863
  const result = await fetchAd({
1878
1864
  messages,
1879
- formats,
1880
1865
  apiKey,
1881
1866
  slotId,
1882
1867
  theme: themeForBackend,
@@ -1907,7 +1892,7 @@ const InChatAdSlot = (props) => {
1907
1892
  finally {
1908
1893
  setLoading(false);
1909
1894
  }
1910
- }, [hasBeenViewed, loading, hasTriggered, error, messages, formats, apiKey, slotId, theme, onError, isBot, reasons, sessionId, measuredWidth]);
1895
+ }, [hasBeenViewed, loading, hasTriggered, error, messages, apiKey, slotId, theme, onError, isBot, reasons, sessionId, measuredWidth]);
1911
1896
  useDebounce(() => {
1912
1897
  if (shouldFetch) {
1913
1898
  fetchAdData();