@automattic/jetpack-ai-client 0.34.7 → 0.34.9

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/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.34.9] - 2026-03-30
9
+ ### Changed
10
+ - Update package dependencies. [#47799]
11
+
12
+ ## [0.34.8] - 2026-03-23
13
+ ### Security
14
+ - Fix markdown-to-HTML paragraph renderer. [#47637]
15
+
16
+ ### Changed
17
+ - Update package dependencies. [#47684] [#47719]
18
+
19
+ ### Fixed
20
+ - AI Assistant: Prevent modal shaking from when content streams in by correcting header margins and making the header sticky. [#47616]
21
+
8
22
  ## [0.34.7] - 2026-03-16
9
23
  ### Changed
10
24
  - Update dependencies. [#47472]
@@ -829,6 +843,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
829
843
  - AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
830
844
  - Updated package dependencies. [#31468] [#31659] [#31785]
831
845
 
846
+ [0.34.9]: https://github.com/Automattic/jetpack-ai-client/compare/v0.34.8...v0.34.9
847
+ [0.34.8]: https://github.com/Automattic/jetpack-ai-client/compare/v0.34.7...v0.34.8
832
848
  [0.34.7]: https://github.com/Automattic/jetpack-ai-client/compare/v0.34.6...v0.34.7
833
849
  [0.34.6]: https://github.com/Automattic/jetpack-ai-client/compare/v0.34.5...v0.34.6
834
850
  [0.34.5]: https://github.com/Automattic/jetpack-ai-client/compare/v0.34.4...v0.34.5
@@ -50,7 +50,7 @@ export default function useAiImage({ feature, type, cost, autoStart = true, prev
50
50
  });
51
51
  }, []);
52
52
  // the selec/useEffect combo...
53
- const loadedMedia = useSelect((select) => select('core')?.getEntityRecord?.('postType', 'attachment', previousMediaId), [previousMediaId]);
53
+ const loadedMedia = useSelect(select => select('core')?.getEntityRecord?.('postType', 'attachment', previousMediaId), [previousMediaId]);
54
54
  useEffect(() => {
55
55
  if (loadedMedia) {
56
56
  updateImages({
@@ -18,5 +18,5 @@ const ModalHeader = ({ requestingState, onClose, title, }) => {
18
18
  */
19
19
  export default function AiAssistantModal({ children, handleClose, hideHeader = true, requestingState = 'init', title = __('AI Assistant', 'jetpack-ai-client'), maxWidth = 720, }) {
20
20
  return (_jsx(Modal, { __experimentalHideHeader: hideHeader, className: "ai-assistant-modal", shouldCloseOnClickOutside: false, onRequestClose: handleClose, children: _jsxs("div", { className: "ai-assistant-modal__content", style: { maxWidth }, children: [
21
- _jsx(ModalHeader, { requestingState: requestingState, onClose: handleClose, title: title }), _jsx("hr", { className: "ai-assistant-modal__divider" }), children] }) }));
21
+ _jsx(ModalHeader, { requestingState: requestingState, onClose: handleClose, title: title }), children] }) }));
22
22
  }
@@ -40,8 +40,18 @@ export const fixes = {
40
40
  if (!extension) {
41
41
  return content;
42
42
  }
43
- // Fix encoding of <br /> tags
44
- return content.replaceAll(/\s*&lt;br \/&gt;\s*/g, '<br />');
43
+ // Fix encoding of <br /> tags and trim surrounding whitespace.
44
+ // Uses split/join instead of regex to avoid polynomial ReDoS on long whitespace runs.
45
+ return content
46
+ .split('&lt;br /&gt;')
47
+ .map((s, i, arr) => {
48
+ if (i < arr.length - 1)
49
+ s = s.trimEnd();
50
+ if (i > 0)
51
+ s = s.trimStart();
52
+ return s;
53
+ })
54
+ .join('<br />');
45
55
  },
46
56
  table: (content, extension = false, { hasFixedLayout = false }) => {
47
57
  if (!extension) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/jetpack-ai-client",
3
- "version": "0.34.7",
3
+ "version": "0.34.9",
4
4
  "private": false,
5
5
  "description": "A JS client for consuming Jetpack AI services",
6
6
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme",
@@ -32,30 +32,30 @@
32
32
  "watch": "tsgo --watch --pretty"
33
33
  },
34
34
  "dependencies": {
35
- "@automattic/jetpack-base-styles": "^1.0.19",
36
- "@automattic/jetpack-components": "^1.6.0",
37
- "@automattic/jetpack-connection": "^1.4.40",
35
+ "@automattic/jetpack-base-styles": "^1.0.20",
36
+ "@automattic/jetpack-components": "^1.7.0",
37
+ "@automattic/jetpack-connection": "^1.4.42",
38
38
  "@automattic/jetpack-explat": "workspace:*",
39
39
  "@automattic/jetpack-script-data": "^0.6.1",
40
- "@automattic/jetpack-shared-extension-utils": "^1.5.4",
40
+ "@automattic/jetpack-shared-extension-utils": "^1.5.6",
41
41
  "@microsoft/fetch-event-source": "2.0.1",
42
42
  "@types/jest": "30.0.0",
43
43
  "@types/react": "18.3.28",
44
- "@types/wordpress__block-editor": "15.0.3",
45
- "@wordpress/api-fetch": "7.41.0",
46
- "@wordpress/base-styles": "6.17.0",
47
- "@wordpress/blob": "4.41.0",
48
- "@wordpress/block-editor": "15.14.0",
49
- "@wordpress/blocks": "15.14.0",
50
- "@wordpress/components": "32.3.0",
51
- "@wordpress/compose": "7.41.0",
52
- "@wordpress/data": "10.41.0",
53
- "@wordpress/editor": "14.41.0",
54
- "@wordpress/element": "6.41.0",
55
- "@wordpress/i18n": "6.14.0",
56
- "@wordpress/icons": "11.8.0",
57
- "@wordpress/primitives": "4.41.0",
58
- "@wordpress/url": "4.41.0",
44
+ "@types/wordpress__block-editor": "15.0.5",
45
+ "@wordpress/api-fetch": "7.42.0",
46
+ "@wordpress/base-styles": "6.18.0",
47
+ "@wordpress/blob": "4.42.0",
48
+ "@wordpress/block-editor": "15.15.0",
49
+ "@wordpress/blocks": "15.15.0",
50
+ "@wordpress/components": "32.4.0",
51
+ "@wordpress/compose": "7.42.0",
52
+ "@wordpress/data": "10.42.0",
53
+ "@wordpress/editor": "14.42.0",
54
+ "@wordpress/element": "6.42.0",
55
+ "@wordpress/i18n": "6.15.0",
56
+ "@wordpress/icons": "12.0.0",
57
+ "@wordpress/primitives": "4.42.0",
58
+ "@wordpress/url": "4.42.0",
59
59
  "clsx": "2.1.1",
60
60
  "debug": "4.4.3",
61
61
  "markdown-it": "14.1.1",
@@ -64,13 +64,14 @@
64
64
  "turndown": "7.1.2"
65
65
  },
66
66
  "devDependencies": {
67
- "@storybook/addon-docs": "10.2.11",
68
- "@storybook/react": "10.2.11",
67
+ "@storybook/addon-docs": "10.3.1",
68
+ "@storybook/react": "10.3.1",
69
69
  "@testing-library/dom": "10.4.1",
70
70
  "@types/markdown-it": "14.1.2",
71
71
  "@types/turndown": "5.0.6",
72
72
  "@typescript/native-preview": "7.0.0-dev.20260225.1",
73
- "jest": "30.2.0",
74
- "storybook": "10.2.11"
73
+ "jest": "30.3.0",
74
+ "storybook": "10.3.1",
75
+ "typescript": "5.9.3"
75
76
  }
76
77
  }
@@ -119,8 +119,12 @@ export default function useAiImage( {
119
119
 
120
120
  // the selec/useEffect combo...
121
121
  const loadedMedia = useSelect(
122
- ( select: ( store ) => CoreSelectors ) =>
123
- select( 'core' )?.getEntityRecord?.( 'postType', 'attachment', previousMediaId ),
122
+ select =>
123
+ ( select( 'core' ) as CoreSelectors )?.getEntityRecord?.(
124
+ 'postType',
125
+ 'attachment',
126
+ previousMediaId
127
+ ),
124
128
  [ previousMediaId ]
125
129
  );
126
130
  useEffect( () => {
@@ -57,7 +57,6 @@ export default function AiAssistantModal( {
57
57
  >
58
58
  <div className="ai-assistant-modal__content" style={ { maxWidth } }>
59
59
  <ModalHeader requestingState={ requestingState } onClose={ handleClose } title={ title } />
60
- <hr className="ai-assistant-modal__divider" />
61
60
  { children }
62
61
  </div>
63
62
  </Modal>
@@ -16,16 +16,14 @@
16
16
  &__header {
17
17
  display: flex;
18
18
  justify-content: space-between;
19
- margin-right: -32px;
20
- margin-left: -32px;
21
- margin-top: -32px;
19
+ margin-right: -24px;
20
+ margin-left: -24px;
21
+ margin-top: -24px;
22
22
  padding: 8px 12px;
23
- }
24
-
25
- &__divider {
26
- background: #dcdcde;
27
- margin: 0 -32px;
28
- height: 1px;
23
+ position: sticky;
24
+ top: -24px;
25
+ background: #fff;
26
+ border-bottom: 1px solid #dcdcde;
29
27
  }
30
28
 
31
29
  &__title-wrapper {
@@ -62,8 +62,16 @@ export const fixes: Fixes = {
62
62
  return content;
63
63
  }
64
64
 
65
- // Fix encoding of <br /> tags
66
- return content.replaceAll( /\s*&lt;br \/&gt;\s*/g, '<br />' );
65
+ // Fix encoding of <br /> tags and trim surrounding whitespace.
66
+ // Uses split/join instead of regex to avoid polynomial ReDoS on long whitespace runs.
67
+ return content
68
+ .split( '&lt;br /&gt;' )
69
+ .map( ( s, i, arr ) => {
70
+ if ( i < arr.length - 1 ) s = s.trimEnd();
71
+ if ( i > 0 ) s = s.trimStart();
72
+ return s;
73
+ } )
74
+ .join( '<br />' );
67
75
  },
68
76
  table: ( content: string, extension = false, { hasFixedLayout = false } ) => {
69
77
  if ( ! extension ) {
@@ -88,7 +88,7 @@
88
88
  color: var(--studio-gray-50, #646970);
89
89
  }
90
90
 
91
- &[data-placeholder]:empty:focus::before:not([contentEditable="false"]) {
91
+ &[data-placeholder]:empty:focus:not([contentEditable="false"])::before {
92
92
  content: "";
93
93
  }
94
94
  }