@automattic/jetpack-ai-client 0.8.2 → 0.9.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/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ 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.9.0] - 2024-03-12
9
+ ### Changed
10
+ - Fix typescript errors [#35904]
11
+ - Updated package dependencies. [#36325]
12
+
13
+ ### Fixed
14
+ - AI Client: Fix audio recording where WebM is not supported (iOS for example). [#36160]
15
+
8
16
  ## [0.8.2] - 2024-03-04
9
17
  ### Added
10
18
  - AI Client: add audio validation hook. [#36043]
@@ -247,6 +255,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
247
255
  - Updated package dependencies. [#31659]
248
256
  - Updated package dependencies. [#31785]
249
257
 
258
+ [0.9.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.8.2...v0.9.0
250
259
  [0.8.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.8.1...v0.8.2
251
260
  [0.8.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.8.0...v0.8.1
252
261
  [0.8.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.7.0...v0.8.0
@@ -2,6 +2,5 @@
2
2
  * External dependencies
3
3
  */
4
4
  import apiFetchMod from '@wordpress/api-fetch';
5
- type ApiFetchType = typeof apiFetchMod.default;
6
- declare const apiFetch: ApiFetchType;
7
- export default apiFetch;
5
+ declare const _default: typeof apiFetchMod.default;
6
+ export default _default;
@@ -2,5 +2,9 @@
2
2
  * External dependencies
3
3
  */
4
4
  import apiFetchMod from '@wordpress/api-fetch';
5
- const apiFetch = (apiFetchMod.default ?? apiFetchMod);
5
+ // @wordpress/api-fetch (as of 6.47.0) declares itself in such a way that tsc and node see the function at apiFetchMod.default
6
+ // while some other environments (including code running inside WordPress itself) see it at apiFetch.
7
+ // See https://arethetypeswrong.github.io/?p=@wordpress/api-fetch@6.47.0
8
+ // This is a helper to simplify the usage of the api-fetch module on the ai-client package.
9
+ const apiFetch = 'default' in apiFetchMod ? apiFetchMod.default : apiFetchMod;
6
10
  export default apiFetch;
@@ -35,6 +35,6 @@ type AiControlProps = {
35
35
  * @param {React.MutableRefObject} ref - Ref to the component.
36
36
  * @returns {ReactElement} Rendered component.
37
37
  */
38
- export declare function AIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, bannerComponent, errorComponent, }: AiControlProps, ref: React.MutableRefObject<null>): ReactElement;
39
- declare const _default: React.ForwardRefExoticComponent<AiControlProps & React.RefAttributes<null>>;
38
+ export declare function AIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, bannerComponent, errorComponent, }: AiControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
39
+ declare const _default: React.ForwardRefExoticComponent<AiControlProps & React.RefAttributes<HTMLInputElement>>;
40
40
  export default _default;
@@ -2,6 +2,12 @@
2
2
  * External dependencies
3
3
  */
4
4
  import { useRef, useState, useEffect, useCallback } from '@wordpress/element';
5
+ /**
6
+ * Media types
7
+ */
8
+ const MEDIA_TYPE_MP4_MP4A = 'audio/mp4;codecs=mp4a';
9
+ const MEDIA_TYPE_MP4 = 'audio/mp4';
10
+ const MEDIA_TYPE_WEBM = 'audio/webm';
5
11
  /**
6
12
  * react custom hook to handle media recording.
7
13
  *
@@ -32,9 +38,10 @@ export default function useMediaRecording({ onDone, } = {}) {
32
38
  * @returns {Blob} The recorded blob
33
39
  */
34
40
  function getBlob() {
35
- return new Blob(recordedChunks, {
36
- type: 'audio/webm',
37
- });
41
+ if (MediaRecorder.isTypeSupported(MEDIA_TYPE_MP4_MP4A)) {
42
+ return new Blob(recordedChunks, { type: MEDIA_TYPE_MP4 }); // omit the codecs parameter
43
+ }
44
+ return new Blob(recordedChunks, { type: MEDIA_TYPE_WEBM });
38
45
  }
39
46
  // `start` recording handler
40
47
  const start = useCallback((timeslice) => {
@@ -115,7 +122,15 @@ export default function useMediaRecording({ onDone, } = {}) {
115
122
  audioStream.current = stream;
116
123
  const source = audioCtx.createMediaStreamSource(stream);
117
124
  source.connect(analyser.current);
118
- mediaRecordRef.current = new MediaRecorder(stream);
125
+ /**
126
+ * Special handling for iOS devices.
127
+ */
128
+ if (MediaRecorder.isTypeSupported(MEDIA_TYPE_MP4_MP4A)) {
129
+ mediaRecordRef.current = new MediaRecorder(stream, { mimeType: MEDIA_TYPE_MP4_MP4A });
130
+ }
131
+ else {
132
+ mediaRecordRef.current = new MediaRecorder(stream, { mimeType: MEDIA_TYPE_WEBM });
133
+ }
119
134
  mediaRecordRef.current.addEventListener('start', onStartListener);
120
135
  mediaRecordRef.current.addEventListener('stop', onStopListener);
121
136
  mediaRecordRef.current.addEventListener('pause', onPauseListener);
package/build/types.d.ts CHANGED
@@ -29,15 +29,3 @@ export type CancelablePromise<T = void> = Promise<T> & {
29
29
  canceled?: boolean;
30
30
  };
31
31
  export type TranscriptionState = RecordingState | 'validating' | 'processing' | 'error';
32
- interface JPConnectionInitialState {
33
- apiNonce: string;
34
- siteSuffix: string;
35
- connectionStatus: {
36
- isActive: boolean;
37
- };
38
- }
39
- declare global {
40
- interface Window {
41
- JP_CONNECTION_INITIAL_STATE: JPConnectionInitialState;
42
- }
43
- }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.8.2",
4
+ "version": "0.9.0",
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",
7
7
  "bugs": {
@@ -38,19 +38,19 @@
38
38
  "main": "./build/index.js",
39
39
  "types": "./build/index.d.ts",
40
40
  "dependencies": {
41
- "@automattic/jetpack-base-styles": "^0.6.18",
42
- "@automattic/jetpack-connection": "^0.33.1",
43
- "@automattic/jetpack-shared-extension-utils": "^0.14.5",
41
+ "@automattic/jetpack-base-styles": "^0.6.19",
42
+ "@automattic/jetpack-connection": "^0.33.3",
43
+ "@automattic/jetpack-shared-extension-utils": "^0.14.7",
44
44
  "@microsoft/fetch-event-source": "2.0.1",
45
45
  "@types/react": "18.2.61",
46
- "@wordpress/api-fetch": "6.49.0",
47
- "@wordpress/block-editor": "12.20.0",
48
- "@wordpress/components": "27.0.0",
49
- "@wordpress/compose": "6.29.0",
50
- "@wordpress/data": "9.22.0",
51
- "@wordpress/element": "5.29.0",
52
- "@wordpress/i18n": "4.52.0",
53
- "@wordpress/icons": "9.43.0",
46
+ "@wordpress/api-fetch": "6.50.0",
47
+ "@wordpress/block-editor": "12.21.0",
48
+ "@wordpress/components": "27.1.0",
49
+ "@wordpress/compose": "6.30.0",
50
+ "@wordpress/data": "9.23.0",
51
+ "@wordpress/element": "5.30.0",
52
+ "@wordpress/i18n": "4.53.0",
53
+ "@wordpress/icons": "9.44.0",
54
54
  "classnames": "2.3.2",
55
55
  "debug": "4.3.4",
56
56
  "react": "18.2.0",
@@ -7,7 +7,8 @@ import apiFetchMod from '@wordpress/api-fetch';
7
7
  // while some other environments (including code running inside WordPress itself) see it at apiFetch.
8
8
  // See https://arethetypeswrong.github.io/?p=@wordpress/api-fetch@6.47.0
9
9
  // This is a helper to simplify the usage of the api-fetch module on the ai-client package.
10
- type ApiFetchType = typeof apiFetchMod.default;
11
- const apiFetch: ApiFetchType = ( apiFetchMod.default ?? apiFetchMod ) as ApiFetchType;
10
+ const apiFetch = 'default' in apiFetchMod ? apiFetchMod.default : apiFetchMod;
11
+ // eslint-disable-next-line @typescript-eslint/ban-types
12
+ type ApiFetchType = typeof apiFetch extends Function ? typeof apiFetch : typeof apiFetchMod;
12
13
 
13
- export default apiFetch;
14
+ export default apiFetch as ApiFetchType;
@@ -73,7 +73,7 @@ export function AIControl(
73
73
  bannerComponent = null,
74
74
  errorComponent = null,
75
75
  }: AiControlProps,
76
- ref: React.MutableRefObject< null >
76
+ ref: React.MutableRefObject< HTMLInputElement >
77
77
  ): ReactElement {
78
78
  const promptUserInputRef = useRef( null );
79
79
  const loading = state === 'requesting' || state === 'suggesting';
@@ -10,6 +10,13 @@ type UseMediaRecordingProps = {
10
10
  onDone?: ( blob: Blob ) => void;
11
11
  };
12
12
 
13
+ /**
14
+ * Media types
15
+ */
16
+ const MEDIA_TYPE_MP4_MP4A = 'audio/mp4;codecs=mp4a';
17
+ const MEDIA_TYPE_MP4 = 'audio/mp4';
18
+ const MEDIA_TYPE_WEBM = 'audio/webm';
19
+
13
20
  type UseMediaRecordingReturn = {
14
21
  /**
15
22
  * The current recording state
@@ -114,9 +121,11 @@ export default function useMediaRecording( {
114
121
  * @returns {Blob} The recorded blob
115
122
  */
116
123
  function getBlob() {
117
- return new Blob( recordedChunks, {
118
- type: 'audio/webm',
119
- } );
124
+ if ( MediaRecorder.isTypeSupported( MEDIA_TYPE_MP4_MP4A ) ) {
125
+ return new Blob( recordedChunks, { type: MEDIA_TYPE_MP4 } ); // omit the codecs parameter
126
+ }
127
+
128
+ return new Blob( recordedChunks, { type: MEDIA_TYPE_WEBM } );
120
129
  }
121
130
 
122
131
  // `start` recording handler
@@ -217,7 +226,15 @@ export default function useMediaRecording( {
217
226
  const source = audioCtx.createMediaStreamSource( stream );
218
227
  source.connect( analyser.current );
219
228
 
220
- mediaRecordRef.current = new MediaRecorder( stream );
229
+ /**
230
+ * Special handling for iOS devices.
231
+ */
232
+ if ( MediaRecorder.isTypeSupported( MEDIA_TYPE_MP4_MP4A ) ) {
233
+ mediaRecordRef.current = new MediaRecorder( stream, { mimeType: MEDIA_TYPE_MP4_MP4A } );
234
+ } else {
235
+ mediaRecordRef.current = new MediaRecorder( stream, { mimeType: MEDIA_TYPE_WEBM } );
236
+ }
237
+
221
238
  mediaRecordRef.current.addEventListener( 'start', onStartListener );
222
239
  mediaRecordRef.current.addEventListener( 'stop', onStopListener );
223
240
  mediaRecordRef.current.addEventListener( 'pause', onPauseListener );
package/src/types.ts CHANGED
@@ -97,20 +97,3 @@ export type CancelablePromise< T = void > = Promise< T > & { canceled?: boolean
97
97
  * Transcription types
98
98
  */
99
99
  export type TranscriptionState = RecordingState | 'validating' | 'processing' | 'error';
100
-
101
- // Connection initial state
102
- // @todo: it should be provided by the connection package
103
- interface JPConnectionInitialState {
104
- apiNonce: string;
105
- siteSuffix: string;
106
- connectionStatus: {
107
- isActive: boolean;
108
- };
109
- }
110
-
111
- // Global
112
- declare global {
113
- interface Window {
114
- JP_CONNECTION_INITIAL_STATE: JPConnectionInitialState;
115
- }
116
- }