From 981028bd247be685e09dc6f16c614aa8c5063cf7 Mon Sep 17 00:00:00 2001 From: box-sdk-build Date: Wed, 20 May 2026 09:37:32 -0700 Subject: [PATCH 1/4] feat: Convert Note Public API (box/box-openapi#599) --- .codegen.json | 2 +- docs/README.md | 1 + docs/convertMarkdownToBoxNote.md | 26 ++ package-lock.json | 59 ++--- src/client.ts | 7 + src/managers/convertMarkdownToBoxNote.ts | 167 +++++++++++++ src/managers/index.ts | 1 + src/schemas/v2026R0/folderReferenceV2026R0.ts | 132 ++++++++++ src/schemas/v2026R0/index.ts | 3 + .../v2026R0/notesConvertRequestBodyV2026R0.ts | 226 ++++++++++++++++++ .../v2026R0/notesConvertResponseV2026R0.ts | 134 +++++++++++ 11 files changed, 715 insertions(+), 43 deletions(-) create mode 100644 docs/convertMarkdownToBoxNote.md create mode 100644 src/managers/convertMarkdownToBoxNote.ts create mode 100644 src/schemas/v2026R0/folderReferenceV2026R0.ts create mode 100644 src/schemas/v2026R0/notesConvertRequestBodyV2026R0.ts create mode 100644 src/schemas/v2026R0/notesConvertResponseV2026R0.ts diff --git a/.codegen.json b/.codegen.json index e41b9128..a8e4873c 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "4de40e1", "specHash": "e0ffc4a", "version": "10.10.0" } +{ "engineHash": "4de40e1", "specHash": "8b85e74", "version": "10.10.0" } diff --git a/docs/README.md b/docs/README.md index 2bafde95..a485eb30 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,6 +26,7 @@ the SDK are available by topic: - [Collaboration allowlist exempt targets](collaborationAllowlistExemptTargets.md) - [Collections](collections.md) - [Comments](comments.md) +- [Convert markdown to box note](convertMarkdownToBoxNote.md) - [Device pinners](devicePinners.md) - [Docgen](docgen.md) - [Docgen template](docgenTemplate.md) diff --git a/docs/convertMarkdownToBoxNote.md b/docs/convertMarkdownToBoxNote.md new file mode 100644 index 00000000..6d9f5d74 --- /dev/null +++ b/docs/convertMarkdownToBoxNote.md @@ -0,0 +1,26 @@ +# ConvertMarkdownToBoxNoteManager + +- [Convert content to Box Note](#convert-content-to-box-note) + +## Convert content to Box Note + +Creates a Box Note (`.boxnote` file) from supported source content. See the `content_format` field for supported formats. + +This operation is performed by calling function `createNoteConvertV2026R0`. + +See the endpoint docs at +[API Reference](https://developer.box.com/reference/v2026.0/post-notes-convert/). + +_Currently we don't have an example for calling `createNoteConvertV2026R0` in integration tests_ + +### Arguments + +- requestBodyInput `NotesConvertRequestBodyV2026R0Input` + - Request body of createNoteConvertV2026R0 method +- optionalsInput `CreateNoteConvertV2026R0OptionalsInput` + +### Returns + +This function returns a value of type `NotesConvertResponseV2026R0`. + +The note was created successfully. diff --git a/package-lock.json b/package-lock.json index ecb91cd0..5d1fdd0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1549,30 +1549,6 @@ "@babel/types": "^7.28.2" } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -1637,9 +1613,9 @@ "peer": true }, "node_modules/@types/node": { - "version": "25.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz", - "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "dev": true, "license": "MIT", "dependencies": { @@ -2766,9 +2742,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.359", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.359.tgz", - "integrity": "sha512-8lPELWuYZIWk7NDvCNthtmMw/7Q5Wu25NpM4djFMHBmk8DubPAtL4YTOp7ou0e7HyJtwkVlWv8XMLURnrtgJQw==", + "version": "1.5.360", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", + "integrity": "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==", "dev": true, "license": "ISC" }, @@ -2793,9 +2769,9 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.21.5", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.5.tgz", - "integrity": "sha512-mLCNbrQli11K1ySUmuNt4ZUB3OpGIDq4q2vTBTf5cL2lpsRjI9QKqSD0ndjW8FyvcW/Jj46gMe9syyHAsvMa/A==", + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6266,14 +6242,13 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.106.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz", - "integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==", + "version": "5.107.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.0.tgz", + "integrity": "sha512-PSxeHk/dmLYZlnTU+vL1Gej6Evg5RNtl3flhxBresfznFnzxinHMzHKloHnywM/3ouQv7/AlZCswWDIkNSggUA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", @@ -6283,20 +6258,20 @@ "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.20.0", - "es-module-lexer": "^2.0.0", + "enhanced-resolve": "^5.21.4", + "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "loader-runner": "^4.3.1", + "loader-runner": "^4.3.2", "mime-db": "^1.54.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.17", + "terser-webpack-plugin": "^5.5.0", "watchpack": "^2.5.1", - "webpack-sources": "^3.3.4" + "webpack-sources": "^3.4.1" }, "bin": { "webpack": "bin/webpack.js" diff --git a/src/client.ts b/src/client.ts index cc3e2366..b692b918 100644 --- a/src/client.ts +++ b/src/client.ts @@ -86,6 +86,7 @@ import { ShieldListsManager } from './managers/shieldLists'; import { ArchivesManager } from './managers/archives'; import { ExternalUsersManager } from './managers/externalUsers'; import { AutomateWorkflowsManager } from './managers/automateWorkflows'; +import { ConvertMarkdownToBoxNoteManager } from './managers/convertMarkdownToBoxNote'; import { Authentication } from './networking/auth'; import { NetworkSession } from './networking/network'; import { BoxSdkError } from './box/errors'; @@ -192,6 +193,7 @@ export class BoxClient { readonly archives: ArchivesManager; readonly externalUsers: ExternalUsersManager; readonly automateWorkflows: AutomateWorkflowsManager; + readonly convertMarkdownToBoxNote: ConvertMarkdownToBoxNoteManager; constructor( fields: Omit< BoxClient, @@ -279,6 +281,7 @@ export class BoxClient { | 'archives' | 'externalUsers' | 'automateWorkflows' + | 'convertMarkdownToBoxNote' | 'networkSession' | 'makeRequest' | 'withAsUserHeader' @@ -640,6 +643,10 @@ export class BoxClient { auth: this.auth, networkSession: this.networkSession, }); + this.convertMarkdownToBoxNote = new ConvertMarkdownToBoxNoteManager({ + auth: this.auth, + networkSession: this.networkSession, + }); } /** * Make a custom http request using the client authentication and network session. diff --git a/src/managers/convertMarkdownToBoxNote.ts b/src/managers/convertMarkdownToBoxNote.ts new file mode 100644 index 00000000..67352832 --- /dev/null +++ b/src/managers/convertMarkdownToBoxNote.ts @@ -0,0 +1,167 @@ +import { serializeNotesConvertResponseV2026R0 } from '../schemas/v2026R0/notesConvertResponseV2026R0'; +import { deserializeNotesConvertResponseV2026R0 } from '../schemas/v2026R0/notesConvertResponseV2026R0'; +import { serializeClientErrorV2026R0 } from '../schemas/v2026R0/clientErrorV2026R0'; +import { deserializeClientErrorV2026R0 } from '../schemas/v2026R0/clientErrorV2026R0'; +import { serializeBoxVersionHeaderV2026R0 } from '../parameters/v2026R0/boxVersionHeaderV2026R0'; +import { deserializeBoxVersionHeaderV2026R0 } from '../parameters/v2026R0/boxVersionHeaderV2026R0'; +import { serializeNotesConvertRequestBodyV2026R0 } from '../schemas/v2026R0/notesConvertRequestBodyV2026R0'; +import { deserializeNotesConvertRequestBodyV2026R0 } from '../schemas/v2026R0/notesConvertRequestBodyV2026R0'; +import { NotesConvertRequestBodyV2026R0Input } from '../schemas/v2026R0/notesConvertRequestBodyV2026R0'; +import { ResponseFormat } from '../networking/fetchOptions'; +import { NotesConvertResponseV2026R0 } from '../schemas/v2026R0/notesConvertResponseV2026R0'; +import { ClientErrorV2026R0 } from '../schemas/v2026R0/clientErrorV2026R0'; +import { BoxVersionHeaderV2026R0 } from '../parameters/v2026R0/boxVersionHeaderV2026R0'; +import { NotesConvertRequestBodyV2026R0 } from '../schemas/v2026R0/notesConvertRequestBodyV2026R0'; +import { BoxSdkError } from '../box/errors'; +import { Authentication } from '../networking/auth'; +import { NetworkSession } from '../networking/network'; +import { FetchOptions } from '../networking/fetchOptions'; +import { FetchResponse } from '../networking/fetchResponse'; +import { prepareParams } from '../internal/utils'; +import { toString } from '../internal/utils'; +import { ByteStream } from '../internal/utils'; +import { CancellationToken } from '../internal/utils'; +import { sdToJson } from '../serialization/json'; +import { SerializedData } from '../serialization/json'; +import { sdIsEmpty } from '../serialization/json'; +import { sdIsBoolean } from '../serialization/json'; +import { sdIsNumber } from '../serialization/json'; +import { sdIsString } from '../serialization/json'; +import { sdIsList } from '../serialization/json'; +import { sdIsMap } from '../serialization/json'; +export class CreateNoteConvertV2026R0Optionals { + readonly headers: CreateNoteConvertV2026R0Headers = + new CreateNoteConvertV2026R0Headers({}); + readonly cancellationToken?: CancellationToken = void 0; + constructor( + fields: Omit< + CreateNoteConvertV2026R0Optionals, + 'headers' | 'cancellationToken' + > & + Partial< + Pick + >, + ) { + if (fields.headers !== undefined) { + this.headers = fields.headers; + } + if (fields.cancellationToken !== undefined) { + this.cancellationToken = fields.cancellationToken; + } + } +} +export interface CreateNoteConvertV2026R0OptionalsInput { + readonly headers?: CreateNoteConvertV2026R0Headers; + readonly cancellationToken?: CancellationToken; +} +export class CreateNoteConvertV2026R0Headers { + /** + * Version header. */ + readonly boxVersion: BoxVersionHeaderV2026R0 = + '2026.0' as BoxVersionHeaderV2026R0; + /** + * Extra headers that will be included in the HTTP request. */ + readonly extraHeaders?: { + readonly [key: string]: undefined | string; + } = {}; + constructor( + fields: Omit< + CreateNoteConvertV2026R0Headers, + 'boxVersion' | 'extraHeaders' + > & + Partial< + Pick + >, + ) { + if (fields.boxVersion !== undefined) { + this.boxVersion = fields.boxVersion; + } + if (fields.extraHeaders !== undefined) { + this.extraHeaders = fields.extraHeaders; + } + } +} +export interface CreateNoteConvertV2026R0HeadersInput { + /** + * Version header. */ + readonly boxVersion?: BoxVersionHeaderV2026R0; + /** + * Extra headers that will be included in the HTTP request. */ + readonly extraHeaders?: { + readonly [key: string]: undefined | string; + }; +} +export class ConvertMarkdownToBoxNoteManager { + readonly auth?: Authentication; + readonly networkSession: NetworkSession = new NetworkSession({}); + constructor( + fields: Omit< + ConvertMarkdownToBoxNoteManager, + 'networkSession' | 'createNoteConvertV2026R0' + > & + Partial>, + ) { + if (fields.auth !== undefined) { + this.auth = fields.auth; + } + if (fields.networkSession !== undefined) { + this.networkSession = fields.networkSession; + } + } + /** + * Creates a Box Note (`.boxnote` file) from supported source content. See the `content_format` field for supported formats. + * @param {NotesConvertRequestBodyV2026R0Input} requestBodyInput Request body of createNoteConvertV2026R0 method + * @param {CreateNoteConvertV2026R0OptionalsInput} optionalsInput + * @returns {Promise} + */ + async createNoteConvertV2026R0( + requestBodyInput: NotesConvertRequestBodyV2026R0Input, + optionalsInput: CreateNoteConvertV2026R0OptionalsInput = {}, + ): Promise { + const requestBody: NotesConvertRequestBodyV2026R0 = + new NotesConvertRequestBodyV2026R0({ + content: requestBodyInput.content, + contentFormat: requestBodyInput.contentFormat, + parent: requestBodyInput.parent, + name: requestBodyInput.name, + }); + const optionals: CreateNoteConvertV2026R0Optionals = + new CreateNoteConvertV2026R0Optionals({ + headers: optionalsInput.headers, + cancellationToken: optionalsInput.cancellationToken, + }); + const headers: any = optionals.headers; + const cancellationToken: any = optionals.cancellationToken; + const headersMap: { + readonly [key: string]: string; + } = prepareParams({ + ...{ ['box-version']: toString(headers.boxVersion) as string }, + ...headers.extraHeaders, + }); + const response: FetchResponse = + await this.networkSession.networkClient.fetch( + new FetchOptions({ + url: ''.concat( + this.networkSession.baseUrls.baseUrl, + '/2.0/notes/convert', + ) as string, + method: 'POST', + headers: headersMap, + data: serializeNotesConvertRequestBodyV2026R0(requestBody), + contentType: 'application/json', + responseFormat: 'json' as ResponseFormat, + auth: this.auth, + networkSession: this.networkSession, + cancellationToken: cancellationToken, + }), + ); + return { + ...deserializeNotesConvertResponseV2026R0(response.data!), + rawData: response.data!, + }; + } +} +export interface ConvertMarkdownToBoxNoteManagerInput { + readonly auth?: Authentication; + readonly networkSession?: NetworkSession; +} diff --git a/src/managers/index.ts b/src/managers/index.ts index 0bd25dff..fb3bdb55 100644 --- a/src/managers/index.ts +++ b/src/managers/index.ts @@ -82,3 +82,4 @@ export * from './shieldLists'; export * from './archives'; export * from './externalUsers'; export * from './automateWorkflows'; +export * from './convertMarkdownToBoxNote'; diff --git a/src/schemas/v2026R0/folderReferenceV2026R0.ts b/src/schemas/v2026R0/folderReferenceV2026R0.ts new file mode 100644 index 00000000..c65c82d8 --- /dev/null +++ b/src/schemas/v2026R0/folderReferenceV2026R0.ts @@ -0,0 +1,132 @@ +import { BoxSdkError } from '../../box/errors'; +import { SerializedData } from '../../serialization/json'; +import { sdIsEmpty } from '../../serialization/json'; +import { sdIsBoolean } from '../../serialization/json'; +import { sdIsNumber } from '../../serialization/json'; +import { sdIsString } from '../../serialization/json'; +import { sdIsList } from '../../serialization/json'; +import { sdIsMap } from '../../serialization/json'; +export type FolderReferenceV2026R0TypeField = 'folder'; +export class FolderReferenceV2026R0 { + /** + * The value will always be `folder`. */ + readonly type: FolderReferenceV2026R0TypeField = + 'folder' as FolderReferenceV2026R0TypeField; + /** + * ID of the folder. */ + readonly id!: string; + readonly rawData?: SerializedData; + constructor( + fields: Omit & + Partial>, + ) { + if (fields.type !== undefined) { + this.type = fields.type; + } + if (fields.id !== undefined) { + this.id = fields.id; + } + if (fields.rawData !== undefined) { + this.rawData = fields.rawData; + } + } +} +export interface FolderReferenceV2026R0Input { + /** + * The value will always be `folder`. */ + readonly type?: FolderReferenceV2026R0TypeField; + /** + * ID of the folder. */ + readonly id: string; + readonly rawData?: SerializedData; +} +export function serializeFolderReferenceV2026R0TypeField( + val: FolderReferenceV2026R0TypeField, +): SerializedData { + return val; +} +export function deserializeFolderReferenceV2026R0TypeField( + val: SerializedData, +): FolderReferenceV2026R0TypeField { + if (val == 'folder') { + return val; + } + throw new BoxSdkError({ + message: "Can't deserialize FolderReferenceV2026R0TypeField", + }); +} +export function serializeFolderReferenceV2026R0( + val: FolderReferenceV2026R0, +): SerializedData { + return { + ['type']: serializeFolderReferenceV2026R0TypeField(val.type), + ['id']: val.id, + }; +} +export function deserializeFolderReferenceV2026R0( + val: SerializedData, +): FolderReferenceV2026R0 { + if (!sdIsMap(val)) { + throw new BoxSdkError({ + message: 'Expecting a map for "FolderReferenceV2026R0"', + }); + } + if (val.type == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "type" of type "FolderReferenceV2026R0" to be defined', + }); + } + const type: FolderReferenceV2026R0TypeField = + deserializeFolderReferenceV2026R0TypeField(val.type); + if (val.id == void 0) { + throw new BoxSdkError({ + message: 'Expecting "id" of type "FolderReferenceV2026R0" to be defined', + }); + } + if (!sdIsString(val.id)) { + throw new BoxSdkError({ + message: 'Expecting string for "id" of type "FolderReferenceV2026R0"', + }); + } + const id: string = val.id; + return { type: type, id: id } satisfies FolderReferenceV2026R0; +} +export function serializeFolderReferenceV2026R0Input( + val: FolderReferenceV2026R0Input, +): SerializedData { + return { + ['type']: + val.type == void 0 + ? val.type + : serializeFolderReferenceV2026R0TypeField(val.type), + ['id']: val.id, + }; +} +export function deserializeFolderReferenceV2026R0Input( + val: SerializedData, +): FolderReferenceV2026R0Input { + if (!sdIsMap(val)) { + throw new BoxSdkError({ + message: 'Expecting a map for "FolderReferenceV2026R0Input"', + }); + } + const type: undefined | FolderReferenceV2026R0TypeField = + val.type == void 0 + ? void 0 + : deserializeFolderReferenceV2026R0TypeField(val.type); + if (val.id == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "id" of type "FolderReferenceV2026R0Input" to be defined', + }); + } + if (!sdIsString(val.id)) { + throw new BoxSdkError({ + message: + 'Expecting string for "id" of type "FolderReferenceV2026R0Input"', + }); + } + const id: string = val.id; + return { type: type, id: id } satisfies FolderReferenceV2026R0Input; +} diff --git a/src/schemas/v2026R0/index.ts b/src/schemas/v2026R0/index.ts index ad6b8e4a..64d753c2 100644 --- a/src/schemas/v2026R0/index.ts +++ b/src/schemas/v2026R0/index.ts @@ -1,6 +1,9 @@ export * from './automateWorkflowReferenceV2026R0'; export * from './automateWorkflowStartRequestV2026R0'; export * from './clientErrorV2026R0'; +export * from './folderReferenceV2026R0'; +export * from './notesConvertRequestBodyV2026R0'; +export * from './notesConvertResponseV2026R0'; export * from './userBaseV2026R0'; export * from './userMiniV2026R0'; export * from './automateWorkflowActionV2026R0'; diff --git a/src/schemas/v2026R0/notesConvertRequestBodyV2026R0.ts b/src/schemas/v2026R0/notesConvertRequestBodyV2026R0.ts new file mode 100644 index 00000000..84addb6b --- /dev/null +++ b/src/schemas/v2026R0/notesConvertRequestBodyV2026R0.ts @@ -0,0 +1,226 @@ +import { serializeFolderReferenceV2026R0 } from './folderReferenceV2026R0'; +import { deserializeFolderReferenceV2026R0 } from './folderReferenceV2026R0'; +import { FolderReferenceV2026R0 } from './folderReferenceV2026R0'; +import { BoxSdkError } from '../../box/errors'; +import { SerializedData } from '../../serialization/json'; +import { sdIsEmpty } from '../../serialization/json'; +import { sdIsBoolean } from '../../serialization/json'; +import { sdIsNumber } from '../../serialization/json'; +import { sdIsString } from '../../serialization/json'; +import { sdIsList } from '../../serialization/json'; +import { sdIsMap } from '../../serialization/json'; +export type NotesConvertRequestBodyV2026R0ContentFormatField = + | 'markdown' + | string; +export class NotesConvertRequestBodyV2026R0 { + /** + * The content to convert to a note. See the `content_format` field for supported formats. */ + readonly content!: string; + /** + * Format of the content to convert. */ + readonly contentFormat: NotesConvertRequestBodyV2026R0ContentFormatField = + 'markdown' as NotesConvertRequestBodyV2026R0ContentFormatField; + readonly parent!: FolderReferenceV2026R0; + /** + * The name for the created note. The `.boxnote` extension is appended automatically. */ + readonly name!: string; + readonly rawData?: SerializedData; + constructor( + fields: Omit & + Partial>, + ) { + if (fields.content !== undefined) { + this.content = fields.content; + } + if (fields.contentFormat !== undefined) { + this.contentFormat = fields.contentFormat; + } + if (fields.parent !== undefined) { + this.parent = fields.parent; + } + if (fields.name !== undefined) { + this.name = fields.name; + } + if (fields.rawData !== undefined) { + this.rawData = fields.rawData; + } + } +} +export interface NotesConvertRequestBodyV2026R0Input { + /** + * The content to convert to a note. See the `content_format` field for supported formats. */ + readonly content: string; + /** + * Format of the content to convert. */ + readonly contentFormat?: NotesConvertRequestBodyV2026R0ContentFormatField; + readonly parent: FolderReferenceV2026R0; + /** + * The name for the created note. The `.boxnote` extension is appended automatically. */ + readonly name: string; + readonly rawData?: SerializedData; +} +export function serializeNotesConvertRequestBodyV2026R0ContentFormatField( + val: NotesConvertRequestBodyV2026R0ContentFormatField, +): SerializedData { + return val; +} +export function deserializeNotesConvertRequestBodyV2026R0ContentFormatField( + val: SerializedData, +): NotesConvertRequestBodyV2026R0ContentFormatField { + if (val == 'markdown') { + return val; + } + if (sdIsString(val)) { + return val; + } + throw new BoxSdkError({ + message: + "Can't deserialize NotesConvertRequestBodyV2026R0ContentFormatField", + }); +} +export function serializeNotesConvertRequestBodyV2026R0( + val: NotesConvertRequestBodyV2026R0, +): SerializedData { + return { + ['content']: val.content, + ['content_format']: + serializeNotesConvertRequestBodyV2026R0ContentFormatField( + val.contentFormat, + ), + ['parent']: serializeFolderReferenceV2026R0(val.parent), + ['name']: val.name, + }; +} +export function deserializeNotesConvertRequestBodyV2026R0( + val: SerializedData, +): NotesConvertRequestBodyV2026R0 { + if (!sdIsMap(val)) { + throw new BoxSdkError({ + message: 'Expecting a map for "NotesConvertRequestBodyV2026R0"', + }); + } + if (val.content == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "content" of type "NotesConvertRequestBodyV2026R0" to be defined', + }); + } + if (!sdIsString(val.content)) { + throw new BoxSdkError({ + message: + 'Expecting string for "content" of type "NotesConvertRequestBodyV2026R0"', + }); + } + const content: string = val.content; + if (val.content_format == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "content_format" of type "NotesConvertRequestBodyV2026R0" to be defined', + }); + } + const contentFormat: NotesConvertRequestBodyV2026R0ContentFormatField = + deserializeNotesConvertRequestBodyV2026R0ContentFormatField( + val.content_format, + ); + if (val.parent == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "parent" of type "NotesConvertRequestBodyV2026R0" to be defined', + }); + } + const parent: FolderReferenceV2026R0 = deserializeFolderReferenceV2026R0( + val.parent, + ); + if (val.name == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "name" of type "NotesConvertRequestBodyV2026R0" to be defined', + }); + } + if (!sdIsString(val.name)) { + throw new BoxSdkError({ + message: + 'Expecting string for "name" of type "NotesConvertRequestBodyV2026R0"', + }); + } + const name: string = val.name; + return { + content: content, + contentFormat: contentFormat, + parent: parent, + name: name, + } satisfies NotesConvertRequestBodyV2026R0; +} +export function serializeNotesConvertRequestBodyV2026R0Input( + val: NotesConvertRequestBodyV2026R0Input, +): SerializedData { + return { + ['content']: val.content, + ['contentFormat']: + val.contentFormat == void 0 + ? val.contentFormat + : serializeNotesConvertRequestBodyV2026R0ContentFormatField( + val.contentFormat, + ), + ['parent']: serializeFolderReferenceV2026R0(val.parent), + ['name']: val.name, + }; +} +export function deserializeNotesConvertRequestBodyV2026R0Input( + val: SerializedData, +): NotesConvertRequestBodyV2026R0Input { + if (!sdIsMap(val)) { + throw new BoxSdkError({ + message: 'Expecting a map for "NotesConvertRequestBodyV2026R0Input"', + }); + } + if (val.content == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "content" of type "NotesConvertRequestBodyV2026R0Input" to be defined', + }); + } + if (!sdIsString(val.content)) { + throw new BoxSdkError({ + message: + 'Expecting string for "content" of type "NotesConvertRequestBodyV2026R0Input"', + }); + } + const content: string = val.content; + const contentFormat: + | undefined + | NotesConvertRequestBodyV2026R0ContentFormatField = + val.contentFormat == void 0 + ? void 0 + : deserializeNotesConvertRequestBodyV2026R0ContentFormatField( + val.contentFormat, + ); + if (val.parent == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "parent" of type "NotesConvertRequestBodyV2026R0Input" to be defined', + }); + } + const parent: FolderReferenceV2026R0 = deserializeFolderReferenceV2026R0( + val.parent, + ); + if (val.name == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "name" of type "NotesConvertRequestBodyV2026R0Input" to be defined', + }); + } + if (!sdIsString(val.name)) { + throw new BoxSdkError({ + message: + 'Expecting string for "name" of type "NotesConvertRequestBodyV2026R0Input"', + }); + } + const name: string = val.name; + return { + content: content, + contentFormat: contentFormat, + parent: parent, + name: name, + } satisfies NotesConvertRequestBodyV2026R0Input; +} diff --git a/src/schemas/v2026R0/notesConvertResponseV2026R0.ts b/src/schemas/v2026R0/notesConvertResponseV2026R0.ts new file mode 100644 index 00000000..e779e244 --- /dev/null +++ b/src/schemas/v2026R0/notesConvertResponseV2026R0.ts @@ -0,0 +1,134 @@ +import { BoxSdkError } from '../../box/errors'; +import { SerializedData } from '../../serialization/json'; +import { sdIsEmpty } from '../../serialization/json'; +import { sdIsBoolean } from '../../serialization/json'; +import { sdIsNumber } from '../../serialization/json'; +import { sdIsString } from '../../serialization/json'; +import { sdIsList } from '../../serialization/json'; +import { sdIsMap } from '../../serialization/json'; +export type NotesConvertResponseV2026R0TypeField = 'file'; +export class NotesConvertResponseV2026R0 { + /** + * The Box resource type; always `file` for a Box file. */ + readonly type: NotesConvertResponseV2026R0TypeField = + 'file' as NotesConvertResponseV2026R0TypeField; + /** + * Box file ID of the created `.boxnote` file. */ + readonly id!: string; + readonly rawData?: SerializedData; + constructor( + fields: Omit & + Partial>, + ) { + if (fields.type !== undefined) { + this.type = fields.type; + } + if (fields.id !== undefined) { + this.id = fields.id; + } + if (fields.rawData !== undefined) { + this.rawData = fields.rawData; + } + } +} +export interface NotesConvertResponseV2026R0Input { + /** + * The Box resource type; always `file` for a Box file. */ + readonly type?: NotesConvertResponseV2026R0TypeField; + /** + * Box file ID of the created `.boxnote` file. */ + readonly id: string; + readonly rawData?: SerializedData; +} +export function serializeNotesConvertResponseV2026R0TypeField( + val: NotesConvertResponseV2026R0TypeField, +): SerializedData { + return val; +} +export function deserializeNotesConvertResponseV2026R0TypeField( + val: SerializedData, +): NotesConvertResponseV2026R0TypeField { + if (val == 'file') { + return val; + } + throw new BoxSdkError({ + message: "Can't deserialize NotesConvertResponseV2026R0TypeField", + }); +} +export function serializeNotesConvertResponseV2026R0( + val: NotesConvertResponseV2026R0, +): SerializedData { + return { + ['type']: serializeNotesConvertResponseV2026R0TypeField(val.type), + ['id']: val.id, + }; +} +export function deserializeNotesConvertResponseV2026R0( + val: SerializedData, +): NotesConvertResponseV2026R0 { + if (!sdIsMap(val)) { + throw new BoxSdkError({ + message: 'Expecting a map for "NotesConvertResponseV2026R0"', + }); + } + if (val.type == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "type" of type "NotesConvertResponseV2026R0" to be defined', + }); + } + const type: NotesConvertResponseV2026R0TypeField = + deserializeNotesConvertResponseV2026R0TypeField(val.type); + if (val.id == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "id" of type "NotesConvertResponseV2026R0" to be defined', + }); + } + if (!sdIsString(val.id)) { + throw new BoxSdkError({ + message: + 'Expecting string for "id" of type "NotesConvertResponseV2026R0"', + }); + } + const id: string = val.id; + return { type: type, id: id } satisfies NotesConvertResponseV2026R0; +} +export function serializeNotesConvertResponseV2026R0Input( + val: NotesConvertResponseV2026R0Input, +): SerializedData { + return { + ['type']: + val.type == void 0 + ? val.type + : serializeNotesConvertResponseV2026R0TypeField(val.type), + ['id']: val.id, + }; +} +export function deserializeNotesConvertResponseV2026R0Input( + val: SerializedData, +): NotesConvertResponseV2026R0Input { + if (!sdIsMap(val)) { + throw new BoxSdkError({ + message: 'Expecting a map for "NotesConvertResponseV2026R0Input"', + }); + } + const type: undefined | NotesConvertResponseV2026R0TypeField = + val.type == void 0 + ? void 0 + : deserializeNotesConvertResponseV2026R0TypeField(val.type); + if (val.id == void 0) { + throw new BoxSdkError({ + message: + 'Expecting "id" of type "NotesConvertResponseV2026R0Input" to be defined', + }); + } + if (!sdIsString(val.id)) { + throw new BoxSdkError({ + message: + 'Expecting string for "id" of type "NotesConvertResponseV2026R0Input"', + }); + } + const id: string = val.id; + return { type: type, id: id } satisfies NotesConvertResponseV2026R0Input; +} From a96dca37e0c68eea5719a136dea6c4a34de39322 Mon Sep 17 00:00:00 2001 From: box-sdk-build Date: Wed, 20 May 2026 09:40:47 -0700 Subject: [PATCH 2/4] test: migrate test browser from `next` to `vite` (box/box-codegen#953) --- .codegen.json | 2 +- test-browser/.gitignore | 29 +---- test-browser/README.md | 2 +- test-browser/eslint.config.mjs | 16 --- test-browser/index.html | 30 +++++ test-browser/next.config.ts | 9 -- test-browser/package.json | 25 ++-- test-browser/pages/api/env.ts | 15 --- test-browser/src/app/favicon.ico | Bin 25931 -> 0 bytes test-browser/src/app/globals.css | 29 ----- test-browser/src/app/layout.tsx | 31 ----- test-browser/src/app/page.module.css | 24 ---- test-browser/src/app/page.tsx | 154 ------------------------- test-browser/src/main.ts | 91 +++++++++++++++ test-browser/src/shims/node-fetch.ts | 4 + test-browser/src/styles.css | 100 ++++++++++++++++ test-browser/src/utils/testRegistry.ts | 133 +++++++++------------ test-browser/tsconfig.json | 17 +-- test-browser/vite.config.ts | 56 +++++++++ 19 files changed, 356 insertions(+), 411 deletions(-) delete mode 100644 test-browser/eslint.config.mjs create mode 100644 test-browser/index.html delete mode 100644 test-browser/next.config.ts delete mode 100644 test-browser/pages/api/env.ts delete mode 100644 test-browser/src/app/favicon.ico delete mode 100644 test-browser/src/app/globals.css delete mode 100644 test-browser/src/app/layout.tsx delete mode 100644 test-browser/src/app/page.module.css delete mode 100644 test-browser/src/app/page.tsx create mode 100644 test-browser/src/main.ts create mode 100644 test-browser/src/shims/node-fetch.ts create mode 100644 test-browser/src/styles.css create mode 100644 test-browser/vite.config.ts diff --git a/.codegen.json b/.codegen.json index a8e4873c..d8ee1683 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "4de40e1", "specHash": "8b85e74", "version": "10.10.0" } +{ "engineHash": "8196e61", "specHash": "8b85e74", "version": "10.10.0" } diff --git a/test-browser/.gitignore b/test-browser/.gitignore index 76c1c042..6b0409c1 100644 --- a/test-browser/.gitignore +++ b/test-browser/.gitignore @@ -1,24 +1,11 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - # dependencies /node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions # testing /coverage -# next.js -/.next/ -/out/ - # production -/build +/dist # misc .DS_Store @@ -26,21 +13,17 @@ # debug npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* -# env files (can opt-in for committing if needed) +# env files .env* -# vercel -.vercel - # typescript *.tsbuildinfo -next-env.d.ts + +# generated +src/utils/importTests.ts # cypress cypress/screenshots cypress/videos -cypress/downloads \ No newline at end of file +cypress/downloads diff --git a/test-browser/README.md b/test-browser/README.md index 5b0de9c5..147d544c 100644 --- a/test-browser/README.md +++ b/test-browser/README.md @@ -1,6 +1,6 @@ # Box TypeScript SDK Gen Browser Test Runner -A browser-based test runner for Box TypeScript SDK, built with Next.js and Cypress. +A browser-based test runner for Box TypeScript SDK, built with Vite and Cypress. ## Features diff --git a/test-browser/eslint.config.mjs b/test-browser/eslint.config.mjs deleted file mode 100644 index 7f86eca7..00000000 --- a/test-browser/eslint.config.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { FlatCompat } from '@eslint/eslintrc'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -const compat = new FlatCompat({ - baseDirectory: __dirname, -}); - -const eslintConfig = [ - ...compat.extends('next/core-web-vitals', 'next/typescript'), -]; - -export default eslintConfig; diff --git a/test-browser/index.html b/test-browser/index.html new file mode 100644 index 00000000..5d8aa4a8 --- /dev/null +++ b/test-browser/index.html @@ -0,0 +1,30 @@ + + + + + + Browser Test + + + +
+
+

Test Results

+
+ + + + + + + + + + + +
Test NameStatusDurationErrorActions
+
+
+ + + diff --git a/test-browser/next.config.ts b/test-browser/next.config.ts deleted file mode 100644 index fa5c7fc9..00000000 --- a/test-browser/next.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { NextConfig } from 'next'; -import path from 'path'; - -const nextConfig: NextConfig = { - /* config options here */ - outputFileTracingRoot: path.join(__dirname, '../'), -}; - -export default nextConfig; diff --git a/test-browser/package.json b/test-browser/package.json index 277bc8dc..ec22b126 100644 --- a/test-browser/package.json +++ b/test-browser/package.json @@ -2,35 +2,28 @@ "name": "box-node-sdk-browser-test", "version": "0.1.0", "private": true, + "type": "module", "scripts": { - "dev": "npm run prebuild && next dev --turbopack", + "dev": "npm run prebuild && vite", "prebuild": "tsx init.ts", - "build": "next build", - "build:dev": "NODE_ENV=development next build", + "build": "npm run prebuild && vite build", + "start": "vite preview", "build-run": "npm run build && npm run start", - "start": "next start", - "lint": "next lint", "cypress:open": "cypress open", "cypress:run": "cypress run", "cypress:run:all": "npm run cypress:run:chrome && npm run cypress:run:firefox", - "cypress:run:chrome": "start-server-and-test build-run 3000 'cypress run --browser chrome'", - "cypress:run:firefox": "start-server-and-test build-run 3000 'cypress run --browser firefox'" + "cypress:run:chrome": "start-server-and-test 'npm run build-run' http://localhost:3000 'cypress run --browser chrome'", + "cypress:run:firefox": "start-server-and-test 'npm run build-run' http://localhost:3000 'cypress run --browser firefox'" }, "dependencies": { - "box-node-sdk": "file:../", - "next": "15.5.18", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "box-node-sdk": "file:../" }, "devDependencies": { "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", "cypress": "^14.5.3", - "eslint": "^9", - "eslint-config-next": "15.4.10", "start-server-and-test": "^2.0.11", "tsx": "^4.20.3", - "typescript": "^5" + "typescript": "^5", + "vite": "^6.0.0" } } diff --git a/test-browser/pages/api/env.ts b/test-browser/pages/api/env.ts deleted file mode 100644 index 7b63d593..00000000 --- a/test-browser/pages/api/env.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { testEnvList } from '../../sdkTest.config.mjs'; - -export default function handler(req: NextApiRequest, res: NextApiResponse) { - try { - const envObject = Object.fromEntries( - testEnvList.map((env) => [env, process.env[env]]), - ); - res.status(200).json(envObject); - } catch (error) { - res.status(500).json({ - error: error instanceof Error ? error.message : 'Unknown error', - }); - } -} diff --git a/test-browser/src/app/favicon.ico b/test-browser/src/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/test-browser/src/app/globals.css b/test-browser/src/app/globals.css deleted file mode 100644 index 9925df3f..00000000 --- a/test-browser/src/app/globals.css +++ /dev/null @@ -1,29 +0,0 @@ -:root { - --background: #ffffff; - --foreground: #171717; -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -a { - color: inherit; - text-decoration: none; -} diff --git a/test-browser/src/app/layout.tsx b/test-browser/src/app/layout.tsx deleted file mode 100644 index d96094a3..00000000 --- a/test-browser/src/app/layout.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type { Metadata } from 'next'; -import { Geist, Geist_Mono } from 'next/font/google'; -import './globals.css'; - -const geistSans = Geist({ - variable: '--font-geist-sans', - subsets: ['latin'], -}); - -const geistMono = Geist_Mono({ - variable: '--font-geist-mono', - subsets: ['latin'], -}); - -export const metadata: Metadata = { - title: 'Browser Test', -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {children} - - - ); -} diff --git a/test-browser/src/app/page.module.css b/test-browser/src/app/page.module.css deleted file mode 100644 index 107990b8..00000000 --- a/test-browser/src/app/page.module.css +++ /dev/null @@ -1,24 +0,0 @@ -.page { - --gray-rgb: 0, 0, 0; - --gray-alpha-200: rgba(var(--gray-rgb), 0.08); - --gray-alpha-100: rgba(var(--gray-rgb), 0.05); - - --button-primary-hover: #383838; - --button-secondary-hover: #f2f2f2; - - display: grid; - grid-template-rows: 20px 1fr 20px; - align-items: center; - justify-items: center; - min-height: 100svh; - padding: 0px 80px; - gap: 64px; - font-family: var(--font-geist-sans); -} - -.main { - display: flex; - flex-direction: column; - gap: 32px; - grid-row-start: 2; -} diff --git a/test-browser/src/app/page.tsx b/test-browser/src/app/page.tsx deleted file mode 100644 index 6a3c2761..00000000 --- a/test-browser/src/app/page.tsx +++ /dev/null @@ -1,154 +0,0 @@ -'use client'; - -import styles from './page.module.css'; -import { useEffect, useState } from 'react'; -import { setEnvVar } from 'box-node-sdk/internal'; -import { setupExpect } from '@/utils/expect'; -import { TestResult, createTestRegistry } from '@/utils/testRegistry'; -import { testConfig } from '@/../sdkTest.config.mjs'; - -declare global { - interface Window { - testRegistry: ReturnType; - test: (name: string, fn: () => Promise) => void; - } -} - -export default function Home() { - const [testResults, setTestResults] = useState([]); - const [error, setError] = useState(); - - const registerTestMethod = () => { - window.testRegistry = createTestRegistry(setTestResults, setError); - // @ts-expect-error - Ignore Mocha TestFunction type conflict - window.test = async (name: string, fn: () => Promise) => { - window.testRegistry.register(name, fn); - if (testConfig[name as keyof typeof testConfig] === 'skip') { - console.log(`Skipping test: ${name}`); - setTestResults((prev) => - prev.map((r) => (r.name === name ? { ...r, status: 'skipped' } : r)), - ); - } - }; - }; - - const setupEnvironment = async () => { - await fetch('/api/env') - .then((res) => res.json()) - .then((data) => { - for (const [key, value] of Object.entries(data)) { - setEnvVar(key, value as string); - } - }); - }; - - useEffect(() => { - registerTestMethod(); - setupExpect(); - setupEnvironment().then(async () => { - try { - await import('../utils/importTests'); - setTimeout(() => { - window.testRegistry.runAll(); - }, 3000); - } catch (e) { - setError( - e instanceof Error ? e.message : 'Failed to import test files', - ); - } - }); - }, []); - - // Add new useEffect to update test results label - useEffect(() => { - const passed = testResults.filter((r) => r.status === 'passed').length; - const failed = testResults.filter((r) => r.status === 'failed').length; - const running = testResults.filter((r) => r.status === 'running').length; - const skipped = testResults.filter((r) => r.status === 'skipped').length; - const total = testResults.length; - setError( - `Test Results: ${passed}/${total} passed, ${running} running, ${failed} failed, ${skipped} skipped`, - ); - }, [testResults]); - - const getStatusColor = (status: TestResult['status']) => { - switch (status) { - case 'passed': - return 'green'; - case 'failed': - return 'red'; - case 'running': - return 'orange'; - case 'skipped': - return 'gray'; - default: - return 'gray'; - } - }; - - const formatDuration = (startTime?: Date, endTime?: Date) => { - if (!startTime || !endTime) return '-'; - const duration = endTime.getTime() - startTime.getTime(); - return `${duration}ms`; - }; - - return ( -
-
-

Test Results

- {error && ( -
- Error: {error} -
- )} - - - - - - - - - - - - {testResults.map((result, index) => ( - - - - - - - - ))} - -
Test NameStatusDurationErrorActions
{result.name} - {result.status.toUpperCase()} - - {formatDuration(result.startTime, result.endTime)} - {result.error} - -
-
-
- ); -} diff --git a/test-browser/src/main.ts b/test-browser/src/main.ts new file mode 100644 index 00000000..0ad265ff --- /dev/null +++ b/test-browser/src/main.ts @@ -0,0 +1,91 @@ +import { setEnvVar } from 'box-node-sdk/internal'; +import { setupExpect } from './utils/expect'; +import { createTestRegistry } from './utils/testRegistry'; +import { testConfig } from '../sdkTest.config.mjs'; + +declare global { + interface Window { + testRegistry: ReturnType; + test: (name: string, fn: () => Promise) => void; + } +} + +const statusEl = document.getElementById('status')!; +const tbodyEl = document.getElementById('test-results')!; + +function updateStatus() { + const rows = tbodyEl.querySelectorAll('tr'); + let passed = 0, + failed = 0, + running = 0, + skipped = 0; + rows.forEach((row) => { + const status = row.dataset.status; + if (status === 'passed') passed++; + else if (status === 'failed') failed++; + else if (status === 'running') running++; + else if (status === 'skipped') skipped++; + }); + const total = rows.length; + statusEl.textContent = `Test Results: ${passed}/${total} passed, ${running} running, ${failed} failed, ${skipped} skipped`; +} + +function renderRow( + name: string, + status: string, + duration: string, + error: string, +) { + let row = tbodyEl.querySelector( + `tr[data-test="${CSS.escape(name)}"]`, + ) as HTMLTableRowElement | null; + if (!row) { + row = document.createElement('tr'); + row.dataset.test = name; + tbodyEl.appendChild(row); + } + row.dataset.status = status; + row.innerHTML = ` + ${name} + ${status.toUpperCase()} + ${duration} + ${error} + + `; + row.querySelector('button')!.addEventListener('click', () => { + window.testRegistry.runByName(name); + }); + updateStatus(); +} + +window.testRegistry = createTestRegistry(renderRow); + +window.test = (name: string, fn: () => Promise) => { + window.testRegistry.register(name, fn); + if (testConfig[name as keyof typeof testConfig] === 'skip') { + console.log(`Skipping test: ${name}`); + renderRow(name, 'skipped', '-', ''); + } +}; + +setupExpect(); + +async function init() { + const res = await fetch('/api/env'); + const data = await res.json(); + for (const [key, value] of Object.entries(data)) { + setEnvVar(key, value as string); + } + + try { + await import('./utils/importTests'); + setTimeout(() => { + window.testRegistry.runAll(); + }, 3000); + } catch (e) { + statusEl.textContent = + e instanceof Error ? e.message : 'Failed to import test files'; + } +} + +init(); diff --git a/test-browser/src/shims/node-fetch.ts b/test-browser/src/shims/node-fetch.ts new file mode 100644 index 00000000..b3deda51 --- /dev/null +++ b/test-browser/src/shims/node-fetch.ts @@ -0,0 +1,4 @@ +export default fetch; +export const Headers = globalThis.Headers; +export const Request = globalThis.Request; +export const Response = globalThis.Response; diff --git a/test-browser/src/styles.css b/test-browser/src/styles.css new file mode 100644 index 00000000..7350dc51 --- /dev/null +++ b/test-browser/src/styles.css @@ -0,0 +1,100 @@ +:root { + --background: #ffffff; + --foreground: #171717; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + color: var(--foreground); + background: var(--background); + font-family: Arial, Helvetica, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +#app { + display: grid; + grid-template-rows: 20px 1fr 20px; + align-items: center; + justify-items: center; + min-height: 100svh; + padding: 0 80px; + gap: 64px; +} + +main { + display: flex; + flex-direction: column; + gap: 32px; + grid-row-start: 2; + width: 100%; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th { + text-align: left; + padding: 8px; +} + +td { + padding: 8px; +} + +tr + tr { + border-top: 1px solid #ddd; +} + +#status { + color: red; + margin-bottom: 1rem; +} + +.status-passed { + color: green; +} +.status-failed { + color: red; +} +.status-running { + color: orange; +} +.status-skipped { + color: gray; +} +.status-not_started { + color: gray; +} + +.error-cell { + color: red; +} + +button { + padding: 4px 8px; + background-color: #0070f3; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} + +button:disabled { + opacity: 0.5; + cursor: not-allowed; +} diff --git a/test-browser/src/utils/testRegistry.ts b/test-browser/src/utils/testRegistry.ts index 466059d2..948569cf 100644 --- a/test-browser/src/utils/testRegistry.ts +++ b/test-browser/src/utils/testRegistry.ts @@ -8,6 +8,13 @@ export type TestResult = { endTime?: Date; }; +export type RenderFn = ( + name: string, + status: string, + duration: string, + error: string, +) => void; + export type TestRegistry = { tests: Array<{ name: string; fn: () => Promise }>; register: (name: string, fn: () => Promise) => void; @@ -15,16 +22,21 @@ export type TestRegistry = { runByName: (name: string) => Promise; }; -export function createTestRegistry( - setTestResults: React.Dispatch>, - setError: React.Dispatch>, -): TestRegistry { +function formatDuration(startTime?: Date, endTime?: Date): string { + if (!startTime || !endTime) return '-'; + return `${endTime.getTime() - startTime.getTime()}ms`; +} + +export function createTestRegistry(render: RenderFn): TestRegistry { + const results = new Map(); + return { tests: [] as Array<{ name: string; fn: () => Promise }>, register(name: string, fn: () => Promise) { this.tests.push({ name, fn }); - setTestResults((prev) => [...prev, { name, status: 'not_started' }]); + results.set(name, { name, status: 'not_started' }); + render(name, 'not_started', '-', ''); console.log(`Registered test: ${name}`); }, @@ -33,99 +45,66 @@ export function createTestRegistry( `Running ${this.tests.length} tests with 10 concurrent tests...`, ); - try { - const concurrencyLimit = 10; - const runningTests = new Set(); - const testQueue = [...this.tests]; + const concurrencyLimit = 10; + const runningTests = new Set(); + const testQueue = [...this.tests]; - // Function to run next test if we have capacity - const runNextTest = async () => { - if (runningTests.size >= concurrencyLimit || testQueue.length === 0) { - return; - } + const runNextTest = async () => { + if (runningTests.size >= concurrencyLimit || testQueue.length === 0) { + return; + } - const test = testQueue.shift()!; - runningTests.add(test.name); + const test = testQueue.shift()!; + runningTests.add(test.name); - try { - await this.runByName(test.name); - } finally { - runningTests.delete(test.name); - // Try to run another test if we have capacity - await runNextTest(); - } - }; + try { + await this.runByName(test.name); + } finally { + runningTests.delete(test.name); + await runNextTest(); + } + }; - // Start initial tests up to concurrency limit - const initialTests = Math.min(concurrencyLimit, testQueue.length); - await Promise.all( - Array(initialTests) - .fill(null) - .map(() => runNextTest()), - ); - } catch (e) { - console.error('Error running tests:', e); - setError( - 'Error running tests: ' + - (e instanceof Error ? e.message : 'Unknown error'), - ); - } + const initialTests = Math.min(concurrencyLimit, testQueue.length); + await Promise.all( + Array(initialTests) + .fill(null) + .map(() => runNextTest()), + ); }, async runByName(name: string) { - const test = this.tests.find( - (t: { name: string; fn: () => Promise }) => t.name === name, - ); + const test = this.tests.find((t) => t.name === name); if (!test) { console.error(`Test not found: ${name}`); return; } if (testConfig[name as keyof typeof testConfig] === 'skip') { console.log(`Skipping test: ${name}`); - setTestResults((prev) => - prev.map((r) => - r.name === test.name ? { ...r, status: 'skipped' } : r, - ), - ); + results.set(name, { name, status: 'skipped' }); + render(name, 'skipped', '-', ''); return; } try { - setTestResults((prev) => - prev.map((r) => - r.name === test.name - ? { - ...r, - status: 'running', - startTime: new Date(), - endTime: undefined, - error: undefined, - } - : r, - ), - ); + const startTime = new Date(); + results.set(name, { name, status: 'running', startTime }); + render(name, 'running', '-', ''); console.log(`Running test: ${test.name}`); await test.fn(); - setTestResults((prev) => - prev.map((r) => - r.name === test.name - ? { - ...r, - status: 'passed', - endTime: new Date(), - error: undefined, - } - : r, - ), - ); + const endTime = new Date(); + results.set(name, { name, status: 'passed', startTime, endTime }); + render(name, 'passed', formatDuration(startTime, endTime), ''); console.log(`✓ Test passed: ${test.name}`); } catch (e) { const error = e instanceof Error ? e.message : 'Unknown error'; - setTestResults((prev) => - prev.map((r) => - r.name === test.name - ? { ...r, status: 'failed', error, endTime: new Date() } - : r, - ), + const result = results.get(name)!; + const endTime = new Date(); + results.set(name, { ...result, status: 'failed', error, endTime }); + render( + name, + 'failed', + formatDuration(result.startTime, endTime), + error, ); console.error(`✗ Test failed: ${test.name}`, e); } diff --git a/test-browser/tsconfig.json b/test-browser/tsconfig.json index cd69de88..84be0395 100644 --- a/test-browser/tsconfig.json +++ b/test-browser/tsconfig.json @@ -11,23 +11,10 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], "paths": { "@/*": ["./src/*"] } }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - "sdkTest.config.mjs" - ], - "exclude": ["node_modules", ".next"] + "include": ["**/*.ts", "sdkTest.config.mjs"], + "exclude": ["node_modules", "dist"] } diff --git a/test-browser/vite.config.ts b/test-browser/vite.config.ts new file mode 100644 index 00000000..c8390c31 --- /dev/null +++ b/test-browser/vite.config.ts @@ -0,0 +1,56 @@ +import { defineConfig } from 'vite'; +import path from 'path'; +import { testEnvList } from './sdkTest.config.mjs'; + +export default defineConfig({ + define: { + global: 'globalThis', + }, + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + 'node-fetch': path.resolve(__dirname, 'src/shims/node-fetch.ts'), + }, + preserveSymlinks: true, + }, + optimizeDeps: { + include: ['box-node-sdk'], + }, + build: { + commonjsOptions: { + include: [/box-node-sdk/, /node_modules/], + transformMixedEsModules: true, + }, + }, + server: { + port: 3000, + strictPort: true, + }, + preview: { + port: 3000, + strictPort: true, + }, + plugins: [ + { + name: 'env-api', + configureServer(server) { + server.middlewares.use('/api/env', (_req, res) => { + const envObject = Object.fromEntries( + testEnvList.map((env: string) => [env, process.env[env]]), + ); + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(envObject)); + }); + }, + configurePreviewServer(server) { + server.middlewares.use('/api/env', (_req, res) => { + const envObject = Object.fromEntries( + testEnvList.map((env: string) => [env, process.env[env]]), + ); + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(envObject)); + }); + }, + }, + ], +}); From c2413eebf52d90f23da7c4efed46b77d0afc22fb Mon Sep 17 00:00:00 2001 From: box-sdk-build Date: Thu, 21 May 2026 03:20:23 -0700 Subject: [PATCH 3/4] test: update browser Github Actions command (box/box-codegen#954) --- .codegen.json | 2 +- .github/workflows/build_and_test_browser.yml | 4 ++-- .github/workflows/build_and_test_browser_daily.yml | 2 +- package-lock.json | 11 +++++++---- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.codegen.json b/.codegen.json index d8ee1683..2d3398d1 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "8196e61", "specHash": "8b85e74", "version": "10.10.0" } +{ "engineHash": "5e9332b", "specHash": "8b85e74", "version": "10.10.0" } diff --git a/.github/workflows/build_and_test_browser.yml b/.github/workflows/build_and_test_browser.yml index 807aad8c..d503bbce 100644 --- a/.github/workflows/build_and_test_browser.yml +++ b/.github/workflows/build_and_test_browser.yml @@ -58,7 +58,7 @@ jobs: run: | cd test-browser npm install - npx start-server-and-test build-run 3000 'cypress run --browser ${{ matrix.browser }}' + npx start-server-and-test 'npm run build-run' http://localhost:3000 'cypress run --browser ${{ matrix.browser }}' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JWT_CONFIG_BASE_64: ${{ secrets.JWT_CONFIG_BASE_64 }} @@ -83,7 +83,7 @@ jobs: run: | cd test-browser npm install - npx start-server-and-test build-run 3000 'cypress run --browser ${{ matrix.browser }}' + npx start-server-and-test 'npm run build-run' http://localhost:3000 'cypress run --browser ${{ matrix.browser }}' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JWT_CONFIG_BASE_64: ${{ secrets.JWT_CONFIG_BASE_64 }} diff --git a/.github/workflows/build_and_test_browser_daily.yml b/.github/workflows/build_and_test_browser_daily.yml index 841c9d11..afd72847 100644 --- a/.github/workflows/build_and_test_browser_daily.yml +++ b/.github/workflows/build_and_test_browser_daily.yml @@ -30,7 +30,7 @@ jobs: run: | cd test-browser npm install - npx start-server-and-test build-run 3000 'cypress run --browser ${{ matrix.browser }}' + npx start-server-and-test 'npm run build-run' http://localhost:3000 'cypress run --browser ${{ matrix.browser }}' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JWT_CONFIG_BASE_64: ${{ secrets.JWT_CONFIG_BASE_64 }} diff --git a/package-lock.json b/package-lock.json index 5d1fdd0d..88964b06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4854,11 +4854,14 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.44", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", - "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", + "version": "2.0.45", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.45.tgz", + "integrity": "sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/normalize-path": { "version": "3.0.0", From 96ed0369b97de83f4b1f031e108187aa7112893b Mon Sep 17 00:00:00 2001 From: box-sdk-build Date: Thu, 21 May 2026 08:20:33 -0700 Subject: [PATCH 4/4] fix: rename tag for notes API (box/box-openapi#600) --- .codegen.json | 2 +- docs/README.md | 2 +- docs/{convertMarkdownToBoxNote.md => notes.md} | 2 +- package-lock.json | 12 ++++++------ src/client.ts | 8 ++++---- src/managers/index.ts | 2 +- .../{convertMarkdownToBoxNote.ts => notes.ts} | 11 ++++------- src/schemas/signRequest.ts | 4 ++++ 8 files changed, 22 insertions(+), 21 deletions(-) rename docs/{convertMarkdownToBoxNote.md => notes.md} (95%) rename src/managers/{convertMarkdownToBoxNote.ts => notes.ts} (95%) diff --git a/.codegen.json b/.codegen.json index 2d3398d1..f10b8e29 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "5e9332b", "specHash": "8b85e74", "version": "10.10.0" } +{ "engineHash": "5e9332b", "specHash": "d028758", "version": "10.10.0" } diff --git a/docs/README.md b/docs/README.md index a485eb30..47380abd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,7 +26,6 @@ the SDK are available by topic: - [Collaboration allowlist exempt targets](collaborationAllowlistExemptTargets.md) - [Collections](collections.md) - [Comments](comments.md) -- [Convert markdown to box note](convertMarkdownToBoxNote.md) - [Device pinners](devicePinners.md) - [Docgen](docgen.md) - [Docgen template](docgenTemplate.md) @@ -62,6 +61,7 @@ the SDK are available by topic: - [Metadata cascade policies](metadataCascadePolicies.md) - [Metadata taxonomies](metadataTaxonomies.md) - [Metadata templates](metadataTemplates.md) +- [Notes](notes.md) - [Recent items](recentItems.md) - [Retention policies](retentionPolicies.md) - [Retention policy assignments](retentionPolicyAssignments.md) diff --git a/docs/convertMarkdownToBoxNote.md b/docs/notes.md similarity index 95% rename from docs/convertMarkdownToBoxNote.md rename to docs/notes.md index 6d9f5d74..0f872c10 100644 --- a/docs/convertMarkdownToBoxNote.md +++ b/docs/notes.md @@ -1,4 +1,4 @@ -# ConvertMarkdownToBoxNoteManager +# NotesManager - [Convert content to Box Note](#convert-content-to-box-note) diff --git a/package-lock.json b/package-lock.json index 88964b06..7108e5cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5946,9 +5946,9 @@ "license": "MIT" }, "node_modules/ts-jest": { - "version": "29.4.10", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.10.tgz", - "integrity": "sha512-vMTlTTtvz5aKZgzOoc7DQ5TzAL2fCzl8JnG1+ZpwjQa/g0xLlwE44yQ+1Cao9ZP1xVv9y5g34IFXEiqGOGFBUA==", + "version": "29.4.11", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", + "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", "dev": true, "license": "MIT", "dependencies": { @@ -6245,9 +6245,9 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.107.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.0.tgz", - "integrity": "sha512-PSxeHk/dmLYZlnTU+vL1Gej6Evg5RNtl3flhxBresfznFnzxinHMzHKloHnywM/3ouQv7/AlZCswWDIkNSggUA==", + "version": "5.107.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.1.tgz", + "integrity": "sha512-mvdIWxj/H6QsfgDdH9djne3a5dYcmEmtsXGESkypaGN5jXjF/b+9KDlmTDQ2TKlFUeA2fI9Y65kihD30JOdB+Q==", "dev": true, "license": "MIT", "peer": true, diff --git a/src/client.ts b/src/client.ts index b692b918..069fc696 100644 --- a/src/client.ts +++ b/src/client.ts @@ -86,7 +86,7 @@ import { ShieldListsManager } from './managers/shieldLists'; import { ArchivesManager } from './managers/archives'; import { ExternalUsersManager } from './managers/externalUsers'; import { AutomateWorkflowsManager } from './managers/automateWorkflows'; -import { ConvertMarkdownToBoxNoteManager } from './managers/convertMarkdownToBoxNote'; +import { NotesManager } from './managers/notes'; import { Authentication } from './networking/auth'; import { NetworkSession } from './networking/network'; import { BoxSdkError } from './box/errors'; @@ -193,7 +193,7 @@ export class BoxClient { readonly archives: ArchivesManager; readonly externalUsers: ExternalUsersManager; readonly automateWorkflows: AutomateWorkflowsManager; - readonly convertMarkdownToBoxNote: ConvertMarkdownToBoxNoteManager; + readonly notes: NotesManager; constructor( fields: Omit< BoxClient, @@ -281,7 +281,7 @@ export class BoxClient { | 'archives' | 'externalUsers' | 'automateWorkflows' - | 'convertMarkdownToBoxNote' + | 'notes' | 'networkSession' | 'makeRequest' | 'withAsUserHeader' @@ -643,7 +643,7 @@ export class BoxClient { auth: this.auth, networkSession: this.networkSession, }); - this.convertMarkdownToBoxNote = new ConvertMarkdownToBoxNoteManager({ + this.notes = new NotesManager({ auth: this.auth, networkSession: this.networkSession, }); diff --git a/src/managers/index.ts b/src/managers/index.ts index fb3bdb55..dd10eb83 100644 --- a/src/managers/index.ts +++ b/src/managers/index.ts @@ -82,4 +82,4 @@ export * from './shieldLists'; export * from './archives'; export * from './externalUsers'; export * from './automateWorkflows'; -export * from './convertMarkdownToBoxNote'; +export * from './notes'; diff --git a/src/managers/convertMarkdownToBoxNote.ts b/src/managers/notes.ts similarity index 95% rename from src/managers/convertMarkdownToBoxNote.ts rename to src/managers/notes.ts index 67352832..3a833b3b 100644 --- a/src/managers/convertMarkdownToBoxNote.ts +++ b/src/managers/notes.ts @@ -91,15 +91,12 @@ export interface CreateNoteConvertV2026R0HeadersInput { readonly [key: string]: undefined | string; }; } -export class ConvertMarkdownToBoxNoteManager { +export class NotesManager { readonly auth?: Authentication; readonly networkSession: NetworkSession = new NetworkSession({}); constructor( - fields: Omit< - ConvertMarkdownToBoxNoteManager, - 'networkSession' | 'createNoteConvertV2026R0' - > & - Partial>, + fields: Omit & + Partial>, ) { if (fields.auth !== undefined) { this.auth = fields.auth; @@ -161,7 +158,7 @@ export class ConvertMarkdownToBoxNoteManager { }; } } -export interface ConvertMarkdownToBoxNoteManagerInput { +export interface NotesManagerInput { readonly auth?: Authentication; readonly networkSession?: NetworkSession; } diff --git a/src/schemas/signRequest.ts b/src/schemas/signRequest.ts index e062fd06..8cab7ea6 100644 --- a/src/schemas/signRequest.ts +++ b/src/schemas/signRequest.ts @@ -36,6 +36,7 @@ export type SignRequestStatusField = | 'signed' | 'cancelled' | 'declined' + | 'error' | 'error_converting' | 'error_sending' | 'expired' @@ -151,6 +152,9 @@ export function deserializeSignRequestStatusField( if (val == 'declined') { return val; } + if (val == 'error') { + return val; + } if (val == 'error_converting') { return val; }