From 3df7c2a561a20d71342d2c3d6f42eb901568da3a Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Fri, 5 Jun 2026 19:46:01 +0200 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74984=20[jqu?= =?UTF-8?q?ery]=20Fix=20module=20import=20error=20in=20jquery=204.0.0=20by?= =?UTF-8?q?=20@TomiBelan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/jquery/index.d.mts | 3 ++- types/jquery/slim.d.mts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/types/jquery/index.d.mts b/types/jquery/index.d.mts index 34c92eab4027ec..e1166df032ffbe 100644 --- a/types/jquery/index.d.mts +++ b/types/jquery/index.d.mts @@ -1,4 +1,5 @@ /// +export const jQuery: JQueryStatic; +export const $: JQueryStatic; export default jQuery; -export { jQuery, jQuery as $ }; diff --git a/types/jquery/slim.d.mts b/types/jquery/slim.d.mts index 34c92eab4027ec..e1166df032ffbe 100644 --- a/types/jquery/slim.d.mts +++ b/types/jquery/slim.d.mts @@ -1,4 +1,5 @@ /// +export const jQuery: JQueryStatic; +export const $: JQueryStatic; export default jQuery; -export { jQuery, jQuery as $ }; From b93056bfd33d1b21df07e23327211b23b9e16e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yamanqui=20Garc=C3=ADa=20Rosales?= Date: Fri, 5 Jun 2026 11:12:51 -0700 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74905=20[goo?= =?UTF-8?q?gle-apps-script]=20Added=20`ColorStyle`=20type=20by=20@Yamanqui?= =?UTF-8?q?Chacala?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yamanqui García Rosales --- types/google-apps-script/apis/sheets_v4.d.ts | 29 +++++++++++++++++ .../test/google-apps-script-tests.ts | 32 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/types/google-apps-script/apis/sheets_v4.d.ts b/types/google-apps-script/apis/sheets_v4.d.ts index 794b7fc5d39eca..fd63eb79b2c081 100644 --- a/types/google-apps-script/apis/sheets_v4.d.ts +++ b/types/google-apps-script/apis/sheets_v4.d.ts @@ -305,10 +305,18 @@ declare namespace GoogleAppsScript { rowProperties?: Sheets.Schema.BandingProperties | undefined; } interface BandingProperties { + /** @deprecated Use `firstBandColorStyle` instead */ firstBandColor?: Sheets.Schema.Color | undefined; + firstBandColorStyle?: Sheets.Schema.ColorStyle | undefined; + /** @deprecated Use `footerColorStyle` instead */ footerColor?: Sheets.Schema.Color | undefined; + footerColorStyle?: Sheets.Schema.ColorStyle | undefined; + /** @deprecated Use `headerColorStyle` instead */ headerColor?: Sheets.Schema.Color | undefined; + headerColorStyle?: Sheets.Schema.ColorStyle | undefined; + /** @deprecated Use `secondBandColorStyle` instead */ secondBandColor?: Sheets.Schema.Color | undefined; + secondBandColorStyle?: Sheets.Schema.ColorStyle | undefined; } interface BasicChartAxis { format?: Sheets.Schema.TextFormat | undefined; @@ -423,8 +431,11 @@ declare namespace GoogleAppsScript { format?: Sheets.Schema.CellFormat | undefined; } interface Border { + /** @deprecated Use `colorStyle` instead */ color?: Sheets.Schema.Color | undefined; + colorStyle?: Sheets.Schema.ColorStyle | undefined; style?: string | undefined; + /** @deprecated Use `style` instead */ width?: number | undefined; } interface Borders { @@ -476,7 +487,9 @@ declare namespace GoogleAppsScript { userEnteredValue?: Sheets.Schema.ExtendedValue | undefined; } interface CellFormat { + /** @deprecated Use `backgroundColorStyle` instead */ backgroundColor?: Sheets.Schema.Color | undefined; + backgroundColorStyle?: Sheets.Schema.ColorStyle | undefined; borders?: Sheets.Schema.Borders | undefined; horizontalAlignment?: string | undefined; hyperlinkDisplayType?: string | undefined; @@ -528,6 +541,10 @@ declare namespace GoogleAppsScript { green?: number | undefined; red?: number | undefined; } + interface ColorStyle { + rgbColor?: Sheets.Schema.Color | undefined; + themeColor?: string | undefined; + } interface ConditionValue { relativeDate?: string | undefined; userEnteredValue?: string | undefined; @@ -703,6 +720,8 @@ declare namespace GoogleAppsScript { interface FilterCriteria { condition?: Sheets.Schema.BooleanCondition | undefined; hiddenValues?: string[] | undefined; + visibleBackgroundColorStyle?: Sheets.Schema.ColorStyle | undefined; + visibleForegroundColorStyle?: Sheets.Schema.ColorStyle | undefined; } interface FilterView { criteria?: object | undefined; @@ -792,7 +811,9 @@ declare namespace GoogleAppsScript { shiftDimension?: string | undefined; } interface InterpolationPoint { + /** @deprecated Use `colorStyle` instead */ color?: Sheets.Schema.Color | undefined; + colorStyle?: Sheets.Schema.ColorStyle | undefined; type?: string | undefined; value?: string | undefined; } @@ -1044,7 +1065,9 @@ declare namespace GoogleAppsScript { rightToLeft?: boolean | undefined; sheetId?: number | undefined; sheetType?: string | undefined; + /** @deprecated Use `tabColorStyle` instead */ tabColor?: Sheets.Schema.Color | undefined; + tabColorStyle?: Sheets.Schema.ColorStyle | undefined; title?: string | undefined; } interface SortRangeRequest { @@ -1054,6 +1077,8 @@ declare namespace GoogleAppsScript { interface SortSpec { dimensionIndex?: number | undefined; sortOrder?: string | undefined; + foregroundColorStyle?: Sheets.Schema.ColorStyle | undefined; + backgroundColorStyle?: Sheets.Schema.ColorStyle | undefined; } interface SourceAndDestination { dimension?: string | undefined; @@ -1080,7 +1105,9 @@ declare namespace GoogleAppsScript { bold?: boolean | undefined; fontFamily?: string | undefined; fontSize?: number | undefined; + /** @deprecated Use `foregroundColorStyle` instead */ foregroundColor?: Sheets.Schema.Color | undefined; + foregroundColorStyle?: Sheets.Schema.ColorStyle | undefined; italic?: boolean | undefined; strikethrough?: boolean | undefined; underline?: boolean | undefined; @@ -1346,6 +1373,8 @@ declare namespace GoogleAppsScript { newClearValuesRequest(): any; // Schema.ClearValuesRequest; // Create a new instance of Color newColor(): Sheets.Schema.Color; + // Create a new instance of ColorStyle + newColorStyle(): Sheets.Schema.ColorStyle; // Create a new instance of ConditionValue newConditionValue(): Sheets.Schema.ConditionValue; // Create a new instance of ConditionalFormatRule diff --git a/types/google-apps-script/test/google-apps-script-tests.ts b/types/google-apps-script/test/google-apps-script-tests.ts index 0447945aebe636..2cd779886918e7 100644 --- a/types/google-apps-script/test/google-apps-script-tests.ts +++ b/types/google-apps-script/test/google-apps-script-tests.ts @@ -1602,3 +1602,35 @@ function testGmailDraftReplyWithSubject() { attachments: [DriveApp.getFileById("file-id").getBlob()], }); } + +function testSheetsV4ColorStyle() { + const style: GoogleAppsScript.Sheets.Schema.ColorStyle = Sheets!.newColorStyle(); + + // Validate all new properties across all updated interfaces + const banding: GoogleAppsScript.Sheets.Schema.BandingProperties = { + firstBandColorStyle: style, + footerColorStyle: style, + headerColorStyle: style, + secondBandColorStyle: style, + }; + + const border: GoogleAppsScript.Sheets.Schema.Border = { colorStyle: style }; + + const cellFormat: GoogleAppsScript.Sheets.Schema.CellFormat = { backgroundColorStyle: style }; + + const filter: GoogleAppsScript.Sheets.Schema.FilterCriteria = { + visibleBackgroundColorStyle: style, + visibleForegroundColorStyle: style, + }; + + const interpolation: GoogleAppsScript.Sheets.Schema.InterpolationPoint = { colorStyle: style }; + + const sheetProps: GoogleAppsScript.Sheets.Schema.SheetProperties = { tabColorStyle: style }; + + const sortSpec: GoogleAppsScript.Sheets.Schema.SortSpec = { + foregroundColorStyle: style, + backgroundColorStyle: style, + }; + + const textFormat: GoogleAppsScript.Sheets.Schema.TextFormat = { foregroundColorStyle: style }; +} From e0025ad0d217f9c19027259f79551e809b9ea8a9 Mon Sep 17 00:00:00 2001 From: Erwan Jugand <47392755+erwanjugand@users.noreply.github.com> Date: Fri, 5 Jun 2026 20:24:20 +0200 Subject: [PATCH 03/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75076=20[chr?= =?UTF-8?q?ome]=20update=20since=20Chrome=20149=20by=20@erwanjugand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/chrome/index.d.ts | 16 +++++++++++----- types/chrome/test/index.ts | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/types/chrome/index.d.ts b/types/chrome/index.d.ts index a4be0921370abf..ee0e647e71800f 100644 --- a/types/chrome/index.d.ts +++ b/types/chrome/index.d.ts @@ -1725,7 +1725,7 @@ declare namespace chrome { * * `allow`: Allow sites to use advanced clipboard capabilities, * - * `block`: Don't allow sites to use advanced clipboard capabilties, + * `block`: Don't allow sites to use advanced clipboard capabilities, * * `ask`: Ask when a site wants to use advanced clipboard capabilities. * @@ -1876,6 +1876,8 @@ declare namespace chrome { BROWSER_ACTION = "browser_action", PAGE_ACTION = "page_action", ACTION = "action", + /** @since Chrome 149 */ + TAB = "tab", } /** @@ -2585,7 +2587,7 @@ declare namespace chrome { interface EditResponseCookie { /** Filter for cookies that will be modified. All empty entries are ignored. */ filter: ResponseCookie; - /** Attributes that shall be overridden in cookies that machted the filter. Attributes that are set to an empty string are removed. */ + /** Attributes that shall be overridden in cookies that matched the filter. Attributes that are set to an empty string are removed. */ modification: ResponseCookie; } @@ -2603,7 +2605,7 @@ declare namespace chrome { interface EditRequestCookie { /** Filter for cookies that will be modified. All empty entries are ignored. */ filter: RequestCookie; - /** Attributes that shall be overridden in cookies that machted the filter. Attributes that are set to an empty string are removed. */ + /** Attributes that shall be overridden in cookies that matched the filter. Attributes that are set to an empty string are removed. */ modification: RequestCookie; } @@ -4545,7 +4547,7 @@ declare namespace chrome { const inIncognitoContext: boolean; /** - * Set for the lifetime of a callback if an ansychronous extension api has resulted in an error. If no error has occurred lastError will be `undefined`. + * Set for the lifetime of a callback if an asynchronous extension api has resulted in an error. If no error has occurred lastError will be `undefined`. * @deprecated since Chrome 58. Please use {@link runtime.lastError} */ const lastError: runtime.LastError | undefined; @@ -8912,6 +8914,7 @@ declare namespace chrome { /** * The native client architecture. This may be different from arch on some platforms. * @since Chrome 44 + * @deprecated since Chrome 149. This enum is deprecated following complete removal of Native Client. */ enum PlatformNaclArch { /** Specifies the native client architecture as arm. */ @@ -9072,7 +9075,10 @@ declare namespace chrome { os: `${PlatformOs}`; /** The machine's processor architecture. */ arch: `${PlatformArch}`; - /** The native client architecture. This may be different from arch on some platforms. */ + /** + * The native client architecture. This may be different from arch on some platforms. + * @deprecated since Chrome 149. This attribute is deprecated following complete removal of Native Client. + */ nacl_arch?: `${PlatformNaclArch}`; } diff --git a/types/chrome/test/index.ts b/types/chrome/test/index.ts index 1953fa2a314026..a1eb5d42db9d30 100644 --- a/types/chrome/test/index.ts +++ b/types/chrome/test/index.ts @@ -4358,6 +4358,7 @@ function testContextMenus() { chrome.contextMenus.ContextType.PAGE === "page"; chrome.contextMenus.ContextType.PAGE_ACTION === "page_action"; chrome.contextMenus.ContextType.SELECTION === "selection"; + chrome.contextMenus.ContextType.TAB === "tab"; chrome.contextMenus.ContextType.VIDEO === "video"; chrome.contextMenus.ItemType.CHECKBOX === "checkbox"; From ceb82268b93a5f58f62ce97ab01afedd25333962 Mon Sep 17 00:00:00 2001 From: thromer Date: Fri, 5 Jun 2026 12:12:10 -0700 Subject: [PATCH 04/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74949=20Add?= =?UTF-8?q?=203=20missing=20fields=20to=20google-apps-script=20drive=5Fv2?= =?UTF-8?q?=20Permission=20interface=20by=20@thromer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/google-apps-script/apis/drive_v2.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/google-apps-script/apis/drive_v2.d.ts b/types/google-apps-script/apis/drive_v2.d.ts index 17587351178f7a..1163fc5c0a12fb 100644 --- a/types/google-apps-script/apis/drive_v2.d.ts +++ b/types/google-apps-script/apis/drive_v2.d.ts @@ -779,8 +779,10 @@ declare namespace GoogleAppsScript { etag?: string | undefined; expirationDate?: string | undefined; id?: string | undefined; + inheritedPermissionsDisabled?: boolean | undefined; kind?: string | undefined; name?: string | undefined; + pendingOwner?: boolean | undefined; permissionDetails?: Drive.Schema.PermissionPermissionDetails[] | undefined; photoLink?: string | undefined; role?: "owner" | "organizer" | "fileOrganizer" | "writer" | "reader" | undefined; @@ -788,6 +790,7 @@ declare namespace GoogleAppsScript { teamDrivePermissionDetails?: Drive.Schema.PermissionTeamDrivePermissionDetails[] | undefined; type?: string | undefined; value?: string | undefined; + view?: string | undefined; withLink?: boolean | undefined; } interface PermissionId { From fbbe9480f84cc20727e9ff9a7bba7a1cb66157a9 Mon Sep 17 00:00:00 2001 From: "Henry Q. Dineen" Date: Fri, 5 Jun 2026 15:17:29 -0400 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75023=20[rea?= =?UTF-8?q?ct]=20Fix=20broken=20React=20TypeScript=20Cheatsheet=20links=20?= =?UTF-8?q?by=20@henryqdineen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Sonnet 4.6 (1M context) --- types/react/index.d.ts | 8 ++++---- types/react/ts5.0/index.d.ts | 8 ++++---- types/react/v18/index.d.ts | 8 ++++---- types/react/v18/ts5.0/index.d.ts | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/types/react/index.d.ts b/types/react/index.d.ts index 4dd970bf5b1c17..b4948e765f2a77 100644 --- a/types/react/index.d.ts +++ b/types/react/index.d.ts @@ -408,7 +408,7 @@ declare namespace React { * * Where {@link ReactElement} only represents JSX, `ReactNode` represents everything that can be rendered. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/reactnode/ React TypeScript Cheatsheet} * * @example * @@ -1431,7 +1431,7 @@ declare namespace React { * instead of this type, as they let you be explicit about whether or not to include * the `ref` prop. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1459,7 +1459,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1509,7 +1509,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * diff --git a/types/react/ts5.0/index.d.ts b/types/react/ts5.0/index.d.ts index 73b1e875694f18..e1e035b9b05d4b 100644 --- a/types/react/ts5.0/index.d.ts +++ b/types/react/ts5.0/index.d.ts @@ -409,7 +409,7 @@ declare namespace React { * * Where {@link ReactElement} only represents JSX, `ReactNode` represents everything that can be rendered. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/reactnode/ React TypeScript Cheatsheet} * * @example * @@ -1430,7 +1430,7 @@ declare namespace React { * instead of this type, as they let you be explicit about whether or not to include * the `ref` prop. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1458,7 +1458,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1508,7 +1508,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * diff --git a/types/react/v18/index.d.ts b/types/react/v18/index.d.ts index a88c8481e57497..5cbde80287e33c 100644 --- a/types/react/v18/index.d.ts +++ b/types/react/v18/index.d.ts @@ -458,7 +458,7 @@ declare namespace React { * * Where {@link ReactElement} only represents JSX, `ReactNode` represents everything that can be rendered. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/reactnode/ React TypeScript Cheatsheet} * * @example * @@ -1646,7 +1646,7 @@ declare namespace React { * instead of this type, as they let you be explicit about whether or not to include * the `ref` prop. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1674,7 +1674,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1721,7 +1721,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * diff --git a/types/react/v18/ts5.0/index.d.ts b/types/react/v18/ts5.0/index.d.ts index 6bb9083f9de5f1..b4323186e95c55 100644 --- a/types/react/v18/ts5.0/index.d.ts +++ b/types/react/v18/ts5.0/index.d.ts @@ -459,7 +459,7 @@ declare namespace React { * * Where {@link ReactElement} only represents JSX, `ReactNode` represents everything that can be rendered. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/reactnode/ React TypeScript Cheatsheet} * * @example * @@ -1647,7 +1647,7 @@ declare namespace React { * instead of this type, as they let you be explicit about whether or not to include * the `ref` prop. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1675,7 +1675,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * @@ -1722,7 +1722,7 @@ declare namespace React { * passed a string, indicating a DOM element (e.g. 'div', 'span', etc.) or the * type of a React component. * - * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/ React TypeScript Cheatsheet} + * @see {@link https://react-typescript-cheatsheet.netlify.app/docs/reference/ComponentProps React TypeScript Cheatsheet} * * @example * From 121a561e3c12207e4c91bb73b763f9f0dddaed0c Mon Sep 17 00:00:00 2001 From: Quetzal Rivera Date: Fri, 5 Jun 2026 13:53:06 -0600 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74961=20[you?= =?UTF-8?q?tube]=20Allow=20to=20extend=20YT=20definitions=20again=20by=20@?= =?UTF-8?q?Eptagone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/youtube/index.d.ts | 4 ---- types/youtube/package.json | 2 +- types/youtube/youtube-tests.ts | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/types/youtube/index.d.ts b/types/youtube/index.d.ts index 62c58755976091..0e803982e0929a 100644 --- a/types/youtube/index.d.ts +++ b/types/youtube/index.d.ts @@ -1035,7 +1035,3 @@ declare namespace YT { getVideoData(): VideoData; } } - -// eslint-disable-next-line @definitelytyped/export-just-namespace -export = YT; -export as namespace YT; diff --git a/types/youtube/package.json b/types/youtube/package.json index 20220bae5f4413..f86e4383607bf0 100644 --- a/types/youtube/package.json +++ b/types/youtube/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/youtube", - "version": "0.2.9999", + "version": "0.3.9999", "projects": [ "https://developers.google.com/youtube/" ], diff --git a/types/youtube/youtube-tests.ts b/types/youtube/youtube-tests.ts index 617a561860e3e3..fd68f5ea5b9901 100644 --- a/types/youtube/youtube-tests.ts +++ b/types/youtube/youtube-tests.ts @@ -1,5 +1,3 @@ -import * as YT from "youtube"; - const players: YT.Player[] = [ new YT.Player(document.body, {}), new YT.Player(document.body, { From 65acac0aa48fcb04a10eaa27f8f315b0c4b03076 Mon Sep 17 00:00:00 2001 From: Valentin <27902270+vdistortion@users.noreply.github.com> Date: Sat, 6 Jun 2026 01:12:22 +0500 Subject: [PATCH 07/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75039=20[arc?= =?UTF-8?q?hiver]=20Update=20to=20v8=20by=20@vdistortion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/archiver/archiver-tests.ts | 76 +++++----- types/archiver/index.d.ts | 235 ++++++++++++++----------------- types/archiver/package.json | 8 +- types/gulp-tar/index.d.ts | 4 +- 4 files changed, 156 insertions(+), 167 deletions(-) diff --git a/types/archiver/archiver-tests.ts b/types/archiver/archiver-tests.ts index eb231448a73c52..1efe15cccdab4b 100644 --- a/types/archiver/archiver-tests.ts +++ b/types/archiver/archiver-tests.ts @@ -1,32 +1,45 @@ -import Archiver = require("archiver"); +import { + Archiver, + type ArchiverError, + ArchiverOptions, + EntryData, + EntryDataFunction, + JsonArchive, + ProgressData, + TarArchive, + ZipArchive, +} from "archiver"; + import * as fs from "fs"; import { Readable, Writable } from "stream"; -const options: Archiver.ArchiverOptions = { +const options: ArchiverOptions = { statConcurrency: 1, allowHalfOpen: true, readableObjectMode: true, - writeableObjectMode: true, + writableObjectMode: true, decodeStrings: true, - encoding: "test", + encoding: "utf8", highWaterMark: 1, - objectmode: true, + objectMode: true, comment: "test", forceLocalTime: true, forceZip64: true, namePrependSlash: true, store: true, + level: 9, zlib: {}, gzip: true, gzipOptions: {}, }; -Archiver("zip", options); - -const archiver = Archiver.create("zip"); +const zipArchiver: ZipArchive = new ZipArchive(options); +const tarArchiver: TarArchive = new TarArchive({ gzip: true }); +const jsonArchiver: JsonArchive = new JsonArchive(); -const archiverAsReadable: Readable = archiver; -const archiverAsWritable: Writable = archiver; +const archiver: Archiver = zipArchiver; +const readable: Readable = archiver; +const writable: Writable = archiver; const writeStream = fs.createWriteStream("./archiver.d.ts"); const readStream = fs.createReadStream("./archiver.d.ts"); @@ -38,54 +51,53 @@ archiver.append(readStream, { name: "archiver.d.ts" }); archiver.append(readStream, { name: "buffer.txt", date: "05/05/1991" }); archiver.append(readStream, { name: "buffer.txt", date: new Date() }); archiver.append(readStream, { name: "buffer.txt", mode: 1 }); -archiver.append(readStream, { name: "buffer.txt", mode: 1, stats: ({} as fs.Stats) }); +archiver.append(readStream, { + name: "buffer.txt", + mode: 1, + stats: {} as fs.Stats, +}); archiver.append("Some content", { name: "filename", store: true }); -archiver.append(readStream, { name: "archiver.d.ts" }).append(readStream, { name: "archiver.d.ts" }); +archiver + .append(readStream, { name: "archiver.d.ts" }) + .append(readStream, { name: "archiver.d.ts" }); archiver.append(Readable.from(["test"]), { name: "buffer.txt", date: new Date() }); archiver.directory("./path", "./someOtherPath"); archiver.directory("./", "", {}); archiver.directory("./", false, { name: "test" }); -archiver.directory("./", false, (entry: Archiver.EntryData) => { +archiver.directory("./", false, (entry: EntryData) => { entry.name = "foobar"; return entry; }); -archiver.directory("./", false, (entry: Archiver.EntryData) => false); - -archiver.append(readStream, { - name: "sub/folder.xml", -}); - -archiver.glob("**", { - cwd: "path/to/files", -}); -archiver.glob("./path", {}, {}); +archiver.directory("./", false, (entry: EntryData) => false); +archiver.file("./path"); archiver.file("./path", { name: "test" }); -archiver.setFormat("zip"); -archiver.setModule(() => {}); +archiver.glob("**", { cwd: "path/to/files" }); +archiver.glob("./path", {}, {}); archiver.pointer(); -archiver.use(() => {}); archiver.finalize(); // $ExpectType Promise archiver.symlink("./path", "./target"); +archiver.symlink("directory/directory", "../../directory", 493); -function fakeHandler(err: Archiver.ArchiverError) { +function fakeHandler(err: ArchiverError) { console.log(err.code); console.log(err.message); console.log(err.stack); console.log(err.data); } -const fakeError = new Archiver.ArchiverError("code", "foo"); - archiver.on("error", fakeHandler); archiver.on("warning", fakeHandler); archiver.on("data", (chunk: Buffer) => console.log(chunk)); - -Archiver.isRegisteredFormat("zip"); // $ExpectType boolean -archiver.symlink("directory/directory", "../../directory", 493); // $ExpectType Archiver +archiver.on("progress", (progress: ProgressData) => { + console.log(progress.entries.total); +}); +archiver.on("entry", (entry: EntryData) => { + console.log(entry.name); +}); diff --git a/types/archiver/index.d.ts b/types/archiver/index.d.ts index 03d2d7d4cdd914..f2fa22a400af07 100644 --- a/types/archiver/index.d.ts +++ b/types/archiver/index.d.ts @@ -1,137 +1,108 @@ import * as fs from "fs"; -import ReaddirGlob = require("readdir-glob"); -import stream = require("stream"); +import * as ReaddirGlob from "readdir-glob"; +import * as stream from "stream"; import { ZlibOptions } from "zlib"; -type Partial = { - [P in keyof T]?: T[P]; -}; - -// This library adds `cwd` to the options -type GlobOptions = ReaddirGlob.Options & { cwd?: string }; - -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- support for ConstructorFn function and classes -type ConstructorFn = Function | (new(...params: any[]) => T); - -declare function archiver(format: archiver.Format, options?: archiver.ArchiverOptions): archiver.Archiver; - -declare namespace archiver { - type Format = "zip" | "tar"; - - function create(format: string, options?: ArchiverOptions): Archiver; - - /** Check if the format is already registered. */ - function isRegisteredFormat(format: string): boolean; - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - function registerFormat(format: string, module: Function): void; - - interface EntryData { - /** Sets the entry name including internal path */ - name: string; - /** Sets the entry date */ - date?: Date | string | undefined; - /** Sets the entry permissions */ - mode?: number | undefined; - /** - * Sets a path prefix for the entry name. - * Useful when working with methods like `directory` or `glob` - */ - prefix?: string | undefined; - /** - * Sets the fs stat data for this entry allowing - * for reduction of fs stat calls when stat data is already known - */ - stats?: fs.Stats | undefined; - } - - interface ZipEntryData extends EntryData { - /** Sets the compression method to STORE */ - store?: boolean | undefined; - } - - type TarEntryData = EntryData; - - interface ProgressData { - entries: { - total: number; - processed: number; - }; - fs: { - totalBytes: number; - processedBytes: number; - }; - } - - /** A function that lets you either opt out of including an entry (by returning false), or modify the contents of an entry as it is added (by returning an EntryData) */ - type EntryDataFunction = (entry: EntryData) => false | EntryData; - - class ArchiverError extends Error { - code: string; // Since archiver format support is modular, we cannot enumerate all possible error codes, as the modules can throw arbitrary ones. - data: any; - path?: any; - - constructor(code: string, data: any); - } - - interface Archiver extends stream.Transform { - abort(): this; - append(source: stream.Readable | Buffer | string, data?: EntryData | ZipEntryData | TarEntryData): this; - - /** if false is passed for destpath, the path of a chunk of data in the archive is set to the root */ - directory(dirpath: string, destpath: false | string, data?: Partial | EntryDataFunction): this; - file(filename: string, data: EntryData): this; - glob(pattern: string, options?: GlobOptions, data?: Partial): this; - finalize(): Promise; - - setFormat(format: string): this; - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - setModule(module: Function): this; - - pointer(): number; - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - use(plugin: Function): this; - - symlink(filepath: string, target: string, mode?: number): this; - - on(event: "error" | "warning", listener: (error: ArchiverError) => void): this; - on(event: "data", listener: (data: Buffer) => void): this; - on(event: "progress", listener: (progress: ProgressData) => void): this; - on(event: "close" | "drain" | "finish", listener: () => void): this; - on(event: "pipe" | "unpipe", listener: (src: stream.Readable) => void): this; - on(event: "entry", listener: (entry: EntryData) => void): this; - on(event: string, listener: (...args: any[]) => void): this; - } - - type ArchiverOptions = CoreOptions & TransformOptions & ZipOptions & TarOptions; - - interface CoreOptions { - statConcurrency?: number | undefined; - } - - interface TransformOptions { - allowHalfOpen?: boolean | undefined; - readableObjectMode?: boolean | undefined; - writeableObjectMode?: boolean | undefined; - decodeStrings?: boolean | undefined; - encoding?: string | undefined; - highWaterMark?: number | undefined; - objectmode?: boolean | undefined; - } - - interface ZipOptions { - comment?: string | undefined; - forceLocalTime?: boolean | undefined; - forceZip64?: boolean | undefined; - /** @default false */ - namePrependSlash?: boolean | undefined; - store?: boolean | undefined; - zlib?: ZlibOptions | undefined; - } - - interface TarOptions { - gzip?: boolean | undefined; - gzipOptions?: ZlibOptions | undefined; - } +export type GlobOptions = ReaddirGlob.Options & { cwd?: string }; + +export interface EntryData { + name: string; + type?: "directory" | "file" | "symlink"; + date?: Date | string; + mode?: number; + prefix?: string; + stats?: fs.Stats; +} + +export interface ZipEntryData extends EntryData { + store?: boolean; + comment?: string; + namePrependSlash?: boolean; +} + +export type TarEntryData = EntryData; + +export interface ProgressData { + entries: { + total: number; + processed: number; + }; + fs: { + totalBytes: number; + processedBytes: number; + }; +} + +export type EntryDataFunction = (entry: EntryData) => false | EntryData; + +export interface ArchiverError extends Error { + code: string; + data?: any; +} + +export class Archiver extends stream.Transform { + constructor(options?: CoreOptions & TransformOptions); + abort(): this; + append(source: stream.Readable | Buffer | string, data?: EntryData | ZipEntryData | TarEntryData): this; + directory( + dirpath: string, + destpath: false | string, + data?: Partial | EntryDataFunction, + ): this; + /** @param data - entry data (optional) */ + file(filename: string, data?: EntryData): this; + glob(pattern: string, options?: GlobOptions, data?: Partial): this; + finalize(): Promise; + pointer(): number; + symlink(filepath: string, target: string, mode?: number): this; + on(event: "error" | "warning", listener: (error: ArchiverError) => void): this; + on(event: "data", listener: (data: Buffer) => void): this; + on(event: "progress", listener: (progress: ProgressData) => void): this; + on(event: "close" | "drain" | "finish", listener: () => void): this; + on(event: "pipe" | "unpipe", listener: (src: stream.Readable) => void): this; + on(event: "entry", listener: (entry: EntryData) => void): this; + on(event: string, listener: (...args: any[]) => void): this; +} + +export interface CoreOptions { + statConcurrency?: number; } -export = archiver; +export interface TransformOptions { + allowHalfOpen?: boolean; + readableObjectMode?: boolean; + writableObjectMode?: boolean; + decodeStrings?: boolean; + encoding?: BufferEncoding; + highWaterMark?: number; + objectMode?: boolean; +} + +export interface ZipOptions { + comment?: string; + forceLocalTime?: boolean; + forceZip64?: boolean; + namePrependSlash?: boolean; + store?: boolean; + level?: number; + zlib?: ZlibOptions; +} + +export interface TarOptions { + gzip?: boolean; + gzipOptions?: ZlibOptions; +} + +export type ArchiverOptions = CoreOptions & TransformOptions & ZipOptions & TarOptions; + +export class ZipArchive extends Archiver { + constructor(options?: CoreOptions & TransformOptions & ZipOptions); +} + +export class TarArchive extends Archiver { + constructor(options?: CoreOptions & TransformOptions & TarOptions); +} + +export class JsonArchive extends Archiver { + constructor(options?: CoreOptions & TransformOptions); +} diff --git a/types/archiver/package.json b/types/archiver/package.json index e2d1c12b1cda8c..e571ad2f5712f5 100644 --- a/types/archiver/package.json +++ b/types/archiver/package.json @@ -1,11 +1,13 @@ { "private": true, "name": "@types/archiver", - "version": "7.0.9999", + "version": "8.0.9999", "projects": [ "https://github.com/archiverjs/node-archiver" ], + "type": "module", "dependencies": { + "@types/node": "*", "@types/readdir-glob": "*" }, "devDependencies": { @@ -23,6 +25,10 @@ { "name": "Piotr Błażejewicz", "githubUsername": "peterblazejewicz" + }, + { + "name": "Valentin Zolotov", + "githubUsername": "vdistortion" } ] } diff --git a/types/gulp-tar/index.d.ts b/types/gulp-tar/index.d.ts index c6c20da94c7dd4..1be99f98491147 100644 --- a/types/gulp-tar/index.d.ts +++ b/types/gulp-tar/index.d.ts @@ -1,10 +1,10 @@ /// -import archiver = require("archiver"); +import type { ArchiverOptions } from "archiver"; declare function gulpTar( filename: string, - options?: archiver.ArchiverOptions, + options?: ArchiverOptions, ): NodeJS.ReadableStream & NodeJS.WritableStream; export default gulpTar; From 2330ee20127e9835b9aebf04ae6697dc294b0cff Mon Sep 17 00:00:00 2001 From: Prajal Gupta Date: Sat, 6 Jun 2026 02:04:07 +0530 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75075=20=20[?= =?UTF-8?q?oracledb]=20Update=20types=20for=20node-oracledb=207.0=20featur?= =?UTF-8?q?es=20by=20@prajalg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/oracledb/index.d.ts | 653 +++++++++++++++++++++++++++++++ types/oracledb/oracledb-tests.ts | 161 ++++++++ types/oracledb/package.json | 2 +- types/oracledb/tsconfig.json | 3 +- 4 files changed, 817 insertions(+), 2 deletions(-) diff --git a/types/oracledb/index.d.ts b/types/oracledb/index.d.ts index 7c31d1acc55ffa..1eac06dbc24373 100644 --- a/types/oracledb/index.d.ts +++ b/types/oracledb/index.d.ts @@ -1,4 +1,5 @@ /// +/// import { Duplex, Readable } from "stream"; @@ -915,6 +916,17 @@ declare namespace OracleDB { * The value that is displayed for the connection.thin, pool.thin, and oracledb.thin attributes will be the same. */ let thin: boolean; + /** + * This property is a boolean that determines whether connect strings in + * node-oracledb Thick mode are passed unchanged to Oracle Client libraries + * or parsed by node-oracledb. + * + * If we are using this property, it must be be set before creating the first standalone connection or pool. + * + * @default true + * @since 7.0 + */ + let thickModeDSNPassthrough: boolean; /** * This readonly property gives a numeric representation of the node-oracledb version. * For version x.y.z, this property gives the number: (10000 * x) + (100 * y) + z @@ -1046,6 +1058,77 @@ declare namespace OracleDB { deferRoundTrip?: boolean; } + /** + * Configuration options used to create an EndUserSecurityContext object. + * + * Use either endUserToken, or the endUserName/key combination. + * + * @since 7.0 + */ + interface BaseEndUserSecurityContextOptions { + /** + * A security token issued by an external Identity and Access Management (IAM) + * system that authorizes access to Oracle Database. + */ + databaseAccessToken: string; + /** + * The names of data roles granted to the application or local database user. + */ + dataRoles?: string[] | undefined; + /** + * The attribute-value pairs provided by the application. + */ + attributes?: Record | undefined; + } + + type EndUserSecurityContextOptions = + | (BaseEndUserSecurityContextOptions & { + /** + * The unique identification of an end user managed by an external IAM system. + */ + endUserToken: string; + /** + * The unique identification of an end user managed by Oracle Database. + * + * This attribute should not be set when `endUserToken` is specified. + */ + endUserName?: never; + /** + * The lookup identifier that the database maps to stored context attributes. + * + * This attribute should not be set when `endUserToken` is specified. + */ + key?: never; + }) + | (BaseEndUserSecurityContextOptions & { + /** + * The unique identification of an end user managed by an external IAM system. + * + * This attribute should not be set when `endUserName` is specified. + */ + endUserToken?: never; + /** + * The unique identification of an end user managed by Oracle Database. + */ + endUserName: string; + /** + * The lookup identifier that the database maps to stored context attributes. + * This is required when `endUserName` is set. + */ + key: string; + }); + + /** + * Defines end user security context information for an end user. + * + * In this release, Deep Data Security is only supported in node-oracledb Thin mode. + * + * @since 7.0 + */ + class EndUserSecurityContext { + constructor(options: EndUserSecurityContextOptions); + } + interface Connection { /** * The action attribute for end-to-end application tracing. @@ -1150,6 +1233,16 @@ declare namespace OracleDB { * @since 4.1 */ dbOp?: string | undefined; + /** + * This read-only property is a string that identifies a globally + * unique name for the database. This property returns the same value + * as the SQL expression: + * SELECT UPPER(SYS_CONTEXT('USERENV', 'DB_UNIQUE_NAME')) FROM DUAL; + * Available only in node-oracledb Thin mode. + * + * @since 7.0 + */ + readonly dbUniqueName?: string | undefined; /** * This write-only property is a string that sets the execution context identifier. * The value is available in the ECID column of the V$SESSION view. It is also shown in audit logs. @@ -1217,6 +1310,15 @@ declare namespace OracleDB { * @since 2.2 */ readonly oracleServerVersionString: string; + /** + * This read-only property is a string that identifies the name of the + * pluggable database associated with the connection. This property + * returns the same value as the SQL expression: + * SELECT UPPER(SYS_CONTEXT('USERENV', 'CON_NAME')) FROM DUAL; + * + * @since 7.0 + */ + readonly pdbName?: string | undefined; /** * This read-only property identifies the port to which the client is connected. * Available only in node-oracledb Thin mode. @@ -1296,6 +1398,19 @@ declare namespace OracleDB { * @since 6.3 */ readonly warning?: DBError | undefined; + /** + * This synchronous method sets application context key-value pairs for + * the given namespace. + * + * The namespace "CLIENTCONTEXT" is reserved for client + * session-based application contexts. + * + * @param namespaceName The application context namespace. + * @param keyValues The key-value entries to set. + * + * @since 7.0 + */ + appContext(namespaceName: string, keyValues: AppContextKeyValue[]): void; /** * Begins a new sessionless transaction using the specified transaction identifier. * This method returns the transaction identifier specified by the user or generated by node-oracledb as a Buffer value. @@ -1341,6 +1456,28 @@ declare namespace OracleDB { newPassword: string, callback: (error: DBError | null) => void, ): void; + /** + * This synchronous method clears all application context key-value + * pairs for the given namespace. + * + * @param namespaceName The application context namespace. + * + * @since 7.0 + */ + clearAppContext(namespaceName: string): void; + + /** + * This synchronous method clears the end user security context specified + * on a connection. + * + * This reverts the connection to its original state in which subsequent + * database operations are executed without any end user security context. + * + * Currently, this method is only relevant in node-oracledb Thin mode. + * + * @since 7.0 + */ + clearEndUserSecurityContext(): void; /** * Releases a connection. @@ -1364,6 +1501,16 @@ declare namespace OracleDB { close(options: CloseConnectionOptions, callback: (error: DBError | null) => void): void; close(callback: (error: DBError | null) => void): void; + /** + * Implements Explicit Resource Management. Equivalent to calling + * connection.close(). + * + * Requires Node.js 24. + * + * @since 7.0 + */ + [Symbol.asyncDispose](): Promise; + /** * This call commits the current transaction in progress on the connection. */ @@ -1399,6 +1546,49 @@ declare namespace OracleDB { * @see https://node-oracledb.readthedocs.io/en/latest/user_guide/json_data_type.html#osontype */ decodeOSON(buf: Buffer): any; + + /** + * Performs a direct path load into the specified table. + * + * This method can only be used in node-oracledb Thin mode. + * It is not supported for BFILE data. + * + * @param schema The name of the database schema. + * @param table The name of the table into which data is to be loaded. + * @param columns The names of the columns to be populated. + * @param data The data to be loaded. + * + * @since 7.0 + */ + directPathLoad( + schema: string, + table: string, + columns: DirectPathLoadColumns, + data: DirectPathLoadData, + ): Promise; + /** + * Performs a direct path load into the specified table. + * + * This method can only be used in node-oracledb Thin mode. + * It is not supported for BFILE data. + * + * @param schema The name of the database schema. + * @param table The name of the table into which data is to be loaded. + * @param columns The names of the columns to be populated. + * @param data The data to be loaded. + * @param callback If directPathLoad() succeeds, error is NULL. + * If an error occurs, error contains the error message. + * + * @since 7.0 + */ + directPathLoad( + schema: string, + table: string, + columns: DirectPathLoadColumns, + data: DirectPathLoadData, + callback: (error: DBError | null) => void, + ): void; + /** * This synchronous method encodes a JavaScript value to OSON bytes and returns a Buffer. This method is useful for inserting OSON bytes directly into BLOB columns that have the check constraint IS JSON FORMAT OSON enabled. * @@ -1698,6 +1888,84 @@ declare namespace OracleDB { rollback(): Promise; rollback(callback: (error: DBError | null) => void): void; + /** + * Runs all of the operations in a pipeline and returns an array of + * results, each entry corresponding to an operation executed in the + * pipeline. + * + * True pipelining requires Oracle AI Database 26ai (or later) in Thin + * mode. In Thick mode or older database versions, operations are + * executed sequentially. + * + * @param pipeline The pipeline to be run. + * @param continueOnError Determines whether operations should continue + * to run after an error has occurred. + * If true, errors are stored as a corresponding pipeline operation result. + * If false, an error is raised as soon as it occurs and subsequent + * operations are terminated. + * Default is false. + * + * @since 7.0 + */ + runPipeline( + pipeline: Pipeline, + continueOnError?: boolean, + ): Promise; + /** + * Runs all of the operations in a pipeline and invokes the callback with + * the results. + * + * True pipelining requires Oracle AI Database 26ai (or later) in Thin + * mode. In Thick mode or older database versions, operations are + * executed sequentially. + * + * @param pipeline The pipeline to be run. + * @param continueOnError Determines whether operations should continue + * to run after an error has occurred. + * @param callback Callback where error is NULL on success, otherwise + * contains the error message; results is the array that contains the + * results of the executed pipeline operations. + * + * @since 7.0 + */ + runPipeline( + pipeline: Pipeline, + continueOnError: boolean, + callback: ResultCallback, + ): void; + /** + * Runs all of the operations in a pipeline and invokes the callback with + * the results. + * + * True pipelining requires Oracle AI Database 26ai (or later) in Thin + * mode. In Thick mode or older database versions, operations are + * executed sequentially. + * + * @param pipeline The pipeline to be run. + * @param callback Callback where error is NULL on success, otherwise + * contains the error message; results is the array that contains the + * results of the executed pipeline operations. + * + * @since 7.0 + */ + runPipeline( + pipeline: Pipeline, + callback: ResultCallback, + ): void; + + /** + * This synchronous method sets the end user security context on a connection + * using the specified context. + * + * Once this method is called, the specified end user security context is + * applicable to all database operations performed in the connection. + * + * Currently, this method is only relevant to node-oracledb Thin mode. + * + * @since 7.0 + */ + setEndUserSecurityContext(context: EndUserSecurityContext): void; + /** * Used to shut down a database instance. This is the flexible version of oracledb.shutdown(), allowing more control over behavior. * @@ -1947,6 +2215,15 @@ declare namespace OracleDB { profile: string; configFileLocation: string; } + /** + * A key-value entry used by connection.appContext(). + * Each entry should represent one context attribute assignment. + */ + type AppContextKeyValue = Record; + /** + * An application context entry used when creating a connection or pool. + * Each tuple contains the namespace, name, and value strings. + */ type AppContextOpts = [string, string, string]; /** * Provides connection credentials and connection-specific configuration properties. @@ -2347,6 +2624,240 @@ declare namespace OracleDB { stack?: string; } + /** + * The names of table columns populated by directPathLoad(). + * Each entry corresponds to a target column in the destination table. + * + * @since 7.0 + */ + type DirectPathLoadColumns = Array; + + /** + * Data supplied to directPathLoad(). + * This is an array of rows, where each row is an array of column values. + * + * @since 7.0 + */ + type DirectPathLoadData = Array>; + + /** + * Bind values supplied to pipeline operations. + * This can be an object for bind-by-name or an array for bind-by-position. + * + * @since 7.0 + */ + type PipelineBindParameters = BindParameters; + /** + * Bind values supplied to pipeline addExecuteMany(). + * This should be an array of bind-by-name objects or bind-by-position + * arrays. + * + * @since 7.0 + */ + type PipelineExecuteManyBindParameters = BindParameters[]; + + /** + * Options supported in pipeline addExecute(), addFetchAll(), + * addFetchMany(), and addFetchOne(). + * + * @since 7.0 + */ + interface PipelineExecuteOptions { + /** + * Determines whether a commit occurs at the end of statement execution. + */ + autoCommit?: boolean | undefined; + /** + * The size of the internal buffer used for fetching query rows. + */ + fetchArraySize?: number | undefined; + /** + * The maximum number of rows that are fetched from a query. + */ + maxRows?: number | undefined; + /** + * The format of query rows, such as OUT_FORMAT_ARRAY or + * OUT_FORMAT_OBJECT. + */ + outFormat?: number | undefined; + /** + * The number of rows prefetched from Oracle Database. + */ + prefetchRows?: number | undefined; + } + + /** + * Options supported in pipeline addExecuteMany(). + * + * @since 7.0 + */ + interface PipelineExecuteManyOptions extends PipelineExecuteOptions { + /** + * Bind variable definitions for array DML operations. + */ + bindDefs?: Record | BindDefinition[] | undefined; + } + + /** + * Result object for each pipeline operation. + * + * @since 7.0 + */ + interface PipelineOperationResult { + /** + * Defined if the statement executed in the operation returned implicit + * results. + */ + implicitResults?: any[] | undefined; + /** + * Error encountered when running the operation. + * Only available if continueOnError is true. + */ + error?: DBError | undefined; + /** + * ROWID of a row affected by DML. + * If multiple rows were affected, this is the last ROWID. + */ + lastRowid?: string | undefined; + /** + * Array describing each column in a query executed by the operation. + */ + metaData?: Array> | undefined; + /** + * Array or object containing output values of OUT and IN OUT binds used + * in an operation. + */ + outBinds?: Record | any[] | undefined; + /** + * Array containing the rows fetched by the operation, if a query was + * executed. + */ + rows?: any[] | undefined; + /** + * Number of rows affected by the operation. + */ + rowsAffected?: number | undefined; + /** + * Warning encountered when running the operation. + */ + warning?: DBError | undefined; + } + + /** + * Pipeline objects represent a list of operations to be executed by + * connection.runPipeline(). + * + * @since 7.0 + */ + class Pipeline { + constructor(); + /** + * Adds a commit operation to the pipeline. + */ + addCommit(): void; + /** + * Adds an execute operation to the pipeline. + * + * @param statement The SQL statement to be executed. + * @param parameters The values or variables to be bound to the executed + * statement. + * @param options Optional parameter that may be used to control statement + * execution. + */ + addExecute( + statement: string, + parameters?: PipelineBindParameters, + options?: PipelineExecuteOptions, + ): void; + /** + * Adds an executeMany operation to the pipeline. + * + * @param statement The SQL or PL/SQL statement to be executed. + * @param parameters The values or variables to be bound to the executed + * statement. It must be an array of arrays (for bind by position) or an + * array of objects whose keys match the bind variable names in the SQL + * statement (for bind by name). + * @param options Optional parameter that may be used to control statement + * execution. + */ + addExecuteMany( + statement: string, + parameters: PipelineExecuteManyBindParameters, + options?: PipelineExecuteManyOptions, + ): void; + /** + * Adds an executeMany operation to the pipeline with a specified number + * of iterations when using previously-bound values. + * + * @param statement The SQL or PL/SQL statement to be executed. + * @param numIterations The number of iterations. + * @param options Optional parameter that may be used to control statement + * execution. + */ + addExecuteMany( + statement: string, + numIterations: number, + options?: PipelineExecuteManyOptions, + ): void; + /** + * Adds a fetch operation to the pipeline that returns all rows. + * + * @param statement The SQL or PL/SQL statement to be executed. + * @param parameters The values or variables to be bound to the executed + * statement. + * @param options Optional parameter that may be used to control statement + * execution. + * @param fetchArraySize The size of an internal buffer used for fetching + * query rows from Oracle Database. + * @param fetchLobs Determines whether to return LOB objects, or string or + * buffer values when fetching LOB columns. Default is true. + */ + addFetchAll( + statement: string, + parameters?: PipelineBindParameters, + options?: PipelineExecuteOptions, + fetchArraySize?: number, + fetchLobs?: boolean, + ): void; + /** + * Adds a fetch operation to the pipeline that returns up to numRows rows. + * + * @param statement The SQL or PL/SQL statement to be executed. + * @param parameters The values or variables to be bound to the executed + * statement. + * @param options Optional parameter that may be used to control statement + * execution. + * @param numRows The number of rows to be fetched. + * Default is the value of oracledb.fetchArraySize. + * @param fetchLobs Determines whether to return LOB objects, or string or + * buffer values when fetching LOB columns. Default is true. + */ + addFetchMany( + statement: string, + parameters?: PipelineBindParameters, + options?: PipelineExecuteOptions, + numRows?: number, + fetchLobs?: boolean, + ): void; + /** + * Adds a fetch operation to the pipeline that returns at most one row. + * + * @param statement The SQL or PL/SQL statement to be executed. + * @param parameters The values or variables to be bound to the executed + * statement. + * @param options Optional parameter that may be used to control statement + * execution. + * @param fetchLobs Determines whether to return LOB objects, or string or + * buffer values when fetching LOB columns. Default is true. + */ + addFetchOne( + statement: string, + parameters?: PipelineBindParameters, + options?: PipelineExecuteOptions, + fetchLobs?: boolean, + ): void; + } + // eslint-disable-next-line @definitelytyped/no-single-element-tuple-type type ResultCallback = (...args: [DBError] | [null, T]) => void; @@ -2669,6 +3180,19 @@ declare namespace OracleDB { amount: number, callback: ResultCallback, ): void; + /** + * Trims the non-BFILE LOB to the specified size. + * + * If newSize is omitted, the LOB is trimmed to size 0. + * Values greater than or equal to 2^32 are not supported. + * + * @param newSize The size to which the LOB is to be trimmed. + * + * @since 7.0 + */ + trim(newSize?: number): Promise; + trim(callback: (error: DBError | null) => void): void; + trim(newSize: number, callback: (error: DBError | null) => void): void; } /** @@ -2888,6 +3412,16 @@ declare namespace OracleDB { close(drainTime: number, callback: (error: DBError | null) => void): void; close(callback: (error: DBError | null) => void): void; + /** + * Implements Explicit Resource Management. Equivalent to calling + * pool.close(). + * + * Requires Node.js 24. + * + * @since 7.0 + */ + [Symbol.asyncDispose](): Promise; + /** * This method obtains a connection from the connection pool. * @@ -3933,6 +4467,16 @@ declare namespace OracleDB { close(): Promise; close(callback: (error: DBError | null) => void): void; + /** + * Implements Explicit Resource Management. Equivalent to calling + * resultSet.close(). + * + * Requires Node.js 24. + * + * @since 7.0 + */ + [Symbol.asyncDispose](): Promise; + /** * This call fetches one row of the ResultSet as an object or an array of column values, * depending on the value of outFormat. @@ -4994,6 +5538,61 @@ declare namespace OracleDB { readOnly?: boolean | undefined; } + /** + * This synchronous method returns the input value as a string that can safely + * be included in a SQL statement as a string literal. + * + * Embedded single quote characters are doubled. + * Non-string values fail standard parameter validation. + * + * @param value The value to be converted to a SQL string literal. + * @since 7.0 + */ + function enquoteLiteral(value: string): string; + + /** + * This synchronous method returns the input string enclosed in double quotes + * so it can be included in a SQL statement as an identifier. + * + * The default value of capitalize is `true`, so the input is converted to + * uppercase using locale-independent Unicode rules before quoting. + * Set capitalize to `false` to preserve case. + * Any input containing a double quote character is rejected. + * + * Uppercasing is done in the Node.js client and can differ from Oracle + * Database `DBMS_ASSERT.ENQUOTE_NAME()` behavior for some characters. + * + * @param name The string to be quoted for identifier use. + * @param capitalize Indicates whether the input string is converted to uppercase before quoting. The default is `true`. + * @since 7.0 + */ + function enquoteName(name: string, capitalize?: boolean): string; + + /** + * This synchronous method returns whether the input string is a qualified SQL name. + * + * Leading and trailing whitespace is ignored. Components may be separated + * by dots, and one optional trailing '@' database link name is allowed. + * The database link name can itself be dotted. + * Invalid SQL name strings return `false`. + * + * @param name The string to be validated. + * @since 7.0 + */ + function isQualifiedSqlName(name: string): boolean; + + /** + * This synchronous method returns whether the input string is a simple SQL name. + * + * Leading and trailing whitespace is ignored. + * Valid names are either unquoted identifiers that begin with a Unicode letter and then use Unicode letters, Unicode combining marks, Unicode digits, '_', '$', or '#', or quoted identifiers enclosed in double quotes with no embedded double quotes or the NUL character ('\u0000'). + * Invalid SQL name strings return `false`. + * + * @param name The string to be validated. + * @since 7.0 + */ + function isSimpleSqlName(name: string): boolean; + /** * This method creates a pool of connections with the specified user name, password and connection string. * A pool is typically created once during application initialization. @@ -5263,6 +5862,60 @@ declare namespace OracleDB { * @param traceContext input/output trace context object. */ onEndRoundTrip(traceContext: TraceContext): void; + + /** + * Called when the pool expands by creating new connections. + * @param pool the pool instance. + */ + onPoolExpand(pool: Pool): void; + + /** + * Called when the pool shrinks by removing connections. + * @param pool the pool instance. + */ + onPoolShrink(pool: Pool): void; + + /** + * Called when a connection is acquired from the pool. + * @param pool the pool instance. + */ + onPoolAcquire(pool: Pool): void; + + /** + * Called when a connection is released back to the pool. + * @param pool the pool instance. + */ + onPoolRelease(pool: Pool): void; + + /** + * Called when a connection request is queued. + * @param pool the pool instance. + */ + onPoolWait(pool: Pool): void; + + /** + * Called when a queued connection request times out. + * @param pool the pool instance. + */ + onPoolRequestTimeout(pool: Pool): void; + + /** + * Called when a pool free connection is reused. + * @param pool the pool instance. + */ + onPoolConnectionHit(pool: Pool): void; + + /** + * Called when a new request is created for a connection. + * @param pool the pool instance. + */ + onPoolConnectionMiss(pool: Pool): void; + + /** + * Called when the pool is closed. + * @param pool the pool instance. + */ + onPoolClose(pool: Pool): void; } /* diff --git a/types/oracledb/oracledb-tests.ts b/types/oracledb/oracledb-tests.ts index 60dc9f3622c464..6d99745ea991b9 100644 --- a/types/oracledb/oracledb-tests.ts +++ b/types/oracledb/oracledb-tests.ts @@ -911,3 +911,164 @@ export const version6_10Tests = async (): Promise => { const messages = await queue.deqMany(5); }; + +export const version7Tests = async (): Promise => { + defaultOracledb.thickModeDSNPassthrough = false; + expectType(defaultOracledb.thickModeDSNPassthrough); + expectType(defaultOracledb.enquoteLiteral("O'Reilly")); + expectType(defaultOracledb.enquoteName("Department_Name")); + expectType(defaultOracledb.enquoteName("Department_Name", false)); + expectType(defaultOracledb.isSimpleSqlName("employee_id")); + expectType(defaultOracledb.isQualifiedSqlName("HR.employees@db1")); + // @ts-expect-error + defaultOracledb.enquoteLiteral(123); + // @ts-expect-error + defaultOracledb.enquoteName("abc", "no"); + // @ts-expect-error + defaultOracledb.isSimpleSqlName(true); + // @ts-expect-error + defaultOracledb.isQualifiedSqlName(); + + const connection = await oracledb.getConnection({ + user: "test", + }); + expectType<() => Promise>(connection[Symbol.asyncDispose]); + + const pool = await oracledb.createPool({}); + expectType<() => Promise>(pool[Symbol.asyncDispose]); + + const resultSetResult = await connection.execute("SELECT 1 FROM dual", [], { resultSet: true }); + expectType<() => Promise>(resultSetResult.resultSet![Symbol.asyncDispose]); + + await using disposablePool = await oracledb.createPool({}); + await using disposableConnection = await disposablePool.getConnection(); + + const disposableResult = await disposableConnection.execute("SELECT 1 FROM dual", [], { resultSet: true }); + await using disposableResultSet = disposableResult.resultSet!; + + class PoolTraceHandler extends oracledb.traceHandler.TraceHandlerBase { + // some representative methods for testing, + // others can be similarly tested. + override onPoolAcquire(pool: oracledb.Pool): void { + expectType(pool); + } + override onPoolWait(pool: oracledb.Pool): void { + expectType(pool); + } + override onPoolConnectionMiss(pool: oracledb.Pool): void { + expectType(pool); + } + } + + defaultOracledb.traceHandler.setTraceInstance(new PoolTraceHandler()); + expectType(defaultOracledb.traceHandler.getTraceInstance()); + + // negative test + class InvalidPoolTraceHandler extends oracledb.traceHandler.TraceHandlerBase { + // @ts-expect-error + override onPoolClose(pool: string): void {} + } + + expectType(connection.pdbName); + expectType(connection.dbUniqueName); + + const appCtx: oracledb.AppContextKeyValue[] = [ + { traceCtx: "12" }, + { version: "1" }, + ]; + connection.appContext("CLIENTCONTEXT", appCtx); + connection.clearAppContext("CLIENTCONTEXT"); + // @ts-expect-error + connection.appContext("CLIENTCONTEXT", [{ traceCtx: 12 }]); + + // valid: IAM end-user token mode + const endUserSecurityContext = new oracledb.EndUserSecurityContext({ + databaseAccessToken: "db-access-token", + endUserToken: "end-user-token", + dataRoles: ["ANALYST_ROLE"], + attributes: { + department: "sales", + }, + }); + connection.setEndUserSecurityContext(endUserSecurityContext); + connection.clearEndUserSecurityContext(); + + // valid: database local user mode + const endUserSecurityContextByName = new oracledb.EndUserSecurityContext({ + databaseAccessToken: "db-access-token", + endUserName: "APP_USER", + key: "ctx-key", + }); + connection.setEndUserSecurityContext(endUserSecurityContextByName); + + // @ts-expect-error databaseAccessToken is required + new oracledb.EndUserSecurityContext({ + endUserToken: "end-user-token", + }); + // @ts-expect-error must specify either endUserToken or endUserName + key + new oracledb.EndUserSecurityContext({ + databaseAccessToken: "db-access-token", + }); + + // @ts-expect-error key is required when endUserName is set + new oracledb.EndUserSecurityContext({ + databaseAccessToken: "db-access-token", + endUserName: "APP_USER", + }); + + // @ts-expect-error endUserToken and endUserName are mutually exclusive + new oracledb.EndUserSecurityContext({ + databaseAccessToken: "db-access-token", + endUserToken: "end-user-token", + endUserName: "APP_USER", + key: "ctx-key", + }); + // @ts-expect-error key should not be set with endUserToken + new oracledb.EndUserSecurityContext({ + databaseAccessToken: "db-access-token", + endUserToken: "end-user-token", + key: "ctx-key", + }); + + const columns: oracledb.DirectPathLoadColumns = ["ID", "NAME"]; + const data: oracledb.DirectPathLoadData = [ + [1, "first"], + [2, "second"], + ]; + await connection.directPathLoad("TEST_SCHEMA", "TEST_TABLE", columns, data); + connection.directPathLoad("TEST_SCHEMA", "TEST_TABLE", columns, data, error => { + expectType(error); + }); + + const lob = await connection.createLob(oracledb.CLOB); + await lob.trim(); + await lob.trim(10); + lob.trim(error => { + expectType(error); + }); + lob.trim(10, error => { + expectType(error); + }); + + const pipeline = new oracledb.Pipeline(); + pipeline.addExecute("insert into test_table values (:1)", [1]); + pipeline.addExecuteMany("insert into test_table values (:1)", [[1], [2]]); + pipeline.addFetchAll("select * from test_table", [], { outFormat: oracledb.OUT_FORMAT_OBJECT }, 50, true); + pipeline.addFetchMany("select * from test_table", [], { outFormat: oracledb.OUT_FORMAT_OBJECT }, 10, false); + pipeline.addFetchOne( + "select * from test_table where id = :1", + [1], + { outFormat: oracledb.OUT_FORMAT_OBJECT }, + false, + ); + pipeline.addCommit(); + + const pipelineResults = await connection.runPipeline(pipeline, true); + expectType(pipelineResults); + connection.runPipeline(pipeline, (...args) => { + expectType<[oracledb.DBError] | [null, oracledb.PipelineOperationResult[]]>(args); + }); + connection.runPipeline(pipeline, true, (...args) => { + expectType<[oracledb.DBError] | [null, oracledb.PipelineOperationResult[]]>(args); + }); +}; diff --git a/types/oracledb/package.json b/types/oracledb/package.json index 5c42224cb97780..6bc0eb208140a3 100644 --- a/types/oracledb/package.json +++ b/types/oracledb/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/oracledb", - "version": "6.10.9999", + "version": "7.0.9999", "projects": [ "https://github.com/oracle/node-oracledb" ], diff --git a/types/oracledb/tsconfig.json b/types/oracledb/tsconfig.json index 0d5374decf12b9..1bf90f427427da 100644 --- a/types/oracledb/tsconfig.json +++ b/types/oracledb/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "module": "node16", "lib": [ - "es6" + "es6", + "esnext.disposable" ], "noImplicitAny": true, "noImplicitThis": true, From 5c25a26a6c6e95373a3d2561c15bc58ee1249594 Mon Sep 17 00:00:00 2001 From: Koutaro Mukai Date: Sat, 6 Jun 2026 06:25:05 +0900 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75069=20[yau?= =?UTF-8?q?zl]=20Update=20to=203.3;=20keep=202.x=20as=20v2=20by=20@u1f992?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/yauzl/.npmignore | 1 + types/yauzl/index.d.ts | 79 ++++++++++++++++++++--- types/yauzl/package.json | 2 +- types/yauzl/v2/.npmignore | 5 ++ types/yauzl/v2/index.d.ts | 110 ++++++++++++++++++++++++++++++++ types/yauzl/v2/package.json | 20 ++++++ types/yauzl/v2/tsconfig.json | 19 ++++++ types/yauzl/v2/yauzl-tests.ts | 30 +++++++++ types/yauzl/yauzl-tests.ts | 117 ++++++++++++++++++++++++++++++---- 9 files changed, 361 insertions(+), 22 deletions(-) create mode 100644 types/yauzl/v2/.npmignore create mode 100644 types/yauzl/v2/index.d.ts create mode 100644 types/yauzl/v2/package.json create mode 100644 types/yauzl/v2/tsconfig.json create mode 100644 types/yauzl/v2/yauzl-tests.ts diff --git a/types/yauzl/.npmignore b/types/yauzl/.npmignore index 93e307400a5456..d73cba2e3a91b8 100644 --- a/types/yauzl/.npmignore +++ b/types/yauzl/.npmignore @@ -3,3 +3,4 @@ !**/*.d.cts !**/*.d.mts !**/*.d.*.ts +/v2/ diff --git a/types/yauzl/index.d.ts b/types/yauzl/index.d.ts index e426fb62e46fd7..31a8fc4defa250 100644 --- a/types/yauzl/index.d.ts +++ b/types/yauzl/index.d.ts @@ -3,9 +3,14 @@ import { EventEmitter } from "events"; import { Readable } from "stream"; +export interface ExtraField { + id: number; + data: Buffer; +} + export abstract class RandomAccessReader extends EventEmitter { - _readStreamForRange(start: number, end: number): void; - createReadStream(options: { start: number; end: number }): void; + _readStreamForRange(start: number, end: number): Readable; + createReadStream(options: { start: number; end: number }): Readable; read(buffer: Buffer, offset: number, length: number, position: number, callback: (err: Error | null) => void): void; close(callback: (err: Error | null) => void): void; } @@ -17,10 +22,14 @@ export class Entry { crc32: number; externalFileAttributes: number; extraFieldLength: number; - extraFields: Array<{ id: number; data: Buffer }>; + extraFieldRaw: Buffer; + extraFields: ExtraField[]; + fileComment: string; fileCommentLength: number; + fileCommentRaw: Buffer; fileName: string; fileNameLength: number; + fileNameRaw: Buffer; generalPurposeBitFlag: number; internalFileAttributes: number; lastModFileDate: number; @@ -30,16 +39,42 @@ export class Entry { versionMadeBy: number; versionNeededToExtract: number; - getLastModDate(): Date; + getLastModDate(options?: GetLastModDateOptions): Date; + canDecodeFileData(): boolean; isEncrypted(): boolean; + /** @deprecated Use `canDecodeFileData()` and/or check `compressionMethod`. */ isCompressed(): boolean; } +export interface GetLastModDateOptions { + timezone?: "local" | "UTC" | null | undefined; + forceDosFormat?: boolean | undefined; +} + +export class LocalFileHeader { + fileDataStart: number; + versionNeededToExtract: number; + generalPurposeBitFlag: number; + compressionMethod: number; + lastModFileTime: number; + lastModFileDate: number; + crc32: number; + compressedSize: number; + uncompressedSize: number; + fileNameLength: number; + extraFieldLength: number; + fileName: Buffer; + extraField: Buffer; +} + export interface ZipFileOptions { - decompress: boolean | null; - decrypt: boolean | null; - start: number | null; - end: number | null; + decodeFileData?: boolean | null | undefined; + start?: number | null | undefined; + end?: number | null | undefined; + /** @deprecated */ + decompress?: boolean | null | undefined; + /** @deprecated */ + decrypt?: boolean | null | undefined; } export class ZipFile extends EventEmitter { @@ -73,6 +108,26 @@ export class ZipFile extends EventEmitter { callback: (err: Error | null, stream: Readable) => void, ): void; openReadStream(entry: Entry, callback: (err: Error | null, stream: Readable) => void): void; + readLocalFileHeader( + entry: Entry, + options: { minimal: true }, + callback: (err: Error | null, header: { fileDataStart: number }) => void, + ): void; + readLocalFileHeader( + entry: Entry, + options: { minimal?: boolean }, + callback: (err: Error | null, header: LocalFileHeader) => void, + ): void; + readLocalFileHeader(entry: Entry, callback: (err: Error | null, header: LocalFileHeader) => void): void; + openReadStreamLowLevel( + fileDataStart: number, + compressedSize: number, + relativeStart: number, + relativeEnd: number, + decompress: boolean, + uncompressedSize: number | null, + callback: (err: Error | null, stream: Readable) => void, + ): void; close(): void; readEntry(): void; } @@ -106,5 +161,13 @@ export function fromRandomAccessReader( totalSize: number, callback: (err: Error | null, zipfile: ZipFile) => void, ): void; +/** @deprecated Use `entry.getLastModDate()` instead. */ export function dosDateTimeToDate(date: number, time: number): Date; export function validateFileName(fileName: string): string | null; +export function getFileNameLowLevel( + generalPurposeBitFlag: number, + fileNameBuffer: Buffer, + extraFields: ExtraField[], + strictFileNames: boolean, +): string; +export function parseExtraFields(extraFieldBuffer: Buffer): ExtraField[]; diff --git a/types/yauzl/package.json b/types/yauzl/package.json index 89a380bdfca311..bac6fe251c4a07 100644 --- a/types/yauzl/package.json +++ b/types/yauzl/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/yauzl", - "version": "2.10.9999", + "version": "3.3.9999", "projects": [ "https://github.com/thejoshwolfe/yauzl" ], diff --git a/types/yauzl/v2/.npmignore b/types/yauzl/v2/.npmignore new file mode 100644 index 00000000000000..93e307400a5456 --- /dev/null +++ b/types/yauzl/v2/.npmignore @@ -0,0 +1,5 @@ +* +!**/*.d.ts +!**/*.d.cts +!**/*.d.mts +!**/*.d.*.ts diff --git a/types/yauzl/v2/index.d.ts b/types/yauzl/v2/index.d.ts new file mode 100644 index 00000000000000..e426fb62e46fd7 --- /dev/null +++ b/types/yauzl/v2/index.d.ts @@ -0,0 +1,110 @@ +/// + +import { EventEmitter } from "events"; +import { Readable } from "stream"; + +export abstract class RandomAccessReader extends EventEmitter { + _readStreamForRange(start: number, end: number): void; + createReadStream(options: { start: number; end: number }): void; + read(buffer: Buffer, offset: number, length: number, position: number, callback: (err: Error | null) => void): void; + close(callback: (err: Error | null) => void): void; +} + +export class Entry { + comment: string; + compressedSize: number; + compressionMethod: number; + crc32: number; + externalFileAttributes: number; + extraFieldLength: number; + extraFields: Array<{ id: number; data: Buffer }>; + fileCommentLength: number; + fileName: string; + fileNameLength: number; + generalPurposeBitFlag: number; + internalFileAttributes: number; + lastModFileDate: number; + lastModFileTime: number; + relativeOffsetOfLocalHeader: number; + uncompressedSize: number; + versionMadeBy: number; + versionNeededToExtract: number; + + getLastModDate(): Date; + isEncrypted(): boolean; + isCompressed(): boolean; +} + +export interface ZipFileOptions { + decompress: boolean | null; + decrypt: boolean | null; + start: number | null; + end: number | null; +} + +export class ZipFile extends EventEmitter { + autoClose: boolean; + comment: string; + decodeStrings: boolean; + emittedError: boolean; + entriesRead: number; + entryCount: number; + fileSize: number; + isOpen: boolean; + lazyEntries: boolean; + readEntryCursor: boolean; + validateEntrySizes: boolean; + + constructor( + reader: RandomAccessReader, + centralDirectoryOffset: number, + fileSize: number, + entryCount: number, + comment: string, + autoClose: boolean, + lazyEntries: boolean, + decodeStrings: boolean, + validateEntrySizes: boolean, + ); + + openReadStream( + entry: Entry, + options: ZipFileOptions, + callback: (err: Error | null, stream: Readable) => void, + ): void; + openReadStream(entry: Entry, callback: (err: Error | null, stream: Readable) => void): void; + close(): void; + readEntry(): void; +} + +export interface Options { + autoClose?: boolean | undefined; + lazyEntries?: boolean | undefined; + decodeStrings?: boolean | undefined; + validateEntrySizes?: boolean | undefined; + strictFileNames?: boolean | undefined; +} + +export function open(path: string, options: Options, callback?: (err: Error | null, zipfile: ZipFile) => void): void; +export function open(path: string, callback?: (err: Error | null, zipfile: ZipFile) => void): void; +export function fromFd(fd: number, options: Options, callback?: (err: Error | null, zipfile: ZipFile) => void): void; +export function fromFd(fd: number, callback?: (err: Error | null, zipfile: ZipFile) => void): void; +export function fromBuffer( + buffer: Buffer, + options: Options, + callback?: (err: Error | null, zipfile: ZipFile) => void, +): void; +export function fromBuffer(buffer: Buffer, callback?: (err: Error | null, zipfile: ZipFile) => void): void; +export function fromRandomAccessReader( + reader: RandomAccessReader, + totalSize: number, + options: Options, + callback: (err: Error | null, zipfile: ZipFile) => void, +): void; +export function fromRandomAccessReader( + reader: RandomAccessReader, + totalSize: number, + callback: (err: Error | null, zipfile: ZipFile) => void, +): void; +export function dosDateTimeToDate(date: number, time: number): Date; +export function validateFileName(fileName: string): string | null; diff --git a/types/yauzl/v2/package.json b/types/yauzl/v2/package.json new file mode 100644 index 00000000000000..89a380bdfca311 --- /dev/null +++ b/types/yauzl/v2/package.json @@ -0,0 +1,20 @@ +{ + "private": true, + "name": "@types/yauzl", + "version": "2.10.9999", + "projects": [ + "https://github.com/thejoshwolfe/yauzl" + ], + "dependencies": { + "@types/node": "*" + }, + "devDependencies": { + "@types/yauzl": "workspace:." + }, + "owners": [ + { + "name": "Florian Keller", + "githubUsername": "ffflorian" + } + ] +} diff --git a/types/yauzl/v2/tsconfig.json b/types/yauzl/v2/tsconfig.json new file mode 100644 index 00000000000000..d287e4dfc369a7 --- /dev/null +++ b/types/yauzl/v2/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "node16", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "yauzl-tests.ts" + ] +} diff --git a/types/yauzl/v2/yauzl-tests.ts b/types/yauzl/v2/yauzl-tests.ts new file mode 100644 index 00000000000000..79e02fdeb2dc08 --- /dev/null +++ b/types/yauzl/v2/yauzl-tests.ts @@ -0,0 +1,30 @@ +import { Writable } from "stream"; +import * as yauzl from "yauzl"; + +yauzl.open("path/to/file.zip", { lazyEntries: true }, (err, zipfile) => { + if (err) { + throw err; + } + if (zipfile) { + zipfile.readEntry(); + zipfile.on("entry", entry => { + if (/\/$/.test(entry.fileName)) { + zipfile.readEntry(); + } else { + zipfile.openReadStream(entry, (err, readStream) => { + if (err) { + throw err; + } + if (readStream) { + readStream.on("end", () => { + zipfile.readEntry(); + }); + readStream.pipe(new Writable()); + } + }); + } + }); + } +}); + +yauzl.open("options.zip", { strictFileNames: true }, () => {}); diff --git a/types/yauzl/yauzl-tests.ts b/types/yauzl/yauzl-tests.ts index 79e02fdeb2dc08..988000feff4c7e 100644 --- a/types/yauzl/yauzl-tests.ts +++ b/types/yauzl/yauzl-tests.ts @@ -1,4 +1,4 @@ -import { Writable } from "stream"; +import { Readable, Writable } from "stream"; import * as yauzl from "yauzl"; yauzl.open("path/to/file.zip", { lazyEntries: true }, (err, zipfile) => { @@ -7,24 +7,115 @@ yauzl.open("path/to/file.zip", { lazyEntries: true }, (err, zipfile) => { } if (zipfile) { zipfile.readEntry(); - zipfile.on("entry", entry => { - if (/\/$/.test(entry.fileName)) { + zipfile.on("entry", (entry: yauzl.Entry) => { + // String and number metadata. + const name: string = entry.fileName; + const comment: string = entry.fileComment; + const aliased: string = entry.comment; + const mode: number = entry.externalFileAttributes; + const madeBy: number = entry.versionMadeBy; + + // Raw, undecoded buffers. + const nameRaw: Buffer = entry.fileNameRaw; + const extraRaw: Buffer = entry.extraFieldRaw; + const commentRaw: Buffer = entry.fileCommentRaw; + + // Parsed extra fields. + const fields: yauzl.ExtraField[] = entry.extraFields; + const firstId: number | undefined = fields[0]?.id; + const firstData: Buffer | undefined = fields[0]?.data; + + // Timestamps. + const localDate: Date = entry.getLastModDate(); + const utcDate: Date = entry.getLastModDate({ timezone: "UTC" }); + const dosDate: Date = entry.getLastModDate({ forceDosFormat: true }); + + // Predicates. + const decodable: boolean = entry.canDecodeFileData(); + const encrypted: boolean = entry.isEncrypted(); + const compressed: boolean = entry.isCompressed(); + + if ( + /\/$/.test(name) || mode + madeBy + (firstId ?? 0) < 0 + || aliased.length + comment.length + nameRaw.length + extraRaw.length + commentRaw.length < 0 + || localDate < utcDate || dosDate < localDate || (firstData?.length ?? 0) < 0 + ) { zipfile.readEntry(); + } else if (!decodable || encrypted || compressed) { + // Reading raw bytes of a range. + zipfile.openReadStream( + entry, + { decodeFileData: false, start: 0, end: entry.compressedSize }, + (streamErr, readStream) => { + if (streamErr) throw streamErr; + readStream.on("end", () => zipfile.readEntry()).pipe(new Writable()); + }, + ); } else { - zipfile.openReadStream(entry, (err, readStream) => { - if (err) { - throw err; - } - if (readStream) { - readStream.on("end", () => { - zipfile.readEntry(); - }); - readStream.pipe(new Writable()); - } + zipfile.openReadStream(entry, (streamErr, readStream: Readable) => { + if (streamErr) throw streamErr; + readStream.on("end", () => zipfile.readEntry()).pipe(new Writable()); }); } + + // Low-level header and stream APIs. + zipfile.readLocalFileHeader(entry, { minimal: true }, (headerErr, header) => { + if (headerErr) throw headerErr; + const start: number = header.fileDataStart; + zipfile.openReadStreamLowLevel( + start, + entry.compressedSize, + 0, + entry.compressedSize, + true, + entry.uncompressedSize, + (lowErr, lowStream: Readable) => { + if (lowErr) throw lowErr; + lowStream.pipe(new Writable()); + }, + ); + }); + + zipfile.readLocalFileHeader(entry, (headerErr, header: yauzl.LocalFileHeader) => { + if (headerErr) throw headerErr; + const rawName: Buffer = header.fileName; + const rawExtra: Buffer = header.extraField; + yauzl.parseExtraFields(rawExtra); + yauzl.getFileNameLowLevel(header.generalPurposeBitFlag, rawName, [], false); + if (header.fileDataStart < 0) throw new Error("unreachable"); + }); }); + + zipfile.on("end", () => {}); + zipfile.on("error", () => {}); + zipfile.on("close", () => {}); + + const open: boolean = zipfile.isOpen; + const count: number = zipfile.entryCount; + if (open && count >= 0) zipfile.close(); } }); yauzl.open("options.zip", { strictFileNames: true }, () => {}); +yauzl.open("no-options.zip", () => {}); + +yauzl.fromBuffer(Buffer.alloc(0), { lazyEntries: true }, () => {}); +yauzl.fromFd(0, () => {}); + +// Subclassing RandomAccessReader for fromRandomAccessReader(). +class MemoryReader extends yauzl.RandomAccessReader { + _readStreamForRange(start: number, end: number): Readable { + return Readable.from(Buffer.alloc(end - start)); + } +} +yauzl.fromRandomAccessReader(new MemoryReader(), 1024, { lazyEntries: true }, () => {}); + +// Standalone helpers. +const nameError: string | null = yauzl.validateFileName("a/b/c.txt"); +if (nameError != null) throw new Error(nameError); +const fromDos: Date = yauzl.dosDateTimeToDate(0, 0); +if (fromDos.getTime() < 0) throw new Error("unreachable"); + +const decodedName: string = yauzl.getFileNameLowLevel(0x800, Buffer.from("a.txt"), [], true); +const parsed: yauzl.ExtraField[] = yauzl.parseExtraFields(Buffer.alloc(0)); +if (decodedName.length < 0 || parsed.length < 0) throw new Error("unreachable"); From bd15be7af1d458d0d0cd7a40d3b32e89ff3d029d Mon Sep 17 00:00:00 2001 From: daberni Date: Fri, 5 Jun 2026 23:37:25 +0200 Subject: [PATCH 10/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74972=20[fan?= =?UTF-8?q?cytree]=20include=20missing=20type=20declarations=20from=20sour?= =?UTF-8?q?ce=20by=20@daberni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 4.8 (1M context) --- types/jquery.fancytree/index.d.ts | 394 ++++++++++++++---- .../jquery.fancytree-tests.ts | 167 +++++++- types/jquery.fancytree/package.json | 2 +- 3 files changed, 465 insertions(+), 98 deletions(-) diff --git a/types/jquery.fancytree/index.d.ts b/types/jquery.fancytree/index.d.ts index ab58c76c45ac34..e0ea48732a2594 100644 --- a/types/jquery.fancytree/index.d.ts +++ b/types/jquery.fancytree/index.d.ts @@ -8,14 +8,27 @@ declare namespace JQueryUI { } interface JQuery { - fancytree(options?: Fancytree.FancytreeOptions): Fancytree.Fancytree; - fancytree(option?: string, ...rest: any[]): any; + fancytree(options?: Fancytree.FancytreeOptions): JQuery; + fancytree(option: "getTree"): Fancytree.Fancytree; + fancytree(option: "getActiveNode"): Fancytree.FancytreeNode | null; + fancytree(option: "getRootNode"): Fancytree.FancytreeNode; + fancytree(option: "getNodeByKey", key: string): Fancytree.FancytreeNode | null; + fancytree(option: "option", name: K): Fancytree.FancytreeOptions[K]; + fancytree( + option: "option", + name: K, + value: Fancytree.FancytreeOptions[K], + ): JQuery; + fancytree(option: "option", name: string): unknown; + fancytree(option: "option", name: string, value: unknown): JQuery; + fancytree(option: "enable" | "disable" | "destroy" | "clear"): JQuery; + fancytree(option?: string, ...rest: unknown[]): unknown; } declare namespace Fancytree { interface Fancytree { $div: JQuery; - widget: any; // JQueryUI.Widget; + widget: JQueryUI.Widget; rootNode: FancytreeNode; $container: JQuery; focusNode: FancytreeNode; @@ -35,14 +48,26 @@ declare namespace Fancytree { * * @returns resolved, when all patches have been applied */ - applyPatch(patchList: NodePatch[]): JQueryPromise; + applyPatch(patchList: NodePatch[]): JQueryPromise; /** [ext-clones] Replace a refKey with a new one. */ changeRefKey(oldRefKey: string, newRefKey: string): void; + /** Add paging status node. */ + addPagingNode(node?: NodeData | false, mode?: string): FancytreeNode | undefined; + + /** Apply command to tree (and optionally node). */ + applyCommand(cmd: string, node?: FancytreeNode, opts?: unknown): unknown; + + /** Remove all nodes. */ + clear(source?: unknown): void; + /** [ext-persist] Remove persistence cookies of the given type(s). - * Called like $("#tree").fancytree("getTree").clearCookies("active expanded focus selected"); */ - clearCookies(): void; + * Called like $("#tree").fancytree("getTree").clearCookies("active expanded focus selected"); + * @deprecated since v2.27, use clearPersistData() */ + clearCookies(types?: PersistTypeSpec): void; + /** [ext-persist] Remove persistence data of the given type(s). */ + clearPersistData(types?: PersistTypeSpec): void; /** [ext-filter] Reset the filter. */ clearFilter(): void; @@ -50,8 +75,14 @@ declare namespace Fancytree { /** Return the number of nodes. */ count(): number; + /** Destroy this widget and cleanup resources. */ + destroy(): void; + + /** Enable (or disable) the tree control. */ + enable(flag?: boolean): void; + /** Write to browser console if debugLevel >= 2 (prepending tree name) */ - debug(msg: any): void; + debug(msg: unknown): void; /** Expand (or collapse) all parent nodes. */ expandAll(flag?: boolean, options?: Object): void; @@ -80,13 +111,13 @@ declare namespace Fancytree { * * @returns matching node or null */ - findNextNode(match: string, startNode?: FancytreeNode): FancytreeNode; + findNextNode(match: string, startNode?: FancytreeNode): FancytreeNode | null; /** Find the next visible node that starts with `match`, starting at `startNode` and wrap-around at the end. * * @returns matching node or null */ - findNextNode(match: (node: FancytreeNode) => boolean, startNode?: FancytreeNode): FancytreeNode; + findNextNode(match: (node: FancytreeNode) => boolean, startNode?: FancytreeNode): FancytreeNode | null; /** Find all nodes that matches condition. * @@ -94,26 +125,36 @@ declare namespace Fancytree { */ findAll(match: string | ((node: FancytreeNode) => boolean | undefined)): FancytreeNode[]; + /** Find first node that matches condition. */ + findFirst(match: string | ((node: FancytreeNode) => boolean | undefined)): FancytreeNode | null; + + /** Find a node relative to another node. */ + findRelatedNode(node: FancytreeNode, where: string | number, includeHidden?: boolean): FancytreeNode | null; + /** Generate INPUT elements that can be submitted with html forms. In selectMode 3 only the topmost selected nodes are considered. */ - generateFormElements(selected?: boolean, active?: boolean): void; + generateFormElements(selected?: boolean | string, active?: boolean | string, opts?: unknown): void; /** Return the currently active node or null. */ - getActiveNode(): FancytreeNode; + getActiveNode(): FancytreeNode | null; /** Return the first top level node if any (not the invisible root node). */ - getFirstChild(): FancytreeNode; + getFirstChild(): FancytreeNode | null; /** Return node that has keyboard focus. * * @param ifTreeHasFocus (default: false) (not yet implemented) */ - getFocusNode(ifTreeHasFocus?: boolean): FancytreeNode; + getFocusNode(ifTreeHasFocus?: boolean): FancytreeNode | null; + + /** Return current option value. */ + getOption(optionName: K): FancytreeOptions[K]; + getOption(optionName: string): unknown; /** Return node with a given key or null if not found. * * @param searchRoot (optional) only search below this node. */ - getNodeByKey(key: string, searchRoot?: FancytreeNode): FancytreeNode; + getNodeByKey(key: string, searchRoot?: FancytreeNode): FancytreeNode | null; /** [ext-clones] Return all nodes with a given refKey (null if not found). * @@ -137,33 +178,49 @@ declare namespace Fancytree { hasFocus(): boolean; /** Write to browser console if debugLevel >= 1 (prepending tree name) */ - info(msg: any): void; + info(msg: unknown): void; + + /** Write error to browser console if debugLevel >= 1 (prepending tree info). */ + error(msg: unknown): void; /** [ext-edit] Check if any node in this tree in edit mode. */ - isEditing(): FancytreeNode; + isEditing(): boolean; + + /** Return true if any node is currently being loaded. */ + isLoading(): boolean; /** Make sure that a node with a given ID is loaded, by traversing - and loading - its parents. This method is ment for lazy hierarchies. A callback is executed for every node as we go. * * @param keyPathList one or more key paths (e.g. '/3/2_1/7') * @param callback callback(node, status) is called for every visited node ('loading', 'loaded', 'ok', 'error') */ - loadKeyPath(keyPathList: string[], callback: (node: FancytreeNode, status: string) => void): JQueryPromise; + loadKeyPath( + keyPathList: string[], + callback: (node: FancytreeNode, status: string) => void, + ): JQueryPromise; /** Make sure that a node with a given ID is loaded, by traversing - and loading - its parents. This method is ment for lazy hierarchies. A callback is executed for every node as we go. * * @param keyPath a key path (e.g. '/3/2_1/7') * @param callback callback(node, status) is called for every visited node ('loading', 'loaded', 'ok', 'error') */ - loadKeyPath(keyPath: string, callback: (node: FancytreeNode, status: string) => void): JQueryPromise; + loadKeyPath(keyPath: string, callback: (node: FancytreeNode, status: string) => void): JQueryPromise; + loadKeyPath( + keyPathList: string | string[], + opts: { + callback?: (node: FancytreeNode, status: string) => void; + matchKey?: (node: FancytreeNode, key: string) => boolean; + }, + ): JQueryPromise; /** Re-fire beforeActivate and activate events. */ - reactivate(): void; + reactivate(setFocus?: boolean): JQueryPromise; /** Reload tree from source and return a promise. * * @param source optional new source (defaults to initial source data) */ - reload(source?: any): JQueryPromise; + reload(source?: unknown): JQueryPromise; /** Render tree (i.e. create DOM elements for all top-level nodes). * @@ -172,32 +229,53 @@ declare namespace Fancytree { */ render(force?: boolean, deep?: boolean): void; + /** Select or deselect all nodes. */ + selectAll(flag?: boolean): void; + /** @param flag (default = true) */ setFocus(flag?: boolean): void; + /** Set current option value. */ + setOption(optionName: K, value: FancytreeOptions[K]): FancytreeOptions[K]; + setOption(optionName: string, value: unknown): unknown; + + /** Call console.time() in verbose debug mode. */ + debugTime(label: string): void; + + /** Call console.timeEnd() in verbose debug mode. */ + debugTimeEnd(label: string): void; + /** Return all nodes as nested list of NodeData. * * @param callback Called for every node * @param includeRoot Returns the hidden system root node (and its children) (default = false) */ - toDict(includeRoot?: boolean, callback?: (node: FancytreeNode) => void): any; + toDict(includeRoot?: boolean, callback?: (node: FancytreeNode) => void): unknown; /** Call fn(node) for all nodes. * * @param fn the callback function. Return false to stop iteration, return "skip" to skip this node and children only. * @returns false, if the iterator was stopped. */ - visit(fn: (node: FancytreeNode) => any): boolean; + visit(fn: (node: FancytreeNode) => void): boolean; + visit(fn: (node: FancytreeNode) => boolean | "skip"): boolean; /** Write warning to browser console (prepending tree info) */ - warn(msg: any): void; + warn(msg: unknown): void; + + /** String representation. */ + toString(): string; /** Temporarily suppress rendering to improve performance on bulk-updates. * * @param {boolean} flag * @returns {boolean} previous status * @since 2.19 */ - enableUpdate(enabled: boolean): void; + enableUpdate(enabled: boolean): boolean; + + /** Call fn(node) for all visible nodes in vertical order. */ + visitRows(fn: (node: FancytreeNode) => void, opts?: unknown): boolean; + visitRows(fn: (node: FancytreeNode) => boolean | "skip", opts?: unknown): boolean; } /** A FancytreeNode represents the hierarchical data model and operations. */ @@ -212,7 +290,7 @@ declare namespace Fancytree { /** Display name (may contain HTML) */ title: string; /** Contains all extra data that was passed on node creation */ - data: any; + data: unknown; /** Array of child nodes. For lazy nodes, null or undefined means 'not yet loaded'. Use an empty array to define a node that has no children. */ children: FancytreeNode[]; /** Use isExpanded(), setExpanded() to access this property. */ @@ -301,11 +379,20 @@ declare namespace Fancytree { */ addNode(node: NodeData, mode?: string): FancytreeNode; + /** Add paging status node below this node. */ + addPagingNode(node?: NodeData | false, mode?: string): FancytreeNode | undefined; + + /** Apply command relative to this node. */ + applyCommand(cmd: string, opts?: unknown): unknown; + + /** Append this node as sibling after current node. */ + appendSibling(node: NodeData): FancytreeNode; + /** Modify existing child nodes. */ - applyPatch(patch: NodePatch): JQueryPromise; + applyPatch(patch: NodePatch): JQueryPromise; /** Collapse all sibling nodes. */ - collapseSiblings(): JQueryPromise; + collapseSiblings(): JQueryPromise; /** Copy this node as sibling or child of `node`. * @@ -323,7 +410,7 @@ declare namespace Fancytree { countChildren(deep?: boolean): number; /** Write to browser console if debugLevel >= 2 (prepending node info) */ - debug(msg: any): void; + debug(msg: unknown): void; /** [ext-edit] Create a new child or sibling node and start edit mode. * @@ -357,13 +444,13 @@ declare namespace Fancytree { * * @param match string to search for */ - findFirst(match: string): FancytreeNode; + findFirst(match: string): FancytreeNode | null; /** Find first node that contains `match` in the title (not including self). * * @param match a function that returns `true` if a node is matched. */ - findFirst(match: (node: FancytreeNode) => boolean): FancytreeNode; + findFirst(match: (node: FancytreeNode) => boolean): FancytreeNode | null; /** Fix selection status, after this node was (de)selected in multi-hier mode. This includes (de)selecting all children. */ fixSelection3AfterClick(): void; @@ -375,13 +462,13 @@ declare namespace Fancytree { fromDict(dict: NodeData): void; /** Return the list of child nodes (undefined for unexpanded lazy nodes). */ - getChildren(): FancytreeNode[]; + getChildren(): FancytreeNode[] | undefined; /** [ext-clones] Return a list of clone-nodes or null. */ - getCloneList(includeSelf?: boolean): FancytreeNode[]; + getCloneList(includeSelf?: boolean): FancytreeNode[] | null; /** Return the first child node or null. */ - getFirstChild(): FancytreeNode; + getFirstChild(): FancytreeNode | null; /** Return the 0-based child index. */ getIndex(): number; @@ -393,16 +480,16 @@ declare namespace Fancytree { getKeyPath(excludeSelf: boolean): string; /** Return the last child of this node or null. */ - getLastChild(): FancytreeNode; + getLastChild(): FancytreeNode | null; /** Return node depth. 0: System root node, 1: visible top-level node, 2: first sub-level, ... . */ getLevel(): number; /** Return the successor node (under the same parent) or null. */ - getNextSibling(): FancytreeNode; + getNextSibling(): FancytreeNode | null; /** Return the parent node (null for the system root node). */ - getParent(): FancytreeNode; + getParent(): FancytreeNode | null; /** Return an array of all parent nodes (top-down). * @@ -411,15 +498,24 @@ declare namespace Fancytree { */ getParentList(includeRoot: boolean, includeSelf: boolean): FancytreeNode[]; + /** Return path string, e.g. "Folder/Subfolder/Node". */ + getPath(includeSelf?: boolean, part?: string | ((node: FancytreeNode) => string), separator?: string): string; + /** Return the predecessor node (under the same parent) or null. */ - getPrevSibling(): FancytreeNode; + getPrevSibling(): FancytreeNode | null; + + /** Return selected nodes below this node. */ + getSelectedNodes(stopOnParents?: boolean): FancytreeNode[]; /** Return true if node has children. Return undefined if not sure, i.e. the node is lazy and not yet loaded). */ - hasChildren(): boolean; + hasChildren(): boolean | undefined; /** Return true if node has keyboard focus. */ hasFocus(): boolean; + /** Return true if node has class. */ + hasClass(className: string): boolean; + /** Write to browser console if debugLevel >= 1 (prepending node info) */ info(msg: string): void; @@ -429,6 +525,9 @@ declare namespace Fancytree { /** Return true if node is a direct child of otherNode. */ isChildOf(otherNode: FancytreeNode): boolean; + /** Return true if this node is rendered below `otherNode`. */ + isBelowOf(otherNode: FancytreeNode): boolean; + /** [ext-clones] Return true if this node has at least another clone with same refKey. */ isClone(): boolean; @@ -459,6 +558,18 @@ declare namespace Fancytree { /**Return true if children are currently beeing loaded, i.e. a Ajax request is pending. */ isLoading(): boolean; + /** Return true if this is a paging status node. */ + isPagingNode(): boolean; + + /** Return true if node is partially loaded. */ + isPartload(): boolean; + + /** Return true if node is partially selected. */ + isPartsel(): boolean; + + /** Return true if this is the (invisible) system root node. */ + isRoot(): boolean; + /** Return true if this is the (invisible) system root node. */ isRootNode(): boolean; @@ -481,13 +592,16 @@ declare namespace Fancytree { * * @param forceReload Pass true to discard any existing nodes before. */ - load(forceReload?: boolean): JQueryPromise; + load(forceReload?: boolean): JQueryPromise; + + /** @deprecated Deprecated alias for load(). */ + lazyLoad(discard?: boolean): void; /** Expand all parents and optionally scroll into visible area as neccessary. Promise is resolved, when lazy loading and animations are done. * * @param opts passed to `setExpanded()`. Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true} */ - makeVisible(opts?: Object): JQueryPromise; + makeVisible(opts?: Object): JQueryPromise; /** Move this node to targetNode. * @@ -506,7 +620,7 @@ declare namespace Fancytree { * @param where The keyCode that would normally trigger this move, e.g. `$.ui.keyCode.LEFT` would collapse the node if it is expanded or move to the parent oterwise. * @param activate (default=true) */ - navigate(where: number, activate?: boolean): JQueryPromise; + navigate(where: number, activate?: boolean): JQueryPromise; /** Remove this node (not allowed for system root). */ remove(): void; @@ -524,6 +638,9 @@ declare namespace Fancytree { */ removeClass(className: string): void; + /** Replace this paging node with source result. */ + replaceWith(source: NodeData | NodeData[]): JQueryPromise; + /** This method renders and updates all HTML markup that is required to display this node in its current state. * * @param force re-render, even if html markup was already created @@ -543,6 +660,12 @@ declare namespace Fancytree { /** Remove all children, collapse, and set the lazy-flag, so that the lazyLoad event is triggered on next expand. */ resetLazy(): void; + /** @deprecated Deprecated alias for resetLazy(). */ + discard(): void; + + /** Remove HTML markup for this node or children. */ + discardMarkup(includeSelf?: boolean): void; + /** Schedule activity for delayed execution (cancel any pending request). scheduleAction('cancel') will only cancel a pending request (if any). */ scheduleAction(mode: string, ms: number): void; @@ -550,25 +673,25 @@ declare namespace Fancytree { * @param effects animation options. * @param options {topNode: null, effects: ..., parent: ...} this node will remain visible in any case, even if `this` is outside the scroll pane. */ - scrollIntoView(effects?: boolean, options?: Object): JQueryPromise; + scrollIntoView(effects?: boolean, options?: Object): JQueryPromise; /** * @param effects animation options. * @param options {topNode: null, effects: ..., parent: ...} this node will remain visible in any case, even if `this` is outside the scroll pane. */ - scrollIntoView(effects?: Object, options?: Object): JQueryPromise; + scrollIntoView(effects?: Object, options?: Object): JQueryPromise; /** * @param flag pass false to deactivate * @param opts additional options. Defaults to {noEvents: false} */ - setActive(flag?: boolean, opts?: Object): JQueryPromise; + setActive(flag?: boolean, opts?: Object): JQueryPromise; /** * @param flag pass false to collapse. * @param opts additional options. Defaults to {noAnimation:false, noEvents:false} */ - setExpanded(flag?: boolean, opts?: Object): JQueryPromise; + setExpanded(flag?: boolean, opts?: Object): JQueryPromise; /** * Set keyboard focus to this node. @@ -631,7 +754,8 @@ declare namespace Fancytree { * @param fn the callback function. Return false to stop iteration, return "skip" to skip this node and its children only. * @param includeSelf (default=false) */ - visit(fn: (node: FancytreeNode) => any, includeSelf?: boolean): boolean; + visit(fn: (node: FancytreeNode) => void, includeSelf?: boolean): boolean; + visit(fn: (node: FancytreeNode) => boolean | "skip", includeSelf?: boolean): boolean; /** * Call fn(node) for all child nodes and recursively load lazy children. @@ -641,7 +765,8 @@ declare namespace Fancytree { * @param fn the callback function. Return false to stop iteration, return "skip" to skip this node and its children only. * @param includeSelf (default=false) */ - visitAndLoad(fn: (node: FancytreeNode) => any, includeSelf?: boolean): JQueryPromise; + visitAndLoad(fn: (node: FancytreeNode) => void, includeSelf?: boolean): JQueryPromise; + visitAndLoad(fn: (node: FancytreeNode) => boolean | "skip", includeSelf?: boolean): JQueryPromise; /** * Call fn(node) for all parent nodes, bottom-up, including invisible system root. @@ -651,12 +776,32 @@ declare namespace Fancytree { * @param fn the callback function. Return false to stop iteration, return "skip" to skip this node and its children only. * @param includeSelf (default=false) */ - visitParents(fn: (node: FancytreeNode) => any, includeSelf?: boolean): boolean; + visitParents(fn: (node: FancytreeNode) => void, includeSelf?: boolean): boolean; + visitParents(fn: (node: FancytreeNode) => boolean | "skip", includeSelf?: boolean): boolean; + + /** Visit siblings under same parent. */ + visitSiblings(fn: (node: FancytreeNode) => void, includeSelf?: boolean): boolean; + visitSiblings(fn: (node: FancytreeNode) => boolean | "skip", includeSelf?: boolean): boolean; /** * Write warning to browser console (prepending node info) */ - warn(msg: any): void; + warn(msg: unknown): void; + + /** Write error to browser console if debugLevel >= 1 (prepending node info). */ + error(msg: unknown): void; + + /** Find related node from this node. */ + findRelatedNode(where: string | number, includeHidden?: boolean): FancytreeNode | null; + + /** Trigger modifyChild event on this node. */ + triggerModifyChild(operation: string, childNode?: FancytreeNode, extra?: unknown): void; + + /** Trigger modifyChild event on parent node. */ + triggerModify(operation: string, extra?: unknown): void; + + /** String representation. */ + toString(): string; // #endregion } @@ -673,12 +818,14 @@ declare namespace Fancytree { mutlti_hier = 3, } - /** Context object passed to events and hook functions. */ - interface EventData { + type EventTargetType = "title" | "prefix" | "expander" | "checkbox" | "icon"; + + /** Common context object passed to events and hook functions. */ + interface BaseEventData { /** The tree instance */ tree: Fancytree; /** The jQuery UI tree widget */ - widget: any; // JQueryUI.Widget; + widget: JQueryUI.Widget; /** Shortcut to tree.options */ options: FancytreeOptions; /** The jQuery Event that initially triggered this call */ @@ -687,11 +834,37 @@ declare namespace Fancytree { node: FancytreeNode; /** (output parameter) Event handlers can return values back to the * caller. Used by `lazyLoad`, `postProcess`, ... */ - result: any; + result?: unknown; + } + + /** Context object passed to events and hook functions. */ + interface EventData extends BaseEventData { /** (only for click and dblclick events) 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' */ - targetType: string; + targetType?: EventTargetType; + /** (only for modifyChild event) Child operation: 'add', 'remove', 'move', ... */ + operation?: string; + /** (only for modifyChild event) Child node that changed, if any. */ + childNode?: FancytreeNode | null; /** (only for postProcess event) Original ajax response */ - response: any; + response?: unknown; + } + + interface ClickEventData extends BaseEventData { + targetType: EventTargetType; + } + + interface ModifyChildEventData extends BaseEventData { + operation: string; + childNode: FancytreeNode | null; + } + + interface PostProcessEventData extends BaseEventData { + response: unknown; + result: unknown; + } + + interface LazyLoadEventData extends BaseEventData { + result: unknown; } /** The `this` context of any event function is set to tree's the HTMLDivElement */ @@ -709,15 +882,17 @@ declare namespace Fancytree { /** `data.tree` lost keyboard focus */ blurTree?(event: JQueryEventObject, data: EventData): void; /** `data.node` was clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. activating, etc. */ - click?(event: JQueryEventObject, data: EventData): boolean; + click?(event: JQueryEventObject, data: ClickEventData): boolean; /** `data.node` was collapsed */ collapse?(event: JQueryEventObject, data: EventData): void; /** Widget was created (called only once, even if re-initialized). */ create?(event: JQueryEventObject, data: EventData): void; + /** `data.node` is a paging node that was clicked. Return `false` to prevent default processing. */ + clickPaging?(event: JQueryEventObject, data: ClickEventData): boolean; /** Allow tweaking and binding, after node was created for the first time (NOTE: this event is only available as callback, but not for bind()) */ createNode?(event: JQueryEventObject, data: EventData): void; /** `data.node` was double-clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. expanding, etc. */ - dblclick?(event: JQueryEventObject, data: EventData): boolean; + dblclick?(event: JQueryEventObject, data: ClickEventData): boolean; /** `data.node` was deactivated */ deactivate?(event: JQueryEventObject, data: EventData): void; /** `data.node` was expanded */ @@ -733,14 +908,17 @@ declare namespace Fancytree { /** (currently unused) */ keypress?(event: JQueryEventObject, data: EventData): void; /** `data.node` is a lazy node that is expanded for the first time. The new child data must be returned in the `data.result` property (see `source` option for available formats). */ - lazyLoad?(event: JQueryEventObject, data: EventData): void; + lazyLoad?(event: JQueryEventObject, data: LazyLoadEventData): void; /** Node data was loaded, i.e. `node.nodeLoadChildren()` finished */ loadChildren?(event: JQueryEventObject, data: EventData): void; /** A load error occured. Return `false` to prevent default processing. */ loadError?(event: JQueryEventObject, data: EventData): boolean; + /** Child was added, removed, moved, etc. */ + modifyChild?(event: JQueryEventObject, data: ModifyChildEventData): void; /** Allows to modify the ajax response. */ - postProcess?(event: JQueryEventObject, data: EventData): void; - /** `data.node` was removed (NOTE: this event is only available as callback, but not for bind()) */ + postProcess?(event: JQueryEventObject, data: PostProcessEventData): void; + /** `data.node` was removed (NOTE: this event is only available as callback, but not for bind()) + * @deprecated since v2.20, use `modifyChild` */ removeNode?(event: JQueryEventObject, data: EventData): void; /** (used by table extension) */ renderColumns?(event: JQueryEventObject, data: EventData): void; @@ -786,12 +964,18 @@ declare namespace Fancytree { checkbox?: boolean | string | ((event: JQueryEventObject, data: EventData) => boolean) | undefined; /** Defines what happens, when the user click a folder node. (default: activate_dblclick_expands) */ clickFolderMode?: FancytreeClickFolderMode | undefined; + /** Copy custom node attributes to `node.data` (default: false). */ + copyFunctionsToData?: boolean | undefined; /** 0..4 (null: use global setting $.ui.fancytree.debugInfo) */ debugLevel?: 0 | 1 | 2 | 3 | 4 | undefined; + /** Disable control (default: false). */ + disabled?: boolean | undefined; /** callback(node) is called for new nodes without a key. Must return a new unique key. (default null: generates default keys like that: "_" + counter) */ defaultKey?: ((node: FancytreeNode) => string) | undefined; /** Accept passing ajax data in a property named `d` (default: true). */ enableAspx?: boolean | undefined; + /** Escape HTML in titles (default: false). */ + escapeTitles?: boolean | undefined; /** Enable titles (default: false) */ enableTitles?: boolean | undefined; /** List of active extensions (default: []) */ @@ -812,6 +996,8 @@ declare namespace Fancytree { keyPathSeparator?: string | undefined; /** 2: top-level nodes are not collapsible (default: 1) */ minExpandLevel?: number | undefined; + /** Display a status node if no data is available (default: true). */ + nodata?: boolean | string | ((event: JQueryEventObject, data: EventData) => string | boolean) | undefined; /** navigate to next node by typing the first letters (default: false) */ quicksearch?: boolean | undefined; /** Right to left mode (default: false) */ @@ -823,17 +1009,21 @@ declare namespace Fancytree { /** default: multi_hier */ selectMode?: FancytreeSelectMode | undefined; /** Used to Initialize the tree. */ - source?: any[] | any | undefined; + source?: SourceData | (() => SourceData) | undefined; /** Translation table */ strings?: TranslationTable | undefined; + /** Add tabindex to container (default: "0"). */ + tabindex?: string | number | undefined; /** Add tabindex='0' to container, so tree can be reached using TAB */ tabbable?: boolean | undefined; /** Add tabindex='0' to node title span, so it can receive keyboard focus */ titlesTabbable?: boolean | undefined; /** Animation options, false:off (default: { effect: "blind", options: {direction: "vertical", scale: "box"}, duration: 200 }) */ - toggleEffect?: false | JQueryUI.EffectOptions | undefined; + toggleEffect?: false | "toggle" | "slideToggle" | JQueryUI.EffectOptions | undefined; /** Tooltips */ tooltip?: boolean | undefined; + /** Optional custom tree id used by `$.ui.fancytree.getTree("treeId")`. */ + treeId?: string | null | undefined; /** (dynamic Option)Prevent (de-)selection using mouse or keyboard. */ unselectable?: @@ -859,7 +1049,7 @@ declare namespace Fancytree { table?: Extensions.Table | undefined; /** Options for misc extensions - see docs for typings */ - [extension: string]: any; + [extension: string]: unknown; } interface TranslationTable { @@ -887,13 +1077,16 @@ declare namespace Fancytree { focus: string | null; selected: string[]; } + type PersistType = "active" | "expanded" | "focus" | "selected"; + /** Space-delimited list like "active expanded focus selected". */ + type PersistTypeSpec = PersistType | string; namespace Extensions { interface List { dnd5?: DragAndDrop5 | undefined; filter?: Filter | undefined; table?: Table | undefined; - [extension: string]: any; + [extension: string]: unknown; } interface DragAndDrop5 { @@ -948,30 +1141,30 @@ declare namespace Fancytree { /** * Callback(sourceNode, data), return true, to enable dnd drag */ - dragStart?: ((sourceNode: FancytreeNode, data: any) => void) | undefined; - dragDrag?: ((sourceNode: FancytreeNode, data: any) => void) | undefined; - dragEnd?: ((sourceNode: FancytreeNode, data: any) => void) | undefined; + dragStart?: ((sourceNode: FancytreeNode, data: unknown) => void) | undefined; + dragDrag?: ((sourceNode: FancytreeNode, data: unknown) => void) | undefined; + dragEnd?: ((sourceNode: FancytreeNode, data: unknown) => void) | undefined; /** * Callback(targetNode, data), return true, to enable dnd drop */ - dragEnter?: ((targetNode: FancytreeNode, data: any) => void) | undefined; + dragEnter?: ((targetNode: FancytreeNode, data: unknown) => void) | undefined; /** * Events (drag over) */ - dragOver?: ((targetNode: FancytreeNode, data: any) => void) | undefined; + dragOver?: ((targetNode: FancytreeNode, data: unknown) => void) | undefined; /** * Callback(targetNode, data), return false to prevent autoExpand */ - dragExpand?: ((targetNode: FancytreeNode, data: any) => void) | undefined; + dragExpand?: ((targetNode: FancytreeNode, data: unknown) => void) | undefined; /** * Events (drag drop) */ - dragDrop?: ((node: FancytreeNode, data: any) => void) | undefined; - dragLeave?: ((targetNode: FancytreeNode, data: any) => void) | undefined; + dragDrop?: ((node: FancytreeNode, data: unknown) => void) | undefined; + dragLeave?: ((targetNode: FancytreeNode, data: unknown) => void) | undefined; /** * Support misc options */ - [key: string]: any; + [key: string]: unknown; } /** * Define filter-extension options @@ -1020,7 +1213,7 @@ declare namespace Fancytree { /** * Support misc options */ - [key: string]: any; + [key: string]: unknown; } /** * Define table-extension options @@ -1029,7 +1222,7 @@ declare namespace Fancytree { /** * Render the checkboxes into the this column index (default: nodeColumnIdx) */ - checkboxColumnIdx: any; + checkboxColumnIdx: number | string; /** * Indent every node level by 16px; default: 16 */ @@ -1041,7 +1234,7 @@ declare namespace Fancytree { /** * Support misc options */ - [key: string]: any; + [key: string]: unknown; } } @@ -1088,6 +1281,16 @@ declare namespace Fancytree { unselectableStatus?: boolean | undefined; } + /** Node data, or a descriptor of how to load it: inline data, a URL string, + * `$.ajax` options (with a required `url`), or a promise resolving to node data. */ + type SourceData = + | NodeData[] + | NodeData + | string + | (JQueryAjaxSettings & { url: string }) + | JQueryXHR + | JQueryPromise; + /** Data object similar to NodeData, but with additional options. * May be passed to FancytreeNode#applyPatch (Every property that is omitted (or set to undefined) will be ignored) */ interface NodePatch { @@ -1113,7 +1316,10 @@ declare namespace Fancytree { assert(cond: boolean, msg: string): void; /** Return a function that executes *fn* at most every *timeout* ms. */ - debounce void>(timeout: number, fn: T, invokeAsap?: boolean, ctx?: any): T; + debounce void>(timeout: number, fn: T, invokeAsap?: boolean, ctx?: unknown): T; + + /** Create a new Fancytree instance on a target element. */ + createTree(el: Element | JQuery | string, opts?: FancytreeOptions): Fancytree; debug(msg: string): void; @@ -1121,24 +1327,48 @@ declare namespace Fancytree { escapeHtml(s: string): string; + /** Convert key/mouse/wheel events to a string like 'ctrl+a' or 'shift+click'. */ + eventToString(event: Event): string; + + /** Normalize jQuery.position options for older jQuery UI versions. */ + fixPositionOptions(opts: Object): Object; + + /** Evaluate a tree option that may be callback-backed or overridden on node data. */ + evalOption( + optionName: string, + node: FancytreeNode, + nodeObject: Object, + treeOptions: Object, + defaultValue?: unknown, + ): unknown; + getEventTarget(event: Event): Object; getEventTargetType(event: Event): string; - getNode(el: JQuery): FancytreeNode; - getNode(el: Event): FancytreeNode; - getNode(el: Element): FancytreeNode; + getNode(el: JQuery): FancytreeNode | null; + getNode(el: Event): FancytreeNode | null; + getNode(el: Element): FancytreeNode | null; - getTree(el: Element | JQuery | Event | number | string): Fancytree; + getTree(el?: Element | JQuery | Event | number | string): Fancytree | null; info(msg: string): void; - /** Convert a keydown event to a string like 'ctrl+a', 'ctrl+shift+f2'. */ + /** Convert a keydown event to a string like 'ctrl+a', 'ctrl+shift+f2'. + * @deprecated use `eventToString` */ keyEventToString(event: Event): string; /** Parse tree data from HTML markup */ parseHtml($ul: JQuery): NodeData[]; + /** Override method on an object, preserving access to `_super` and `_superApply`. */ + overrideMethod( + instance: Object, + methodName: string, + handler: (...args: any[]) => unknown, + context?: unknown, + ): void; + /** Add Fancytree extension definition to the list of globally available extensions. */ registerExtension(definition: Object): void; diff --git a/types/jquery.fancytree/jquery.fancytree-tests.ts b/types/jquery.fancytree/jquery.fancytree-tests.ts index 0a36d3b5daa2a8..9400b43d689bf0 100644 --- a/types/jquery.fancytree/jquery.fancytree-tests.ts +++ b/types/jquery.fancytree/jquery.fancytree-tests.ts @@ -33,13 +33,31 @@ $("#tree").fancytree( dnd5: { dragDrag: (node, data) => {}, }, - click: (ev: JQueryEventObject, node: Fancytree.EventData) => { + click: (ev: JQueryEventObject, node: Fancytree.ClickEventData) => { + const target: Fancytree.EventTargetType = node.targetType; + console.log(target); return true; }, + clickPaging: (event, data) => { + const target: Fancytree.EventTargetType = data.targetType; + console.log(target); + return true; + }, + modifyChild: (event, data) => { + console.log(data.operation); + console.log(data.childNode); + }, checkbox: "radio", // boolean or "radio" expand: () => { console.log("expanded"); }, + copyFunctionsToData: false, + disabled: false, + escapeTitles: true, + nodata: (event, data) => "No data.", + tabindex: "0", + treeId: "myTree", + toggleEffect: "slideToggle", activate: function(event, data) { // A node was activated: display its title: var node = data.node; @@ -65,15 +83,20 @@ $("#tree").fancytree( }, ); +var $treeWidget: JQuery = $("#tree").fancytree(); + // $("#tree").fancytree(); var tree: Fancytree.Fancytree = $("#tree").fancytree("getTree"); // test FancytreeStatic.getTree -var otherTree: Fancytree.Fancytree = $.ui.fancytree.getTree("#tree"); +var otherTree: Fancytree.Fancytree | null = $.ui.fancytree.getTree("#tree"); alert(tree === otherTree); +var createdTree: Fancytree.Fancytree = $.ui.fancytree.createTree("#tree", {}); var activeNode: Fancytree.FancytreeNode = tree.getRootNode(); +var maybeActiveNode: Fancytree.FancytreeNode | null = tree.getActiveNode(); +console.log(maybeActiveNode); // Sort children of active node: activeNode.sortChildren(); @@ -99,6 +122,14 @@ tree.loadKeyPath("/1/2", function(node, status) { node.setActive(); } }); +tree.loadKeyPath("/1/2", { + callback: function(node, status) { + console.log(node, status); + }, + matchKey: function(node, key) { + return node.key === key; + }, +}); tree.expandAll(); tree.expandAll(false); @@ -111,12 +142,32 @@ var f = $.ui.fancytree.debounce(50, (a: number) => { console.log(a); }, true); f(2); +var eventAsString = $.ui.fancytree.eventToString(new Event("click")); +console.log(eventAsString); -node = tree.getFirstChild(); -node.setExpanded().done(function() { - alert("expand animation has finished"); +var pos = $.ui.fancytree.fixPositionOptions({ my: "left center", at: "left bottom", of: $("#tree") }); +console.log(pos); + +var opt = $.ui.fancytree.evalOption("checkbox", activeNode, activeNode, tree.options, false); +console.log(opt); + +$.ui.fancytree.overrideMethod(tree as any, "debug", function(msg: string) { + console.log(msg); }); +node = tree.getFirstChild(); +if (node) { + node.setExpanded().done(function() { + alert("expand animation has finished"); + }); +} + +var maybeNodeByKey: Fancytree.FancytreeNode | null = tree.getNodeByKey("1"); +console.log(maybeNodeByKey); + +var maybeFindNode: Fancytree.FancytreeNode | null = tree.findNextNode("Node"); +console.log(maybeFindNode); + // Get or set an option var autoScroll = $("#tree").fancytree("option", "autoScroll"); $("#tree").fancytree("option", "autoCollapse", true); @@ -127,7 +178,9 @@ $("#tree").fancytree("enable"); alert("We have " + tree.count() + " nodes."); // Use the API -node.setTitle("New title"); +if (node) { + node.setTitle("New title"); +} // add/remove/toggle class activeNode.addClass("test-class"); @@ -135,6 +188,22 @@ activeNode.removeClass("test-class"); activeNode.toggleClass("test-class"); activeNode.toggleClass("test-class", true); +tree.clear(); +tree.enable(); +tree.enable(false); +tree.selectAll(true); +tree.getOption("autoScroll"); +tree.setOption("autoCollapse", true); +tree.debugTime("test"); +tree.debugTimeEnd("test"); +var prevUpdate: boolean = tree.enableUpdate(false); +tree.enableUpdate(prevUpdate); +var loading: boolean = tree.isLoading(); +console.log(loading); +tree.visitRows((n) => { + return true; +}); + // Fancytree.findAll() var nodes: Fancytree.FancytreeNode[]; nodes = tree.findAll((node) => { @@ -142,12 +211,80 @@ nodes = tree.findAll((node) => { }); nodes = tree.findAll("Node"); -node.addChildren({ - title: "New Node", - key: "15", - type: "book", - iconTooltip: "Icon toolip", - statusNodeType: "loading", - unselectableIgnore: true, - unselectableStatus: false, -}, 0); +if (node) { + node.addChildren({ + title: "New Node", + key: "15", + type: "book", + iconTooltip: "Icon toolip", + statusNodeType: "loading", + unselectableIgnore: true, + unselectableStatus: false, + }, 0); + + node.appendSibling({ title: "Sibling Node" }); + node.applyCommand("moveDown"); + node.addPagingNode(); + node.getPath(); + node.getSelectedNodes(); + node.hasClass("test-class"); + node.isBelowOf(activeNode); + node.isPagingNode(); + node.isPartload(); + node.isPartsel(); + node.isRoot(); + node.lazyLoad(); + node.discard(); + node.discardMarkup(); + node.visitSiblings((n) => true); + node.findRelatedNode("down"); + node.triggerModify("data"); + node.triggerModifyChild("add", node); + node.toString(); + node.error("x"); +} + +tree.addPagingNode(); +tree.applyCommand("moveDown", node || activeNode); +tree.findFirst("Node"); +tree.findRelatedNode(activeNode, "down"); +tree.error("x"); +tree.toString(); + +// `source` accepts every format documented in the implementation source: +// object[] | object | string | $.Promise | function (see PR #74972). + +// Inline node data: array of nodes ... +const sourceFromArray: Fancytree.FancytreeOptions = { + source: [{ title: "Node 1", key: "1" }], +}; + +// ... or a single object carrying a `children` array. +const sourceFromObject: Fancytree.FancytreeOptions = { + source: { title: "Root", key: "1", children: [{ title: "Child", key: "2" }] }, +}; + +// A URL string is loaded via Ajax. +const sourceFromUrl: Fancytree.FancytreeOptions = { + source: "/api/tree", +}; + +// Ajax options object (the `source.url` branch). +const sourceFromAjax: Fancytree.FancytreeOptions = { + source: { url: "/api/tree", cache: false }, +}; + +// A promise resolving to node data. +const sourceFromPromise: Fancytree.FancytreeOptions = { + source: $.getJSON("/api/tree"), +}; + +// A function returning node data ... +const sourceFromFunction: Fancytree.FancytreeOptions = { + source: () => [{ title: "Node 1", key: "1" }], +}; + +// ... or returning a promise (e.g. for deferred loading). +const sourceFromFunctionPromise: Fancytree.FancytreeOptions = { + source: () => $.getJSON("/api/tree"), +}; diff --git a/types/jquery.fancytree/package.json b/types/jquery.fancytree/package.json index 443c917e53d2eb..a8e8824327783b 100644 --- a/types/jquery.fancytree/package.json +++ b/types/jquery.fancytree/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/jquery.fancytree", - "version": "0.0.9999", + "version": "2.38.9999", "projects": [ "https://github.com/mar10/fancytree" ], From 41653041d341a22d5bf40b3b79d58b40ac5ece98 Mon Sep 17 00:00:00 2001 From: Matthew Abraham <14793093+shottah@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:21:29 -0400 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74993=20afri?= =?UTF-8?q?castalking:=20rewrite=20against=20SDK=200.8.0=20by=20@shottah?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/africastalking/africastalking-tests.ts | 359 +++++++++- types/africastalking/index.d.ts | 663 +++++++++++++++++-- types/africastalking/package.json | 2 +- 3 files changed, 954 insertions(+), 70 deletions(-) diff --git a/types/africastalking/africastalking-tests.ts b/types/africastalking/africastalking-tests.ts index a91bae1801b9e3..7fc6376863c8ae 100644 --- a/types/africastalking/africastalking-tests.ts +++ b/types/africastalking/africastalking-tests.ts @@ -1,29 +1,354 @@ import AfricasTalking = require("africastalking"); -const africastalking = AfricasTalking({ +// ========================================================================= +// Client construction +// ========================================================================= + +const client = AfricasTalking({ + apiKey: "apiKey", + username: "username", +}); + +const clientXml = AfricasTalking({ apiKey: "apiKey", username: "username", + format: "xml", }); -const SMS = async () => { - const token = africastalking.TOKEN; - const sms = africastalking.SMS; +const clientHandle: AfricasTalking.AfricasTalking = client; + +// ========================================================================= +// SMS (sms.d.ts) +// ========================================================================= + +async function smsSurface() { + const sms: AfricasTalking.SMS = client.SMS; + + const single: AfricasTalking.SMSResponse = await sms.send({ + to: "+254700000000", + message: "hello", + }); + const message: string = single.SMSMessageData.Message; + const recipients: AfricasTalking.SMSRecipient[] = single.SMSMessageData.Recipients; + const status: AfricasTalking.SMSRecipientStatus = recipients[0].status; + const messageId: string = recipients[0].messageId; + void message; + void status; + void messageId; + + await sms.send({ + to: ["+254700000000", "+254700000001"], + message: "hi", + from: "AFRICASTKNG", + senderId: "AFRICASTKNG", + enqueue: true, + }); + + const batch: AfricasTalking.SMSResponse[] = await sms.send([ + { to: "+254700000000", message: "hi" }, + { to: "+254700000001", message: "hi" }, + ]); + void batch; + + const bulk: AfricasTalking.SMSResponse = await sms.sendBulk({ + to: "+254700000000", + message: "bulk", + }); + const bulkArray: AfricasTalking.SMSResponse[] = await sms.sendBulk([ + { to: "+254700000000", message: "bulk" }, + ]); + void bulk; + void bulkArray; + + const premium: AfricasTalking.SMSResponse = await sms.sendPremium({ + to: "+254700000000", + message: "premium", + keyword: "premium", + linkId: "linkId", + retryDurationInHours: 1, + }); + void premium; + + const inbox: AfricasTalking.SMSFetchMessagesResponse = await sms.fetchMessages({ + lastReceivedId: 0, + }); + const inboxMessages: AfricasTalking.SMSInboundMessage[] = inbox.SMSMessageData.Messages; + void inboxMessages; + + const createSub: AfricasTalking.SMSSubscriptionResponse = await sms.createSubscription({ + shortCode: "12345", + keyword: "PREMIUM", + phoneNumber: "+254700000000", + }); + void createSub; + + const fetchSub: AfricasTalking.SMSFetchSubscriptionResponse = await sms.fetchSubscription({ + shortCode: "12345", + keyword: "PREMIUM", + lastReceivedId: 0, + }); + const subscribers: AfricasTalking.SMSSubscriber[] = fetchSub.responses; + void subscribers; + + const deleteSub: AfricasTalking.SMSDeleteSubscriptionResponse = await sms.deleteSubscription({ + shortCode: "12345", + keyword: "PREMIUM", + phoneNumber: "+254700000000", + }); + void deleteSub; +} + +// ========================================================================= +// Token (token.d.ts) +// ========================================================================= + +async function tokenSurface() { + const token: AfricasTalking.TOKEN = client.TOKEN; + const auth: AfricasTalking.AuthTokenResponse = await token.generateAuthToken(); + const t: string = auth.token; + const lifetime: number = auth.lifetimeInSeconds; + void t; + void lifetime; +} + +// ========================================================================= +// Voice (voice.d.ts + actionbuilder.d.ts) +// ========================================================================= + +async function voiceSurface() { + const voice: AfricasTalking.VOICE = client.VOICE; + + const call: AfricasTalking.VoiceCallResponse = await voice.call({ + callFrom: "+254700000000", + callTo: ["+254700000001"], + clientRequestId: "req_1", + }); + const callEntries: AfricasTalking.VoiceCallEntry[] = call.entries; + void callEntries; + + const queued: AfricasTalking.VoiceQueuedCallsResponse = await voice.getNumQueuedCalls({ + phoneNumbers: ["+254700000000"], + }); + void queued; - const sendSmsResult = await africastalking.SMS.send({ - to: "to", - message: "message", - from: "from", + const upload: AfricasTalking.VoiceUploadMediaResponse = await voice.uploadMediaFile({ + url: "https://example.com/audio.wav", + phoneNumber: "+254700000000", }); + void upload; - const checkoutTokenResponse = await token.createCheckoutToken("phoneNumber"); + const builder: AfricasTalking.ActionBuilder = new voice.ActionBuilder(); + const xml: string = builder + .say("Welcome", { voice: "woman", playBeep: true }) + .play("https://example.com/jingle.mp3") + .getDigits( + { say: { text: "Enter your pin", attributes: { voice: "woman" } } }, + { finishOnKey: "#", numDigits: 4, callbackUrl: "https://example.com/cb" }, + ) + .dial("+254700000001", { record: true, sequential: true }) + .record( + { play: { url: "https://example.com/beep.mp3" } }, + { finishOnKey: "#", maxLength: 30 }, + ) + .enqueue({ name: "support" }) + .dequeue("+254700000001", { name: "support" }) + .redirect("https://example.com/next") + .conference() + .reject() + .build(); + void xml; +} - const options = { - // Set your premium product shortCode and keyword - shortCode: "shortCode", - keyword: "keyword", - phoneNumber: "+phoneNumber", - checkoutToken: checkoutTokenResponse.token, +// ========================================================================= +// Airtime (airtime.d.ts) +// ========================================================================= + +async function airtimeSurface() { + const airtime: AfricasTalking.AIRTIME = client.AIRTIME; + + const sendResult: AfricasTalking.AirtimeSendResponse = await airtime.send({ + idempotencyKey: "abc", + maxNumRetry: 3, + recipients: [ + { phoneNumber: "+254700000000", currencyCode: "KES", amount: 50 }, + ], + }); + const responses: AfricasTalking.AirtimeResponseEntry[] = sendResult.responses; + void responses; + + const status: AfricasTalking.AirtimeTransactionStatusResponse = await airtime.findTransactionStatus( + "tx_id", + ); + const data: AfricasTalking.AirtimeTransactionData | undefined = status.data; + void data; +} + +// ========================================================================= +// Application (application.d.ts) +// ========================================================================= + +async function applicationSurface() { + const app: AfricasTalking.APPLICATION = client.APPLICATION; + const data: AfricasTalking.ApplicationDataResponse = await app.fetchApplicationData(); + const balance: string = data.UserData.balance; + void balance; + + const accountSurface: AfricasTalking.APPLICATION = client.ACCOUNT; + const accountData: AfricasTalking.ApplicationDataResponse = await accountSurface.fetchAccount(); + void accountData; +} + +// ========================================================================= +// Insights (insights.d.ts) +// ========================================================================= + +async function insightsSurface() { + const insights: AfricasTalking.INSIGHTS = client.INSIGHTS; + const oneNumber: AfricasTalking.InsightsSimSwapResponse = await insights.checkSimSwapState( + "+254700000000", + ); + const manyNumbers: AfricasTalking.InsightsSimSwapResponse = await insights.checkSimSwapState([ + "+254700000000", + "+254700000001", + ]); + const entries: AfricasTalking.InsightsSimSwapEntry[] = oneNumber.responses; + void manyNumbers; + void entries; +} + +// ========================================================================= +// Mobile data (mobileData.d.ts) +// ========================================================================= + +async function mobileDataSurface() { + const md: AfricasTalking.MOBILE_DATA = client.MOBILE_DATA; + await md.send({ + productName: "DataBundle", + idempotencyKey: "abc", + recipients: [ + { + phoneNumber: "+254700000000", + quantity: 1, + unit: "GB", + validity: "Month", + metadata: { userId: "user_1" }, + }, + ], + }); + await md.findTransaction({ transactionId: "tx_id" }); + await md.fetchWalletBalance(); +} + +// ========================================================================= +// WhatsApp (whatsapp.d.ts) +// ========================================================================= + +async function whatsappSurface() { + const wa: AfricasTalking.WHATSAPP = client.WHATSAPP; + + await wa.sendMessage({ + waNumber: "wa_number", + phoneNumber: "+254700000000", + body: { message: "hello" }, + }); + + await wa.sendMessage({ + waNumber: "wa_number", + phoneNumber: "+254700000000", + body: { + templateId: "welcome_v1", + headerValue: "Welcome", + bodyValues: ["Alice"], + }, + }); + + await wa.sendMessage({ + waNumber: "wa_number", + phoneNumber: "+254700000000", + body: { + mediaType: "Image", + url: "https://example.com/img.png", + caption: "see attached", + }, + }); + + await wa.sendMessage({ + waNumber: "wa_number", + phoneNumber: "+254700000000", + body: { + action: { + button: "Pick one", + sections: [ + { + title: "Options", + rows: [{ id: "1", title: "First", description: "..." }], + }, + ], + }, + body: { text: "Select an option" }, + }, + }); + + await wa.sendMessage({ + waNumber: "wa_number", + phoneNumber: "+254700000000", + body: { + action: { + buttons: [ + { id: "yes", title: "Yes" }, + { id: "no", title: "No" }, + ], + }, + body: { text: "Confirm?" }, + }, + }); + + await wa.createTemplate({ + waNumber: "wa_number", + name: "promo_template", + language: "en", + category: "MARKETING", + components: { + body: { type: "BODY", text: "Hi {{1}}" }, + }, + }); +} + +// ========================================================================= +// USSD (ussd.d.ts) +// ========================================================================= + +function ussdSurface() { + const ussd: AfricasTalking.USSDMiddlewareFactory = client.USSD; + + const handler: AfricasTalking.USSDHandlerFn = (payload, respond) => { + const session: string = payload.sessionId; + const phone: string = payload.phoneNumber; + const text: string = payload.text; + const code: string = payload.serviceCode; + void session; + void phone; + void code; + + if (text === "") { + respond({ response: "Welcome", endSession: false }); + } else { + respond({ response: "Goodbye", endSession: true }); + } }; - const res = await sms.createSubscription(options); -}; + const middleware: AfricasTalking.USSDMiddleware[] = ussd(handler); + void middleware; +} + +void clientHandle; +void clientXml; +void smsSurface; +void tokenSurface; +void voiceSurface; +void airtimeSurface; +void applicationSurface; +void insightsSurface; +void mobileDataSurface; +void whatsappSurface; +void ussdSurface; diff --git a/types/africastalking/index.d.ts b/types/africastalking/index.d.ts index 87de89394b22b3..c7733bcef17383 100644 --- a/types/africastalking/index.d.ts +++ b/types/africastalking/index.d.ts @@ -1,66 +1,625 @@ -interface SMSMessageData { - Message: string; - Recipients: { - "statusCode": number; - "number": string; - "status": "fulfilled" | "failed"; - "cost": string; - "messageId": string; - }; -} +// Single-file declaration; section comments below mirror the SDK's `lib/` +// layout one-to-one. DT's `@definitelytyped/no-declare-current-package` rule +// blocks cross-file namespace augmentation for `export =` packages, so all +// types live here. -interface SMSOptions { - to: string | string[]; - from: string; - message: string; -} +export = africastalking; + +declare function africastalking( + options: africastalking.ClientOptions, +): africastalking.AfricasTalking; + +declare namespace africastalking { + // ========================================================================= + // Client (mirrors `lib/index.js`) + // ========================================================================= + + interface ClientOptions { + username: string; + apiKey: string; + /** Response wire format. SDK default is `"json"`. */ + format?: "json" | "xml"; + } -interface SMS { /** - * This is used to send SMSs to your clients/recipients. - * - * @param to The recipients' phone number. e.g +2547********. Note it can either be a string or an array - * @param from Your registered short code or alphanumeric, e.g. AFRICASTKNG. - * @param message The message to be sent. + * Top-level client surface returned by `africastalking(options)`. Each + * property is a service handle the SDK constructs at instantiation. */ - send: (options: SMSOptions) => Promise; + interface AfricasTalking { + SMS: SMS; + TOKEN: TOKEN; + VOICE: VOICE; + AIRTIME: AIRTIME; + // eslint-disable-next-line @typescript-eslint/naming-convention + INSIGHTS: INSIGHTS; + WHATSAPP: WHATSAPP; + // eslint-disable-next-line @typescript-eslint/naming-convention + MOBILE_DATA: MOBILE_DATA; + APPLICATION: APPLICATION; + /** Backward-compat alias for {@link APPLICATION}; same instance. */ + ACCOUNT: APPLICATION; + /** Express/connect middleware factory for USSD callbacks. */ + USSD: USSDMiddlewareFactory; + } + + // ========================================================================= + // SMS (mirrors `lib/sms.js`) + // ========================================================================= + + interface SMSOptions { + /** Recipient phone number(s) in E.164 format. */ + to: string | string[]; + /** Message body. */ + message: string; + /** Registered short code or alphanumeric sender id, e.g. `AFRICASTKNG`. */ + from?: string; + /** Alternate name for {@link SMSOptions.from}. */ + senderId?: string; + /** Bulk-mode toggle to queue messages rather than dispatch immediately. */ + enqueue?: boolean; + } + + interface SMSPremiumOptions extends SMSOptions { + keyword: string; + linkId?: string; + retryDurationInHours?: number; + } + /** - * This is used to send SMSs to your clients/recipients. - * - * @param to The recipients' phone number. e.g +2547********. Note it can either be a string or an array - * @param from Your registered short code or alphanumeric, e.g. AFRICASTKNG. - * @param message The message to be sent. + * Status returned per recipient. See AT bulk-SMS status codes: + * https://developers.africastalking.com/docs/sms/sending/bulk */ - sendBulk: (options: SMSOptions) => Promise; - createSubscription: (options: { + type SMSRecipientStatus = + | "Success" + | "Failed" + | "Throttled" + | "InsufficientBalance" + | "UserInBlackList" + | "CouldNotRoute" + | "InternalServerError" + | "UserIsInactive" + | "RequestExpired" + | "InvalidLongShortCode" + // Forward-compat for AT status values not yet enumerated. + | (string & {}); + + interface SMSRecipient { + statusCode: number; + number: string; + status: SMSRecipientStatus; + cost: string; + messageId: string; + } + + /** Inner content of the AT SMS-send response envelope. */ + interface SMSMessageData { + Message: string; + Recipients: SMSRecipient[]; + } + + /** Top-level shape resolved by {@link SMS.send} for a single request. */ + interface SMSResponse { + SMSMessageData: SMSMessageData; + } + + interface SMSFetchOptions { + lastReceivedId?: number; + keyword?: string; + shortCode?: string; + } + + interface SMSInboundMessage { + linkId: string; + text: string; + to: string; + id: number; + date: string; + from: string; + } + + interface SMSFetchMessagesResponse { + SMSMessageData: { + Messages: SMSInboundMessage[]; + }; + } + + interface SMSSubscriptionOptions { shortCode: string; keyword: string; phoneNumber: string; - checkoutToken: string; - }) => Promise<{ - "description": "Success" | "Failed"; - "token": string; - }>; -} + } + + interface SMSFetchSubscriptionOptions { + shortCode: string; + keyword: string; + lastReceivedId?: number; + } + + interface SMSSubscriber { + phoneNumber: string; + id: number; + updateType?: string; + } + + interface SMSSubscriptionResponse { + description: string; + success: string; + token?: string; + } + + interface SMSFetchSubscriptionResponse { + responses: SMSSubscriber[]; + } + + interface SMSDeleteSubscriptionResponse { + description: string; + success: string; + } -interface TOKEN { - generateAuthToken: () => Promise<{ - "description": "Success" | "Failed"; - "token": string; - }>; - createCheckoutToken: (phoneNumber: string) => Promise<{ - description: "Success" | "Failed"; + interface SMS { + /** + * Send the same content to one or more recipients in a single request. + * + * @see https://developers.africastalking.com/docs/sms/sending/bulk + */ + send(options: SMSOptions): Promise; + /** + * Send multiple distinct payloads in parallel (one request per element). + * Rejected requests appear as `{ SMSMessageData: { Message: , Recipients: [], status: "failed" } }`. + */ + send(options: SMSOptions[]): Promise; + /** Alias for {@link SMS.send}. */ + sendBulk(options: SMSOptions): Promise; + sendBulk(options: SMSOptions[]): Promise; + /** + * Send a premium-content SMS. Bulk-mode off; per-recipient delivery + * state surfaces in the response. + * + * @see https://developers.africastalking.com/docs/sms/sending/premium + */ + sendPremium(options: SMSPremiumOptions): Promise; + /** + * Fetch inbound messages received against the account's short codes. + * + * @see https://developers.africastalking.com/docs/sms/incoming + */ + fetchMessages(options?: SMSFetchOptions): Promise; + /** + * Create a premium-SMS subscription for a phone number against a + * (`shortCode`, `keyword`) pair. + * + * @see https://developers.africastalking.com/docs/sms/subscriptions/create + */ + createSubscription(options: SMSSubscriptionOptions): Promise; + fetchSubscription(options: SMSFetchSubscriptionOptions): Promise; + deleteSubscription(options: SMSSubscriptionOptions): Promise; + } + + // ========================================================================= + // Token (mirrors `lib/token.js`) + // ========================================================================= + + interface AuthTokenResponse { token: string; - }>; -} + lifetimeInSeconds: number; + } -interface AfricasTalking { - SMS: SMS; - TOKEN: TOKEN; -} + interface TOKEN { + /** + * Generate a short-lived auth token usable by client SDKs (mobile / web). + * + * @see https://developers.africastalking.com/docs/auth-token + */ + generateAuthToken(): Promise; + } -export = africastalking; + // ========================================================================= + // Voice (mirrors `lib/voice.js`) + // ========================================================================= -declare function africastalking( - options: { username: string; apiKey: string }, -): AfricasTalking; + interface VoiceCallOptions { + callFrom: string; + callTo: string | string[]; + clientRequestId?: string; + } + + type VoiceCallStatus = + | "Queued" + | "InvalidPhoneNumber" + | "DestinationNotSupported" + | "InsufficientCredit" + | (string & {}); + + interface VoiceCallEntry { + phoneNumber: string; + status: VoiceCallStatus; + sessionId?: string; + errorMessage?: string; + } + + interface VoiceCallResponse { + entries: VoiceCallEntry[]; + errorMessage?: string; + } + + interface VoiceQueuedCallsOptions { + phoneNumbers: string | string[]; + } + + interface VoiceQueuedCallEntry { + phoneNumber: string; + queueName: string; + numCalls: number; + } + + interface VoiceQueuedCallsResponse { + entries: VoiceQueuedCallEntry[]; + errorMessage?: string; + } + + interface VoiceUploadMediaOptions { + url: string; + phoneNumber: string; + } + + /** + * Response shape is documented only on the AT side and not in the SDK. + * Consumers should treat as opaque or narrow against runtime checks. + */ + type VoiceUploadMediaResponse = unknown; + + interface VOICE { + /** + * Initiate an outbound voice call to one or more numbers. + * + * @see https://developers.africastalking.com/docs/voice/makecall + */ + call(options: VoiceCallOptions): Promise; + /** + * Get the number of calls currently queued against the account's + * virtual numbers. + * + * @see https://developers.africastalking.com/docs/voice/queue + */ + getNumQueuedCalls(options: VoiceQueuedCallsOptions): Promise; + /** + * Upload a media file to AT for later playback in voice flows. + * + * @see https://developers.africastalking.com/docs/voice/mediaupload + */ + uploadMediaFile(options: VoiceUploadMediaOptions): Promise; + /** Constructor for the voice-XML response builder. Instantiate per response. */ + readonly ActionBuilder: ActionBuilderConstructor; + } + + // ========================================================================= + // ActionBuilder (mirrors `lib/actionbuilder.js`) + // ========================================================================= + + interface VoiceSayAttributes { + voice?: "man" | "woman" | (string & {}); + playBeep?: boolean; + } + + interface VoiceGetDigitsAttributes { + finishOnKey?: string; + numDigits?: number; + timeout?: number; + callbackUrl?: string; + } + + interface VoiceDialAttributes { + callerId?: string; + record?: boolean; + sequential?: boolean; + maxDuration?: number; + ringBackTone?: string; + } + + interface VoiceRecordAttributes { + finishOnKey?: string; + maxLength?: number; + timeout?: number; + playBeep?: boolean; + trimSilence?: boolean; + callbackUrl?: string; + } + + interface VoiceEnqueueAttributes { + holdMusic?: string; + name?: string; + } + + interface VoiceDequeueAttributes { + name?: string; + } + + interface VoiceActionChild { + say?: { text: string; attributes?: VoiceSayAttributes }; + play?: { url: string }; + } + + interface ActionBuilder { + say(text: string, attributes?: VoiceSayAttributes): ActionBuilder; + play(url: string): ActionBuilder; + getDigits(children: VoiceActionChild, attributes: VoiceGetDigitsAttributes): ActionBuilder; + dial(phoneNumbers: string, attributes?: VoiceDialAttributes): ActionBuilder; + record(children: VoiceActionChild, attributes?: VoiceRecordAttributes): ActionBuilder; + enqueue(attributes?: VoiceEnqueueAttributes): ActionBuilder; + dequeue(phoneNumber: string, attributes?: VoiceDequeueAttributes): ActionBuilder; + redirect(url: string): ActionBuilder; + conference(): ActionBuilder; + reject(): ActionBuilder; + /** Finalize and return the response XML. Throws if called twice. */ + build(): string; + } + + interface ActionBuilderConstructor { + new(): ActionBuilder; + } + + // ========================================================================= + // Airtime (mirrors `lib/airtime.js`) + // ========================================================================= + + interface AirtimeRecipient { + phoneNumber: string; + currencyCode: string; + amount: number; + } + + interface AirtimeSendOptions { + recipients: AirtimeRecipient[]; + idempotencyKey?: string; + maxNumRetry?: number; + } + + interface AirtimeResponseEntry { + phoneNumber: string; + amount: string; + discount: string; + status: string; + requestId: string; + errorMessage: string; + } + + interface AirtimeSendResponse { + numSent: number; + totalAmount: string; + totalDiscount: string; + responses: AirtimeResponseEntry[]; + errorMessage?: string; + } + + interface AirtimeTransactionData { + amount: string; + deliveredAt?: string; + phoneNumber: string; + requestId: string; + status: string; + transactionDate?: string; + } + + interface AirtimeTransactionStatusResponse { + errorMessage?: string; + data?: AirtimeTransactionData; + } + + interface AIRTIME { + /** @see https://developers.africastalking.com/docs/airtime/sending */ + send(options: AirtimeSendOptions): Promise; + /** @see https://developers.africastalking.com/docs/airtime/status */ + findTransactionStatus(transactionId: string): Promise; + } + + // ========================================================================= + // Application (mirrors `lib/application.js`; also exposed as `ACCOUNT`) + // ========================================================================= + + interface ApplicationDataResponse { + UserData: { + balance: string; + }; + } + + interface APPLICATION { + /** + * Fetch the application's wallet balance and metadata. + * + * @see https://developers.africastalking.com/docs/application/balance + */ + fetchApplicationData(): Promise; + /** Alias for {@link APPLICATION.fetchApplicationData}; same shape. */ + fetchAccount(): Promise; + } + + // ========================================================================= + // Insights (mirrors `lib/insights.js`) + // ========================================================================= + + interface InsightsSimSwapEntry { + phoneNumber: string; + simSwapStatus?: string; + errorMessage?: string; + } + + interface InsightsSimSwapResponse { + status: "Processed" | (string & {}); + responses: InsightsSimSwapEntry[]; + } + + // Identifier matches the SDK's `this.INSIGHTS` runtime property on the + // client; `@typescript-eslint/naming-convention` rejects names matching + // `^I[A-Z]/u`, so the override is necessary to preserve the runtime- + // property convention used across this declaration. + // eslint-disable-next-line @typescript-eslint/naming-convention + interface INSIGHTS { + /** + * Check whether the given phone number(s) have undergone a SIM swap + * recently. Useful for fraud / takeover signals. + * + * @see https://developers.africastalking.com/docs/insights/sim-swap + */ + checkSimSwapState(phoneNumbers: string | string[]): Promise; + } + + // ========================================================================= + // Mobile data (mirrors `lib/mobileData.js`) + // ========================================================================= + + type MobileDataUnit = "MB" | "GB"; + type MobileDataValidity = "Day" | "Week" | "BiWeek" | "Month" | "Quarterly"; + + interface MobileDataRecipient { + phoneNumber: string; + quantity: number; + unit: MobileDataUnit; + validity: MobileDataValidity; + metadata: Record; + } + + interface MobileDataSendOptions { + productName: string; + recipients: MobileDataRecipient[]; + idempotencyKey?: string; + } + + interface MobileDataFindTransactionOptions { + transactionId: string; + } + + /** + * Response shapes for mobile-data endpoints are documented only on the + * AT side; opaque to keep the type honest until they stabilize. + */ + type MobileDataResponse = unknown; + + // Identifier matches the SDK's `this.MOBILE_DATA` runtime property on + // the client; `@typescript-eslint/naming-convention` rejects + // SCREAMING_SNAKE_CASE for interfaces, so the override is necessary to + // preserve the runtime-property convention used across this declaration. + // eslint-disable-next-line @typescript-eslint/naming-convention + interface MOBILE_DATA { + send(options: MobileDataSendOptions): Promise; + findTransaction(options: MobileDataFindTransactionOptions): Promise; + fetchWalletBalance(): Promise; + } + + // ========================================================================= + // WhatsApp (mirrors `lib/whatsapp.js`) + // ========================================================================= + + type WhatsAppMediaType = "Image" | "Video" | "Audio" | "Voice"; + type WhatsAppTemplateCategory = "MARKETING" | "UTILITY" | "AUTHENTICATION"; + + interface WhatsAppTextBody { + message: string; + } + + interface WhatsAppTemplateBody { + templateId: string; + headerValue: string; + bodyValues: string[]; + } + + interface WhatsAppMediaBody { + mediaType: WhatsAppMediaType; + url: string; + caption?: string; + } + + interface WhatsAppInteractiveSectionRow { + id?: string; + title?: string; + description?: string; + } + + interface WhatsAppInteractiveSection { + title?: string; + product_items?: Array>; + rows: WhatsAppInteractiveSectionRow[]; + } + + interface WhatsAppInteractiveListAction { + button?: string; + sections?: WhatsAppInteractiveSection[]; + } + + interface WhatsAppInteractiveButton { + id?: string; + title?: string; + } + + interface WhatsAppInteractiveButtonAction { + buttons?: WhatsAppInteractiveButton[]; + } + + interface WhatsAppInteractiveBody { + action?: WhatsAppInteractiveListAction | WhatsAppInteractiveButtonAction; + body?: { text?: string }; + header?: { text?: string }; + footer?: { text?: string }; + } + + type WhatsAppBody = WhatsAppTextBody | WhatsAppTemplateBody | WhatsAppMediaBody | WhatsAppInteractiveBody; + + interface WhatsAppSendOptions { + waNumber: string; + phoneNumber: string; + body: WhatsAppBody; + } + + interface WhatsAppTemplateComponents { + header?: Record; + body?: Record; + footer?: Record; + buttons?: Record; + } + + interface WhatsAppCreateTemplateOptions { + waNumber: string; + name: string; + language: string; + category: WhatsAppTemplateCategory; + components: WhatsAppTemplateComponents; + } + + type WhatsAppResponse = unknown; + + interface WHATSAPP { + sendMessage(options: WhatsAppSendOptions): Promise; + createTemplate(options: WhatsAppCreateTemplateOptions): Promise; + } + + // ========================================================================= + // USSD (mirrors `lib/ussd.js`) + // ========================================================================= + + interface USSDPayload { + sessionId: string; + serviceCode: string; + phoneNumber: string; + text: string; + networkCode?: string; + [key: string]: string | undefined; + } + + interface USSDResponseOptions { + response: string; + endSession: boolean; + } + + type USSDRespondCallback = (opts: USSDResponseOptions) => void; + type USSDHandlerFn = (payload: USSDPayload, respond: USSDRespondCallback) => void; + + /** Connect/Express-compatible middleware function. */ + type USSDMiddleware = (req: unknown, res: unknown, next: (err?: unknown) => void) => void; + + /** + * Factory that takes a USSD handler and returns the middleware tuple to + * mount on the USSD callback route. + * + * @see https://developers.africastalking.com/docs/ussd/callback + */ + type USSDMiddlewareFactory = (handler: USSDHandlerFn) => USSDMiddleware[]; +} diff --git a/types/africastalking/package.json b/types/africastalking/package.json index 811ae83adaf083..a7aa140592e30f 100644 --- a/types/africastalking/package.json +++ b/types/africastalking/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/africastalking", - "version": "0.6.9999", + "version": "0.8.9999", "projects": [ "https://www.npmjs.com/package/africastalking" ], From d9f26c379266b2240cc32bf2f61871ed3e77aeb7 Mon Sep 17 00:00:00 2001 From: YuSheng Chen Date: Sat, 6 Jun 2026 06:24:30 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75049=20[nod?= =?UTF-8?q?e]=20http2:=20add=20maxSessionRejectedStreams=20and=20maxSessio?= =?UTF-8?q?nInvalidFrames=20options=20by=20@samuel871211?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/node/http2.d.ts | 2 ++ types/node/node-tests/http2.ts | 2 ++ types/node/v20/http2.d.ts | 2 ++ types/node/v20/test/http2.ts | 2 ++ types/node/v22/http2.d.ts | 2 ++ types/node/v22/test/http2.ts | 2 ++ types/node/v24/http2.d.ts | 2 ++ types/node/v24/test/http2.ts | 2 ++ 8 files changed, 16 insertions(+) diff --git a/types/node/http2.d.ts b/types/node/http2.d.ts index d20753d9eab666..ce6c3bfb69fd65 100644 --- a/types/node/http2.d.ts +++ b/types/node/http2.d.ts @@ -1240,6 +1240,8 @@ declare module "node:http2" { Http2Request extends typeof Http2ServerRequest = typeof Http2ServerRequest, Http2Response extends typeof Http2ServerResponse> = typeof Http2ServerResponse, > extends SessionOptions { + maxSessionRejectedStreams?: number | undefined; + maxSessionInvalidFrames?: number | undefined; streamResetBurst?: number | undefined; streamResetRate?: number | undefined; /** @deprecated Use `http1Options.IncomingMessage` instead. */ diff --git a/types/node/node-tests/http2.ts b/types/node/node-tests/http2.ts index d15bab089fa812..828402107c2346 100644 --- a/types/node/node-tests/http2.ts +++ b/types/node/node-tests/http2.ts @@ -263,6 +263,8 @@ import { URL } from "node:url"; { let settings: Settings = {}; const serverOptions: ServerOptions = { + maxSessionRejectedStreams: 1, + maxSessionInvalidFrames: 1, maxDeflateDynamicTableSize: 0, maxSettings: 32, maxSessionMemory: 10, diff --git a/types/node/v20/http2.d.ts b/types/node/v20/http2.d.ts index ecc3d78c04ebbb..f4d7d08560cc17 100644 --- a/types/node/v20/http2.d.ts +++ b/types/node/v20/http2.d.ts @@ -1337,6 +1337,8 @@ declare module "http2" { Http2Request extends typeof Http2ServerRequest = typeof Http2ServerRequest, Http2Response extends typeof Http2ServerResponse> = typeof Http2ServerResponse, > extends SessionOptions { + maxSessionRejectedStreams?: number | undefined; + maxSessionInvalidFrames?: number | undefined; Http1IncomingMessage?: Http1Request | undefined; Http1ServerResponse?: Http1Response | undefined; Http2ServerRequest?: Http2Request | undefined; diff --git a/types/node/v20/test/http2.ts b/types/node/v20/test/http2.ts index 017408290ccc24..e92f5bc7593a39 100644 --- a/types/node/v20/test/http2.ts +++ b/types/node/v20/test/http2.ts @@ -258,6 +258,8 @@ import { URL } from "node:url"; { let settings: Settings = {}; const serverOptions: ServerOptions = { + maxSessionRejectedStreams: 1, + maxSessionInvalidFrames: 1, maxDeflateDynamicTableSize: 0, maxSettings: 32, maxSessionMemory: 10, diff --git a/types/node/v22/http2.d.ts b/types/node/v22/http2.d.ts index da24362b39181c..3dff7a60af634c 100644 --- a/types/node/v22/http2.d.ts +++ b/types/node/v22/http2.d.ts @@ -1348,6 +1348,8 @@ declare module "http2" { Http2Request extends typeof Http2ServerRequest = typeof Http2ServerRequest, Http2Response extends typeof Http2ServerResponse> = typeof Http2ServerResponse, > extends SessionOptions { + maxSessionRejectedStreams?: number | undefined; + maxSessionInvalidFrames?: number | undefined; streamResetBurst?: number | undefined; streamResetRate?: number | undefined; Http1IncomingMessage?: Http1Request | undefined; diff --git a/types/node/v22/test/http2.ts b/types/node/v22/test/http2.ts index 22b896d9d98605..5a4b3014cc7b31 100644 --- a/types/node/v22/test/http2.ts +++ b/types/node/v22/test/http2.ts @@ -260,6 +260,8 @@ import { URL } from "node:url"; { let settings: Settings = {}; const serverOptions: ServerOptions = { + maxSessionRejectedStreams: 1, + maxSessionInvalidFrames: 1, maxDeflateDynamicTableSize: 0, maxSettings: 32, maxSessionMemory: 10, diff --git a/types/node/v24/http2.d.ts b/types/node/v24/http2.d.ts index 3ac971607fbfd0..77cbe8a7cc9021 100644 --- a/types/node/v24/http2.d.ts +++ b/types/node/v24/http2.d.ts @@ -1429,6 +1429,8 @@ declare module "http2" { Http2Request extends typeof Http2ServerRequest = typeof Http2ServerRequest, Http2Response extends typeof Http2ServerResponse> = typeof Http2ServerResponse, > extends SessionOptions { + maxSessionRejectedStreams?: number | undefined; + maxSessionInvalidFrames?: number | undefined; streamResetBurst?: number | undefined; streamResetRate?: number | undefined; Http1IncomingMessage?: Http1Request | undefined; diff --git a/types/node/v24/test/http2.ts b/types/node/v24/test/http2.ts index badd7a93568abd..ef7695edb7a338 100644 --- a/types/node/v24/test/http2.ts +++ b/types/node/v24/test/http2.ts @@ -262,6 +262,8 @@ import { URL } from "node:url"; { let settings: Settings = {}; const serverOptions: ServerOptions = { + maxSessionRejectedStreams: 1, + maxSessionInvalidFrames: 1, maxDeflateDynamicTableSize: 0, maxSettings: 32, maxSessionMemory: 10, From 4fc5e4ee9d5b4c05aef3bf4c9d08253cee673afd Mon Sep 17 00:00:00 2001 From: YuSheng Chen Date: Sat, 6 Jun 2026 06:25:42 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75033=20[nod?= =?UTF-8?q?e]=20http2=20Settings=20add=20customSettings=20by=20@samuel8712?= =?UTF-8?q?11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/node/http2.d.ts | 1 + types/node/node-tests/http2.ts | 2 ++ types/node/v20/http2.d.ts | 1 + types/node/v20/test/http2.ts | 2 ++ types/node/v22/http2.d.ts | 1 + types/node/v22/test/http2.ts | 2 ++ types/node/v24/http2.d.ts | 1 + types/node/v24/test/http2.ts | 2 ++ 8 files changed, 12 insertions(+) diff --git a/types/node/http2.d.ts b/types/node/http2.d.ts index ce6c3bfb69fd65..a90444ced72c1b 100644 --- a/types/node/http2.d.ts +++ b/types/node/http2.d.ts @@ -582,6 +582,7 @@ declare module "node:http2" { maxConcurrentStreams?: number | undefined; maxHeaderListSize?: number | undefined; enableConnectProtocol?: boolean | undefined; + customSettings?: { [key: number]: number }; } interface ClientSessionRequestOptions { endStream?: boolean | undefined; diff --git a/types/node/node-tests/http2.ts b/types/node/node-tests/http2.ts index 828402107c2346..38455c0ae30aef 100644 --- a/types/node/node-tests/http2.ts +++ b/types/node/node-tests/http2.ts @@ -57,6 +57,8 @@ import { URL } from "node:url"; maxFrameSize: 0, maxConcurrentStreams: 0, maxHeaderListSize: 0, + enableConnectProtocol: false, + customSettings: { 10: 10 }, }; } diff --git a/types/node/v20/http2.d.ts b/types/node/v20/http2.d.ts index f4d7d08560cc17..1f0c4e2a0ed4e0 100644 --- a/types/node/v20/http2.d.ts +++ b/types/node/v20/http2.d.ts @@ -635,6 +635,7 @@ declare module "http2" { maxConcurrentStreams?: number | undefined; maxHeaderListSize?: number | undefined; enableConnectProtocol?: boolean | undefined; + customSettings?: { [key: number]: number }; } export interface ClientSessionRequestOptions { endStream?: boolean | undefined; diff --git a/types/node/v20/test/http2.ts b/types/node/v20/test/http2.ts index e92f5bc7593a39..a1f81145774a00 100644 --- a/types/node/v20/test/http2.ts +++ b/types/node/v20/test/http2.ts @@ -56,6 +56,8 @@ import { URL } from "node:url"; maxFrameSize: 0, maxConcurrentStreams: 0, maxHeaderListSize: 0, + enableConnectProtocol: false, + customSettings: { 10: 10 }, }; } diff --git a/types/node/v22/http2.d.ts b/types/node/v22/http2.d.ts index 3dff7a60af634c..a08c686629591a 100644 --- a/types/node/v22/http2.d.ts +++ b/types/node/v22/http2.d.ts @@ -635,6 +635,7 @@ declare module "http2" { maxConcurrentStreams?: number | undefined; maxHeaderListSize?: number | undefined; enableConnectProtocol?: boolean | undefined; + customSettings?: { [key: number]: number }; } export interface ClientSessionRequestOptions { endStream?: boolean | undefined; diff --git a/types/node/v22/test/http2.ts b/types/node/v22/test/http2.ts index 5a4b3014cc7b31..e83c2a6df97e02 100644 --- a/types/node/v22/test/http2.ts +++ b/types/node/v22/test/http2.ts @@ -56,6 +56,8 @@ import { URL } from "node:url"; maxFrameSize: 0, maxConcurrentStreams: 0, maxHeaderListSize: 0, + enableConnectProtocol: false, + customSettings: { 10: 10 }, }; } diff --git a/types/node/v24/http2.d.ts b/types/node/v24/http2.d.ts index 77cbe8a7cc9021..a175720a9f5c9d 100644 --- a/types/node/v24/http2.d.ts +++ b/types/node/v24/http2.d.ts @@ -680,6 +680,7 @@ declare module "http2" { maxConcurrentStreams?: number | undefined; maxHeaderListSize?: number | undefined; enableConnectProtocol?: boolean | undefined; + customSettings?: { [key: number]: number }; } export interface ClientSessionRequestOptions { endStream?: boolean | undefined; diff --git a/types/node/v24/test/http2.ts b/types/node/v24/test/http2.ts index ef7695edb7a338..25bae7efe4a45b 100644 --- a/types/node/v24/test/http2.ts +++ b/types/node/v24/test/http2.ts @@ -56,6 +56,8 @@ import { URL } from "node:url"; maxFrameSize: 0, maxConcurrentStreams: 0, maxHeaderListSize: 0, + enableConnectProtocol: false, + customSettings: { 10: 10 }, }; }