From 52758823cc9c6f7609a2ae3c31bc89ef477feb23 Mon Sep 17 00:00:00 2001 From: Kevin Stubbs Date: Thu, 4 Jan 2024 17:51:59 +0100 Subject: [PATCH 1/6] Added: Drupal import command. --- packages/cli/package.json | 6 +- packages/cli/src/cli/commands/import.ts | 172 ++++++++++++++++++ packages/cli/src/cli/commands/login.ts | 21 ++- packages/cli/src/cli/index.ts | 36 ++++ packages/cli/src/lib/addonApiHelper.ts | 81 ++++++++- pnpm-lock.yaml | 121 +++++++----- .../components/smart-components/index.ts | 1 + 7 files changed, 381 insertions(+), 57 deletions(-) create mode 100644 packages/cli/src/cli/commands/import.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index a3e3bd1a..39ae6f32 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,23 +39,27 @@ "dependencies": { "@pantheon-systems/pcc-sdk-core": "latest", "axios": "^1.6.0", + "bluebird": "^3.7.2", "boxen": "^7.1.1", "chalk": "^5.3.0", "dayjs": "^1.11.9", "fs-extra": "^11.1.1", "get-port": "^7.0.0", - "google-auth-library": "^8.9.0", + "google-auth-library": "^9.4.0", + "googleapis": "^129.0.0", "inquirer": "^8.2.6", "nunjucks": "^3.2.4", "octokit": "^2.1.0", "open": "^9.1.0", "ora": "^6.3.1", "package-json": "^8.1.1", + "query-string": "^8.1.0", "server-destroy": "^1.0.1", "yargs": "^17.7.2" }, "devDependencies": { "@babel/preset-env": "7.21.5", + "@types/bluebird": "^3.5.42", "@types/fs-extra": "^11.0.1", "@types/inquirer": "^9.0.3", "@types/jest": "29.5.1", diff --git a/packages/cli/src/cli/commands/import.ts b/packages/cli/src/cli/commands/import.ts new file mode 100644 index 00000000..14be8c2b --- /dev/null +++ b/packages/cli/src/cli/commands/import.ts @@ -0,0 +1,172 @@ +import { randomUUID } from "crypto"; +import { exit } from "process"; +import axios, { AxiosError } from "axios"; +import Promise from "bluebird"; +import chalk from "chalk"; +import type { GaxiosResponse } from "gaxios"; +import { OAuth2Client } from "google-auth-library"; +import { drive_v3, google } from "googleapis"; +import queryString from "query-string"; +import AddOnApiHelper from "../../lib/addonApiHelper"; +import { getLocalAuthDetails } from "../../lib/localStorage"; +import { Logger } from "../../lib/logger"; +import { errorHandler } from "../exceptions"; +import login from "./login"; + +type ImportParams = { + baseUrl: string; + siteId: string; +}; + +async function getDrupalPosts(url: string) { + try { + console.log(`Importing from ${url}`); + const result = (await axios.get(url)).data; + + return { + nextURL: result.links?.next?.href, + posts: result.data, + includedData: result.included, + }; + } catch (e: any) { + console.log(e, e.message); + throw e; + } +} + +export const importFromDrupal = errorHandler( + async ({ baseUrl, siteId }: ImportParams) => { + const logger = new Logger(); + + if (baseUrl) { + try { + new URL(baseUrl); + } catch (_err) { + logger.error( + chalk.red( + `ERROR: Value provided for \`baseUrl\` is not a valid URL. `, + ), + ); + exit(1); + } + } + + await login(["https://www.googleapis.com/auth/drive.file"]); + let authDetails = await getLocalAuthDetails(); + const oauth2Client = new OAuth2Client(); + oauth2Client.setCredentials(authDetails!); + const drive = google.drive({ + version: "v3", + auth: oauth2Client, + }); + + const folderRes = (await drive.files + .create({ + fields: "id,name", + requestBody: { + name: `PCC Import from Drupal on ${new Date().toLocaleDateString()} unique id: ${randomUUID()}`, + mimeType: "application/vnd.google-apps.folder", + }, + }) + .catch(console.error)) as GaxiosResponse; + + // Get results. + let page = 0; + let { url, query } = queryString.parseUrl(baseUrl); + query.include = "field_author,field_topics"; + let allPosts: any[] = []; + let allIncludedData: any[] = []; + let nextURL = queryString.stringifyUrl({ url, query }); + + do { + const drupalData = await getDrupalPosts(nextURL); + nextURL = drupalData.nextURL; + + if (drupalData.posts?.length) { + allPosts.push(...drupalData.posts); + } + + if (drupalData.includedData?.length) { + allIncludedData.push(...drupalData.includedData); + } + } while (nextURL != null && ++page < 1000); + + logger.log(chalk.green(`Retrieved ${allPosts.length} posts after ${page} pages`)); + + // Ensure that these metadata fields exist. + await AddOnApiHelper.addSiteMetadataField( + siteId, + "blog", + "drupalId", + "string", + ); + await AddOnApiHelper.addSiteMetadataField( + siteId, + "blog", + "author", + "string", + ); + + await Promise.map( + allPosts, + async (post) => { + if (post?.attributes?.body == null) { + console.log("Skipping post", Object.keys(post)); + return; + } + + // Create the google doc. + const authorName = allIncludedData.find( + (x) => x.id === post.relationships.field_author.data.id, + )?.attributes?.title; + const res = (await drive.files.create({ + requestBody: { + // Name from the article. + name: post.attributes.title, + mimeType: "application/vnd.google-apps.document", + parents: [folderRes.data.id!], + }, + media: { + mimeType: "text/html", + body: post.attributes.body.processed, + }, + })) as GaxiosResponse; + + // Add it to the PCC site. + console.log("Get document", res.data.id); + await AddOnApiHelper.getDocument(res.data.id!, true); + + try { + await AddOnApiHelper.updateDocument( + res.data.id!, + siteId, + post.attributes.title, + post.relationships.field_topics?.data + ?.map( + (topic: any) => + allIncludedData.find((x: any) => x.id === topic.id) + ?.attributes?.name, + ) + .filter((x: string | undefined) => x != null) || [], + { + author: authorName, + drupalId: post.id, + }, + ); + } catch (e: any) { + console.error(e.response?.data); + throw e; + } + }, + { + concurrency: 20, + }, + ); + + logger.log( + chalk.green( + `Successfully imported ${allPosts.length} documents into ${folderRes.data.name}`, + ), + ); + }, +); diff --git a/packages/cli/src/cli/commands/login.ts b/packages/cli/src/cli/commands/login.ts index 976ccc35..7a9d9fd3 100644 --- a/packages/cli/src/cli/commands/login.ts +++ b/packages/cli/src/cli/commands/login.ts @@ -20,7 +20,7 @@ nunjucks.configure({ autoescape: true }); const OAUTH_SCOPES = ["https://www.googleapis.com/auth/userinfo.email"]; -function login(): Promise { +function login(extraScopes: string[] = []): Promise { return new Promise( // eslint-disable-next-line no-async-promise-executor -- Handling promise rejection in the executor async (resolve, reject) => { @@ -28,9 +28,18 @@ function login(): Promise { try { const authData = await getLocalAuthDetails(); if (authData) { - const jwtPayload = parseJwt(authData.id_token as string); - spinner.succeed(`You are already logged in as ${jwtPayload.email}.`); - return; + let scopes = authData.scope?.split(" "); + + if ( + !extraScopes?.length || + extraScopes.find((x) => scopes?.includes(x)) + ) { + const jwtPayload = parseJwt(authData.id_token as string); + spinner.succeed( + `You are already logged in as ${jwtPayload.email}.`, + ); + return resolve(); + } } const oAuth2Client = new OAuth2Client({ @@ -41,7 +50,7 @@ function login(): Promise { // Generate the url that will be used for the consent dialog. const authorizeUrl = oAuth2Client.generateAuthUrl({ access_type: "offline", - scope: OAUTH_SCOPES, + scope: [...OAUTH_SCOPES, ...extraScopes], }); const server = http.createServer(async (req, res) => { @@ -92,4 +101,4 @@ function login(): Promise { }, ); } -export default errorHandler(login); +export default errorHandler(login); diff --git a/packages/cli/src/cli/index.ts b/packages/cli/src/cli/index.ts index 5be154b0..8194d575 100755 --- a/packages/cli/src/cli/index.ts +++ b/packages/cli/src/cli/index.ts @@ -3,6 +3,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import checkUpdate from "../lib/checkUpdate"; import { generatePreviewLink } from "./commands/documents"; +import { importFromDrupal } from "./commands/import"; import init from "./commands/init"; import login from "./commands/login"; import logout from "./commands/logout"; @@ -353,6 +354,41 @@ yargs(hideBin(process.argv)) ); }, ) + .command( + "import", + "Imports posts from a Drupal JSON API endpoint into PCC", + (yargs) => { + yargs + .strictCommands() + .demandCommand() + .command( + "drupal ", + "Imports all articles from a Drupal JSON API endpoint into a new Google Drive folder and connects them to a target PCC site", + (yargs) => { + yargs + .strictCommands() + .positional("baseUrl", { + describe: + 'URL of drupal json API endpoint such as "https://example.com/jsonapi/node/blog".', + type: "string", + }) + .positional("siteId", { + describe: "Id of site to import articles into.", + type: "string", + }) + .demandOption(["baseUrl", "siteId"]); + }, + async (args) => + await importFromDrupal({ + baseUrl: args.baseUrl as string, + siteId: args.siteId as string, + }), + ); + }, + async () => { + // noop + }, + ) .command( "whoami", "Print information about yourself.", diff --git a/packages/cli/src/lib/addonApiHelper.ts b/packages/cli/src/lib/addonApiHelper.ts index a2044dbe..ae92daa0 100644 --- a/packages/cli/src/lib/addonApiHelper.ts +++ b/packages/cli/src/lib/addonApiHelper.ts @@ -49,14 +49,87 @@ class AddOnApiHelper { return authDetails.id_token as string; } - static async getDocument(documentId: string): Promise
{ + static async getDocument( + documentId: string, + insertIfMissing: boolean = false, + ): Promise
{ const idToken = await this.getIdToken(); - const resp = await axios.get(`${DOCUMENT_ENDPOINT}/${documentId}`, { - headers: { - Authorization: `Bearer ${idToken}`, + const resp = await axios.get( + `${DOCUMENT_ENDPOINT}/${documentId}?insertIfMissing=${insertIfMissing.toString()}`, + { + headers: { + Authorization: `Bearer ${idToken}`, + }, }, + ); + + return resp.data as Article; + } + + static async addSiteMetadataField( + siteId: string, + contentType: string, + fieldTitle: string, + fieldType: string, + ): Promise { + const idToken = await this.getIdToken(); + + try { + await axios.post( + `${SITE_ENDPOINT}/${siteId}/metadata`, + { + contentType, + field: { + title: fieldTitle, + type: fieldType, + }, + }, + { + headers: { + Authorization: `Bearer ${idToken}`, + "Content-Type": "application/json", + }, + }, + ); + } catch (e) { + console.log(`${SITE_ENDPOINT}/${siteId}`); + console.warn(e); + throw e; + } + } + + static async updateDocument( + documentId: string, + siteId: string, + title: string, + tags: string[], + metadataFields: any, + ): Promise
{ + const idToken = await this.getIdToken(); + + console.log("update document", { + documentId, + siteId, + title, + tags, + metadataFields, }); + const resp = await axios.patch( + `${DOCUMENT_ENDPOINT}/${documentId}`, + { + siteId, + tags, + title, + metadataFields, + }, + { + headers: { + Authorization: `Bearer ${idToken}`, + "Content-Type": "application/json", + }, + }, + ); return resp.data as Article; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdf3d472..d0ca06b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -112,6 +112,9 @@ importers: axios: specifier: ^1.6.0 version: 1.6.2 + bluebird: + specifier: ^3.7.2 + version: 3.7.2 boxen: specifier: ^7.1.1 version: 7.1.1 @@ -128,8 +131,11 @@ importers: specifier: ^7.0.0 version: 7.0.0 google-auth-library: - specifier: ^8.9.0 - version: 8.9.0 + specifier: ^9.4.0 + version: 9.4.1 + googleapis: + specifier: ^129.0.0 + version: 129.0.0 inquirer: specifier: ^8.2.6 version: 8.2.6 @@ -148,6 +154,9 @@ importers: package-json: specifier: ^8.1.1 version: 8.1.1 + query-string: + specifier: ^8.1.0 + version: 8.1.0 server-destroy: specifier: ^1.0.1 version: 1.0.1 @@ -158,6 +167,9 @@ importers: '@babel/preset-env': specifier: 7.21.5 version: 7.21.5(@babel/core@7.21.8) + '@types/bluebird': + specifier: ^3.5.42 + version: 3.5.42 '@types/fs-extra': specifier: ^11.0.1 version: 11.0.4 @@ -8646,6 +8658,10 @@ packages: '@babel/types': 7.23.6 dev: true + /@types/bluebird@3.5.42: + resolution: {integrity: sha512-Jhy+MWRlro6UjVi578V/4ZGNfeCOcNCp0YaFNIUGFKlImowqwb1O/22wDVk3FDGMLqxdpOV3qQHD5fPEH4hK6A==} + dev: true + /@types/body-parser@1.19.5: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: @@ -10042,6 +10058,7 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color + dev: true /agent-base@7.1.0: resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} @@ -10050,7 +10067,6 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color - dev: true /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -11387,7 +11403,7 @@ packages: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case-first: 2.0.2 dev: false @@ -11916,7 +11932,7 @@ packages: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case: 2.0.2 dev: false @@ -12951,7 +12967,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 /dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} @@ -14586,10 +14602,6 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - /fast-text-encoding@1.0.6: - resolution: {integrity: sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==} - dev: false - /fastest-levenshtein@1.0.16: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} @@ -15620,12 +15632,12 @@ packages: wide-align: 1.1.5 dev: true - /gaxios@5.1.3: - resolution: {integrity: sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==} - engines: {node: '>=12'} + /gaxios@6.1.1: + resolution: {integrity: sha512-bw8smrX+XlAoo9o1JAksBwX+hi/RG15J+NTSxmNPIclKC3ZVK6C2afwY8OSdRvOK0+ZLecUJYtj2MmjOt3Dm0w==} + engines: {node: '>=14'} dependencies: extend: 3.0.2 - https-proxy-agent: 5.0.1 + https-proxy-agent: 7.0.2 is-stream: 2.0.1 node-fetch: 2.7.0 transitivePeerDependencies: @@ -15633,11 +15645,11 @@ packages: - supports-color dev: false - /gcp-metadata@5.3.0: - resolution: {integrity: sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==} - engines: {node: '>=12'} + /gcp-metadata@6.1.0: + resolution: {integrity: sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==} + engines: {node: '>=14'} dependencies: - gaxios: 5.1.3 + gaxios: 6.1.1 json-bigint: 1.0.0 transitivePeerDependencies: - encoding @@ -15908,30 +15920,45 @@ packages: csstype: 3.1.3 dev: false - /google-auth-library@8.9.0: - resolution: {integrity: sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==} - engines: {node: '>=12'} + /google-auth-library@9.4.1: + resolution: {integrity: sha512-Chs7cuzDuav8W/BXOoRgSXw4u0zxYtuqAHETDR5Q6dG1RwNwz7NUKjsDDHAsBV3KkiiJBtJqjbzy1XU1L41w1g==} + engines: {node: '>=14'} dependencies: - arrify: 2.0.1 base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - fast-text-encoding: 1.0.6 - gaxios: 5.1.3 - gcp-metadata: 5.3.0 - gtoken: 6.1.2 + gaxios: 6.1.1 + gcp-metadata: 6.1.0 + gtoken: 7.0.1 jws: 4.0.0 - lru-cache: 6.0.0 transitivePeerDependencies: - encoding - supports-color dev: false - /google-p12-pem@4.0.1: - resolution: {integrity: sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==} - engines: {node: '>=12.0.0'} - hasBin: true + /googleapis-common@7.0.1: + resolution: {integrity: sha512-mgt5zsd7zj5t5QXvDanjWguMdHAcJmmDrF9RkInCecNsyV7S7YtGqm5v2IWONNID88osb7zmx5FtrAP12JfD0w==} + engines: {node: '>=14.0.0'} dependencies: - node-forge: 1.3.1 + extend: 3.0.2 + gaxios: 6.1.1 + google-auth-library: 9.4.1 + qs: 6.11.2 + url-template: 2.0.8 + uuid: 9.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /googleapis@129.0.0: + resolution: {integrity: sha512-gFatrzby+oh/GxEeMhJOKzgs9eG7yksRcTon9b+kPie4ZnDSgGQ85JgtUaBtLSBkcKpUKukdSP6Km1aCjs4y4Q==} + engines: {node: '>=14.0.0'} + dependencies: + google-auth-library: 9.4.1 + googleapis-common: 7.0.1 + transitivePeerDependencies: + - encoding + - supports-color dev: false /gopd@1.0.1: @@ -16046,12 +16073,11 @@ packages: strip-bom-string: 1.0.0 dev: false - /gtoken@6.1.2: - resolution: {integrity: sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==} - engines: {node: '>=12.0.0'} + /gtoken@7.0.1: + resolution: {integrity: sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==} + engines: {node: '>=14.0.0'} dependencies: - gaxios: 5.1.3 - google-p12-pem: 4.0.1 + gaxios: 6.1.1 jws: 4.0.0 transitivePeerDependencies: - encoding @@ -16364,7 +16390,7 @@ packages: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} dependencies: capital-case: 1.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: false /headers-polyfill@3.2.5: @@ -16556,6 +16582,7 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color + dev: true /https-proxy-agent@7.0.2: resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} @@ -16565,7 +16592,6 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color - dev: true /httpxy@0.1.5: resolution: {integrity: sha512-hqLDO+rfststuyEUTWObQK6zHEEmZ/kaIP2/zclGGZn6X8h/ESTWg+WKecQ/e5k4nPswjzZD+q2VqZIbr15CoQ==} @@ -20027,7 +20053,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.4.1 + tslib: 2.6.2 /node-abi@3.52.0: resolution: {integrity: sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==} @@ -20074,6 +20100,7 @@ packages: /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} + dev: true /node-gyp-build-optional-packages@5.0.3: resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} @@ -20920,7 +20947,7 @@ packages: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 /password-prompt@1.1.3: resolution: {integrity: sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==} @@ -20937,7 +20964,7 @@ packages: resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: false /path-exists@3.0.0: @@ -22148,7 +22175,6 @@ packages: engines: {node: '>=0.6'} dependencies: side-channel: 1.0.4 - dev: true /query-string@6.14.1: resolution: {integrity: sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==} @@ -23349,7 +23375,7 @@ packages: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case-first: 2.0.2 dev: false @@ -23600,7 +23626,7 @@ packages: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: false /socket.io-adapter@2.5.2: @@ -25665,6 +25691,10 @@ packages: requires-port: 1.0.0 dev: true + /url-template@2.0.8: + resolution: {integrity: sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==} + dev: false + /url@0.11.3: resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} dependencies: @@ -25751,7 +25781,6 @@ packages: /uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - dev: true /uvu@0.5.6: resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} diff --git a/starters/nextjs-starter-ts/components/smart-components/index.ts b/starters/nextjs-starter-ts/components/smart-components/index.ts index ba2a4b61..fb2942f9 100644 --- a/starters/nextjs-starter-ts/components/smart-components/index.ts +++ b/starters/nextjs-starter-ts/components/smart-components/index.ts @@ -10,6 +10,7 @@ export const serverSmartComponentMap = { displayName: "Title", required: true, type: "string", + defaultValue: "Some title", }, body: { displayName: "Body", From e5e8e78f8120c15d7f840be4f935dfdec50434aa Mon Sep 17 00:00:00 2001 From: Kevin Stubbs Date: Thu, 4 Jan 2024 17:53:35 +0100 Subject: [PATCH 2/6] Remove debug logs. --- packages/cli/src/lib/addonApiHelper.ts | 34 +++++++++++--------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/packages/cli/src/lib/addonApiHelper.ts b/packages/cli/src/lib/addonApiHelper.ts index ae92daa0..0efdd135 100644 --- a/packages/cli/src/lib/addonApiHelper.ts +++ b/packages/cli/src/lib/addonApiHelper.ts @@ -75,28 +75,22 @@ class AddOnApiHelper { ): Promise { const idToken = await this.getIdToken(); - try { - await axios.post( - `${SITE_ENDPOINT}/${siteId}/metadata`, - { - contentType, - field: { - title: fieldTitle, - type: fieldType, - }, + await axios.post( + `${SITE_ENDPOINT}/${siteId}/metadata`, + { + contentType, + field: { + title: fieldTitle, + type: fieldType, }, - { - headers: { - Authorization: `Bearer ${idToken}`, - "Content-Type": "application/json", - }, + }, + { + headers: { + Authorization: `Bearer ${idToken}`, + "Content-Type": "application/json", }, - ); - } catch (e) { - console.log(`${SITE_ENDPOINT}/${siteId}`); - console.warn(e); - throw e; - } + }, + ); } static async updateDocument( From d11b2c570adffe4165269d03b9272ce6fa098436 Mon Sep 17 00:00:00 2001 From: Kevin Stubbs Date: Thu, 4 Jan 2024 17:58:31 +0100 Subject: [PATCH 3/6] Add documentation about how to import posts from Drupal. --- packages/cli/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/cli/README.md b/packages/cli/README.md index 11a12902..2575b8f6 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -100,3 +100,17 @@ Token: TOKEN-SECRET-GUID-DONT-SHARE-THIS # You can use THE_NEW_SITE_ID as the value of PCC_SITE_ID and TOKEN-SECRET-GUID-DONT-SHARE-THIS for PCC_API_KEY ``` + +## Import existing content from a Drupal site + +You must ensure that the JSON API for your Drupal site is enabled (which it should be by default). https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/api-overview + +Once you've ensured that it's working, you will need to determine the URL which PCC can use to get the initial results page of posts (e.g. https://example.com/jsonapi/node/article). But please note that the exact URL will depend on which resource type(s) you want to import. + +The second and last piece of information you will need before proceeding to import, is the id of the PCC site which the posts should be imported into. Posts are NOT going to be published automatically after importing, but they will be automatically connected to the site id provided. + +With this information, you can now run the import command. + +```bash +$ pcc import drupal https://example.com/jsonapi/node/article siteid12345 +``` From be554b73615584fc4ae2755a7df626f01e64b5b2 Mon Sep 17 00:00:00 2001 From: Kevin Stubbs Date: Mon, 8 Jan 2024 20:10:01 +0100 Subject: [PATCH 4/6] Remove debug message. Add verbose flag. Require param for login --- packages/cli/src/cli/commands/import.ts | 5 +++-- packages/cli/src/cli/commands/login.ts | 2 +- packages/cli/src/cli/index.ts | 9 ++++++++- packages/cli/src/lib/addonApiHelper.ts | 20 +++++++++++-------- .../components/smart-components/index.ts | 1 - 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/packages/cli/src/cli/commands/import.ts b/packages/cli/src/cli/commands/import.ts index 14be8c2b..7feb8df7 100644 --- a/packages/cli/src/cli/commands/import.ts +++ b/packages/cli/src/cli/commands/import.ts @@ -16,6 +16,7 @@ import login from "./login"; type ImportParams = { baseUrl: string; siteId: string; + verbose: boolean; }; async function getDrupalPosts(url: string) { @@ -35,7 +36,7 @@ async function getDrupalPosts(url: string) { } export const importFromDrupal = errorHandler( - async ({ baseUrl, siteId }: ImportParams) => { + async ({ baseUrl, siteId, verbose }: ImportParams) => { const logger = new Logger(); if (baseUrl) { @@ -133,7 +134,6 @@ export const importFromDrupal = errorHandler( })) as GaxiosResponse; // Add it to the PCC site. - console.log("Get document", res.data.id); await AddOnApiHelper.getDocument(res.data.id!, true); try { @@ -152,6 +152,7 @@ export const importFromDrupal = errorHandler( author: authorName, drupalId: post.id, }, + verbose, ); } catch (e: any) { console.error(e.response?.data); diff --git a/packages/cli/src/cli/commands/login.ts b/packages/cli/src/cli/commands/login.ts index 253cd617..289140f2 100644 --- a/packages/cli/src/cli/commands/login.ts +++ b/packages/cli/src/cli/commands/login.ts @@ -20,7 +20,7 @@ nunjucks.configure({ autoescape: true }); const OAUTH_SCOPES = ["https://www.googleapis.com/auth/userinfo.email"]; -function login(extraScopes: string[] = []): Promise { +function login(extraScopes: string[]): Promise { return new Promise( // eslint-disable-next-line no-async-promise-executor -- Handling promise rejection in the executor async (resolve, reject) => { diff --git a/packages/cli/src/cli/index.ts b/packages/cli/src/cli/index.ts index db77b61d..42f80c24 100755 --- a/packages/cli/src/cli/index.ts +++ b/packages/cli/src/cli/index.ts @@ -386,12 +386,19 @@ yargs(hideBin(process.argv)) describe: "Id of site to import articles into.", type: "string", }) + .option("verbose", { + describe: "Print verbose logs.", + type: "boolean", + default: false, + demandOption: false, + }) .demandOption(["baseUrl", "siteId"]); }, async (args) => await importFromDrupal({ baseUrl: args.baseUrl as string, siteId: args.siteId as string, + verbose: args.verbose as boolean, }), ); }, @@ -413,7 +420,7 @@ yargs(hideBin(process.argv)) () => { // noop }, - async () => await login(), + async () => await login([]), ) .command( "logout", diff --git a/packages/cli/src/lib/addonApiHelper.ts b/packages/cli/src/lib/addonApiHelper.ts index 0efdd135..21e2b857 100644 --- a/packages/cli/src/lib/addonApiHelper.ts +++ b/packages/cli/src/lib/addonApiHelper.ts @@ -41,7 +41,7 @@ class AddOnApiHelper { // If auth details not found, try user logging in if (!authDetails) { ora().clear(); - await login(); + await login([]); authDetails = await getLocalAuthDetails(); if (!authDetails) throw new UserNotLoggedIn(); } @@ -99,16 +99,20 @@ class AddOnApiHelper { title: string, tags: string[], metadataFields: any, + verbose?: boolean, ): Promise
{ const idToken = await this.getIdToken(); - console.log("update document", { - documentId, - siteId, - title, - tags, - metadataFields, - }); + if (verbose) { + console.log("update document", { + documentId, + siteId, + title, + tags, + metadataFields, + }); + } + const resp = await axios.patch( `${DOCUMENT_ENDPOINT}/${documentId}`, { diff --git a/starters/nextjs-starter-ts/components/smart-components/index.ts b/starters/nextjs-starter-ts/components/smart-components/index.ts index fb2942f9..ba2a4b61 100644 --- a/starters/nextjs-starter-ts/components/smart-components/index.ts +++ b/starters/nextjs-starter-ts/components/smart-components/index.ts @@ -10,7 +10,6 @@ export const serverSmartComponentMap = { displayName: "Title", required: true, type: "string", - defaultValue: "Some title", }, body: { displayName: "Body", From a2fa72e792a7b5d2c5877d6557782245f4b68162 Mon Sep 17 00:00:00 2001 From: Kevin Stubbs Date: Mon, 8 Jan 2024 21:09:52 +0100 Subject: [PATCH 5/6] Fix lint & prettier issues. --- packages/cli/README.md | 18 +++-- packages/cli/src/cli/commands/import.ts | 100 +++++++++++++++++++----- packages/cli/src/cli/commands/login.ts | 2 +- packages/cli/src/lib/addonApiHelper.ts | 7 +- 4 files changed, 101 insertions(+), 26 deletions(-) diff --git a/packages/cli/README.md b/packages/cli/README.md index 2405c7eb..c00dc0e2 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -66,11 +66,19 @@ $ pcc logout ## Import existing content from a Drupal site -You must ensure that the JSON API for your Drupal site is enabled (which it should be by default). https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/api-overview - -Once you've ensured that it's working, you will need to determine the URL which PCC can use to get the initial results page of posts (e.g. https://example.com/jsonapi/node/article). But please note that the exact URL will depend on which resource type(s) you want to import. - -The second and last piece of information you will need before proceeding to import, is the id of the PCC site which the posts should be imported into. Posts are NOT going to be published automatically after importing, but they will be automatically connected to the site id provided. +You must ensure that the JSON API for your Drupal site is enabled (which it +should be by default). +https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/api-overview + +Once you've ensured that it's working, you will need to determine the URL which +PCC can use to get the initial results page of posts (e.g. +https://example.com/jsonapi/node/article). But please note that the exact URL +will depend on which resource type(s) you want to import. + +The second and last piece of information you will need before proceeding to +import, is the id of the PCC site which the posts should be imported into. Posts +are NOT going to be published automatically after importing, but they will be +automatically connected to the site id provided. With this information, you can now run the import command. diff --git a/packages/cli/src/cli/commands/import.ts b/packages/cli/src/cli/commands/import.ts index 7feb8df7..713f7caf 100644 --- a/packages/cli/src/cli/commands/import.ts +++ b/packages/cli/src/cli/commands/import.ts @@ -19,6 +19,45 @@ type ImportParams = { verbose: boolean; }; +interface DrupalPost { + id: string; + attributes?: { + body?: { + processed: string; + }; + title: string; + }; + relationships: { + field_author: { + data: { + id: string; + }; + }; + field_topics?: { + data: [ + { + id: string; + }, + ]; + }; + }; +} + +interface DrupalTopic { + id: string; + attributes?: { + name: string; + }; +} + +interface DrupalIncludedData { + id: string; + attributes?: { + name: string; + title: string; + }; +} + async function getDrupalPosts(url: string) { try { console.log(`Importing from ${url}`); @@ -29,8 +68,8 @@ async function getDrupalPosts(url: string) { posts: result.data, includedData: result.included, }; - } catch (e: any) { - console.log(e, e.message); + } catch (e) { + console.error(e); throw e; } } @@ -53,9 +92,15 @@ export const importFromDrupal = errorHandler( } await login(["https://www.googleapis.com/auth/drive.file"]); - let authDetails = await getLocalAuthDetails(); + const authDetails = await getLocalAuthDetails(); + + if (!authDetails) { + logger.error(chalk.red(`ERROR: Failed to retrieve login details. `)); + exit(1); + } + const oauth2Client = new OAuth2Client(); - oauth2Client.setCredentials(authDetails!); + oauth2Client.setCredentials(authDetails); const drive = google.drive({ version: "v3", auth: oauth2Client, @@ -71,12 +116,23 @@ export const importFromDrupal = errorHandler( }) .catch(console.error)) as GaxiosResponse; + const folderId = folderRes.data.id; + + if (folderId == null) { + logger.error( + chalk.red( + `Failed to create parent folder which we would have imported posts into`, + ), + ); + exit(1); + } + // Get results. let page = 0; - let { url, query } = queryString.parseUrl(baseUrl); + const { url, query } = queryString.parseUrl(baseUrl); query.include = "field_author,field_topics"; - let allPosts: any[] = []; - let allIncludedData: any[] = []; + const allPosts: DrupalPost[] = []; + const allIncludedData: DrupalIncludedData[] = []; let nextURL = queryString.stringifyUrl({ url, query }); do { @@ -92,7 +148,9 @@ export const importFromDrupal = errorHandler( } } while (nextURL != null && ++page < 1000); - logger.log(chalk.green(`Retrieved ${allPosts.length} posts after ${page} pages`)); + logger.log( + chalk.green(`Retrieved ${allPosts.length} posts after ${page} pages`), + ); // Ensure that these metadata fields exist. await AddOnApiHelper.addSiteMetadataField( @@ -117,45 +175,51 @@ export const importFromDrupal = errorHandler( } // Create the google doc. - const authorName = allIncludedData.find( + const authorName: string | undefined = allIncludedData.find( (x) => x.id === post.relationships.field_author.data.id, )?.attributes?.title; + const res = (await drive.files.create({ requestBody: { // Name from the article. name: post.attributes.title, mimeType: "application/vnd.google-apps.document", - parents: [folderRes.data.id!], + parents: [folderId], }, media: { mimeType: "text/html", body: post.attributes.body.processed, }, })) as GaxiosResponse; + const fileId = res.data.id; + + if (!fileId) { + throw new Error(`Failed to create file for ${post.attributes.title}`); + } // Add it to the PCC site. - await AddOnApiHelper.getDocument(res.data.id!, true); + await AddOnApiHelper.getDocument(fileId, true); try { await AddOnApiHelper.updateDocument( - res.data.id!, + fileId, siteId, post.attributes.title, post.relationships.field_topics?.data ?.map( - (topic: any) => - allIncludedData.find((x: any) => x.id === topic.id) - ?.attributes?.name, + (topic: DrupalTopic) => + allIncludedData.find((x) => x.id === topic.id)?.attributes + ?.name, ) - .filter((x: string | undefined) => x != null) || [], + .filter((x: string | undefined): x is string => x != null) || [], { author: authorName, drupalId: post.id, }, verbose, ); - } catch (e: any) { - console.error(e.response?.data); + } catch (e) { + console.error(e instanceof AxiosError ? e.response?.data : e); throw e; } }, diff --git a/packages/cli/src/cli/commands/login.ts b/packages/cli/src/cli/commands/login.ts index 289140f2..1f45e244 100644 --- a/packages/cli/src/cli/commands/login.ts +++ b/packages/cli/src/cli/commands/login.ts @@ -28,7 +28,7 @@ function login(extraScopes: string[]): Promise { try { const authData = await getLocalAuthDetails(); if (authData) { - let scopes = authData.scope?.split(" "); + const scopes = authData.scope?.split(" "); if ( !extraScopes?.length || diff --git a/packages/cli/src/lib/addonApiHelper.ts b/packages/cli/src/lib/addonApiHelper.ts index 21e2b857..c47c315c 100644 --- a/packages/cli/src/lib/addonApiHelper.ts +++ b/packages/cli/src/lib/addonApiHelper.ts @@ -51,7 +51,7 @@ class AddOnApiHelper { static async getDocument( documentId: string, - insertIfMissing: boolean = false, + insertIfMissing = false, ): Promise
{ const idToken = await this.getIdToken(); @@ -98,7 +98,10 @@ class AddOnApiHelper { siteId: string, title: string, tags: string[], - metadataFields: any, + metadataFields: { + [key: string]: string | number | boolean | undefined | null; + }, + verbose?: boolean, ): Promise
{ const idToken = await this.getIdToken(); From f2dba229e2a43a7f8f989f338526f3b4f7bf6794 Mon Sep 17 00:00:00 2001 From: Kevin Stubbs Date: Mon, 8 Jan 2024 21:24:38 +0100 Subject: [PATCH 6/6] Resolve vue-sdk lint issue. --- packages/vue-sdk/package.json | 6 +- pnpm-lock.yaml | 205 +++++++++++++++++++++++++--------- 2 files changed, 156 insertions(+), 55 deletions(-) diff --git a/packages/vue-sdk/package.json b/packages/vue-sdk/package.json index fe64ab6c..66e6dc40 100644 --- a/packages/vue-sdk/package.json +++ b/packages/vue-sdk/package.json @@ -62,9 +62,9 @@ "typescript": "^5.1.3", "unplugin-vue": "^4.3.5", "vite": "^4.4.10", - "vue": "npm:vue@^3.3.4", - "vue-2": "npm:vue@^2.7.14", - "vue-3": "npm:vue@^3.3.4" + "vue": "npm:vue@3.0.0 - 3.3.4", + "vue-2": "npm:vue@^2.7.16", + "vue-3": "npm:vue@3.0.0 - 3.3.4" }, "peerDependencies": { "@vue/composition-api": ">=1.0.0-rc.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1a0bdbaa..afd5acc6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -462,13 +462,13 @@ importers: version: link:../core '@vue/apollo-composable': specifier: ^4.0.0-beta.7 - version: 4.0.0-beta.12(@apollo/client@3.8.8)(@vue/composition-api@1.7.2)(graphql@16.8.1)(typescript@5.3.3)(vue@3.4.5) + version: 4.0.0-beta.12(@apollo/client@3.8.8)(@vue/composition-api@1.7.2)(graphql@16.8.1)(typescript@5.3.3)(vue@3.3.4) '@vue/composition-api': specifier: '>=1.0.0-rc.1' - version: 1.7.2(vue@3.4.5) + version: 1.7.2(vue@3.3.4) floating-vue: specifier: 2.0.0-beta.24 - version: 2.0.0-beta.24(vue@3.4.5) + version: 2.0.0-beta.24(vue@3.3.4) graphql: specifier: ^16.8.1 version: 16.8.1 @@ -501,7 +501,7 @@ importers: version: 5.0.0 vue-demi: specifier: latest - version: 0.14.6(@vue/composition-api@1.7.2)(vue@3.4.5) + version: 0.14.6(@vue/composition-api@1.7.2)(vue@3.3.4) devDependencies: '@types/markdown-it': specifier: ^13.0.2 @@ -532,19 +532,19 @@ importers: version: 5.3.3 unplugin-vue: specifier: ^4.3.5 - version: 4.5.2(vite@4.5.1)(vue@3.4.5) + version: 4.5.2(vite@4.5.1)(vue@3.3.4) vite: specifier: ^4.4.10 version: 4.5.1(@types/node@20.10.7)(sass@1.69.7) vue: - specifier: npm:vue@^3.3.4 - version: 3.4.5(typescript@5.3.3) + specifier: npm:vue@3.0.0 - 3.3.4 + version: 3.3.4 vue-2: - specifier: npm:vue@^2.7.14 + specifier: npm:vue@^2.7.16 version: /vue@2.7.16 vue-3: - specifier: npm:vue@^3.3.4 - version: /vue@3.4.5(typescript@5.3.3) + specifier: npm:vue@3.0.0 - 3.3.4 + version: /vue@3.3.4 starters/gatsby-starter: dependencies: @@ -822,7 +822,7 @@ importers: version: 3.4.1 vue: specifier: ^3.3.4 - version: 3.4.5(typescript@5.3.3) + version: 3.4.5 vue-router: specifier: ^4.2.5 version: 4.2.5(vue@3.4.5) @@ -853,7 +853,7 @@ importers: version: 3.4.1 vue: specifier: ^3.3.4 - version: 3.4.5(typescript@5.3.3) + version: 3.4.5 vue-router: specifier: ^4.2.5 version: 4.2.5(vue@3.4.5) @@ -5656,7 +5656,7 @@ packages: resolution: {integrity: sha512-5gc02Pu1HycOVUWJ8aYsWeeXcSTPe8iX8+KIrhyEtEoOSkY0eMBuo0ssljB8wALuEmepv31DlYe5gpiRwkjESA==} dev: true - /@nuxt/vite-builder@3.7.4(eslint@8.46.0)(vue@3.4.5): + /@nuxt/vite-builder@3.7.4(eslint@8.46.0)(vue@3.3.4): resolution: {integrity: sha512-EWZlUzYvkSfIZPA0pQoi7P++68Mlvf5s/G3GBPksS5JB/9l3yZTX+ZqGvLeORSBmoEpJ6E2oMn2WvCHV0W5y6Q==} engines: {node: ^14.18.0 || >=16.10.0} peerDependencies: @@ -5664,8 +5664,8 @@ packages: dependencies: '@nuxt/kit': 3.7.4 '@rollup/plugin-replace': 5.0.5(rollup@4.9.4) - '@vitejs/plugin-vue': 4.6.2(vite@4.5.1)(vue@3.4.5) - '@vitejs/plugin-vue-jsx': 3.1.0(vite@4.5.1)(vue@3.4.5) + '@vitejs/plugin-vue': 4.6.2(vite@4.5.1)(vue@3.3.4) + '@vitejs/plugin-vue-jsx': 3.1.0(vite@4.5.1)(vue@3.3.4) autoprefixer: 10.4.16(postcss@8.4.33) clear: 0.1.0 consola: 3.2.3 @@ -5696,7 +5696,7 @@ packages: vite: 4.5.1(@types/node@20.10.7)(sass@1.69.7) vite-node: 0.33.0 vite-plugin-checker: 0.6.2(eslint@8.46.0)(vite@4.5.1) - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 vue-bundle-renderer: 2.0.0 transitivePeerDependencies: - '@types/node' @@ -9546,7 +9546,7 @@ packages: '@unhead/shared': 1.8.9 dev: true - /@unhead/vue@1.8.9(vue@3.4.5): + /@unhead/vue@1.8.9(vue@3.3.4): resolution: {integrity: sha512-sL1d2IRBZd5rjzhgTYni2DiociSpt+Cfz3iVWKb0EZwQHgg0GzV8Hkoj5TjZYZow6EjDSPRfVPXDwOwxkVOgug==} peerDependencies: vue: '>=2.7 || >=3' @@ -9555,7 +9555,7 @@ packages: '@unhead/shared': 1.8.9 hookable: 5.5.3 unhead: 1.8.9 - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 dev: true /@vercel/nft@0.24.4: @@ -9603,7 +9603,7 @@ packages: - supports-color dev: true - /@vitejs/plugin-vue-jsx@3.1.0(vite@4.5.1)(vue@3.4.5): + /@vitejs/plugin-vue-jsx@3.1.0(vite@4.5.1)(vue@3.3.4): resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -9614,12 +9614,12 @@ packages: '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.7) vite: 4.5.1(@types/node@20.10.7)(sass@1.69.7) - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 transitivePeerDependencies: - supports-color dev: true - /@vitejs/plugin-vue@4.6.2(vite@4.5.1)(vue@3.4.5): + /@vitejs/plugin-vue@4.6.2(vite@4.5.1)(vue@3.3.4): resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -9627,7 +9627,7 @@ packages: vue: ^3.2.25 dependencies: vite: 4.5.1(@types/node@20.10.7)(sass@1.69.7) - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 dev: true /@vitest/expect@0.34.7: @@ -9652,7 +9652,7 @@ packages: pretty-format: 29.7.0 dev: true - /@vue-macros/common@1.10.0(vue@3.4.5): + /@vue-macros/common@1.10.0(vue@3.3.4): resolution: {integrity: sha512-4DZsPeQA/nBQDw2RkYAmH7KrFjJVrMdAhJhO1JCl1bbbFXCGeoGjXfkg9wHPppj47s2HpAB3GrqNwqVGbi12NQ==} engines: {node: '>=16.14.0'} peerDependencies: @@ -9667,12 +9667,12 @@ packages: ast-kit: 0.11.3 local-pkg: 0.5.0 magic-string-ast: 0.3.0 - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 transitivePeerDependencies: - rollup dev: true - /@vue/apollo-composable@4.0.0-beta.12(@apollo/client@3.8.8)(@vue/composition-api@1.7.2)(graphql@16.8.1)(typescript@5.3.3)(vue@3.4.5): + /@vue/apollo-composable@4.0.0-beta.12(@apollo/client@3.8.8)(@vue/composition-api@1.7.2)(graphql@16.8.1)(typescript@5.3.3)(vue@3.3.4): resolution: {integrity: sha512-qfi6B6obkzvCUVGB9l28s96xCzPfffB0c7esR8y3UbKc1KwzdOIESMHmoYv0xM2isYP0pu+dz6Rt9KUn7zNf4Q==} peerDependencies: '@apollo/client': ^3.4.13 @@ -9684,12 +9684,12 @@ packages: optional: true dependencies: '@apollo/client': 3.8.8(graphql@16.8.1)(react-dom@18.2.0)(react@18.2.0) - '@vue/composition-api': 1.7.2(vue@3.4.5) + '@vue/composition-api': 1.7.2(vue@3.3.4) graphql: 16.8.1 throttle-debounce: 5.0.0 ts-essentials: 9.4.1(typescript@5.3.3) - vue: 3.4.5(typescript@5.3.3) - vue-demi: 0.14.6(@vue/composition-api@1.7.2)(vue@3.4.5) + vue: 3.3.4 + vue-demi: 0.14.6(@vue/composition-api@1.7.2)(vue@3.3.4) transitivePeerDependencies: - typescript dev: false @@ -9717,6 +9717,14 @@ packages: - supports-color dev: true + /@vue/compiler-core@3.3.4: + resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + /@vue/compiler-core@3.4.5: resolution: {integrity: sha512-Daka7P1z2AgKjzuueWXhwzIsKu0NkLB6vGbNVEV2iJ8GJTrzraZo/Sk4GWCMRtd/qVi3zwnk+Owbd/xSZbwHtQ==} dependencies: @@ -9725,12 +9733,20 @@ packages: entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.0.2 + dev: true + + /@vue/compiler-dom@3.3.4: + resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} + dependencies: + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 /@vue/compiler-dom@3.4.5: resolution: {integrity: sha512-J8YlxknJVd90SXFJ4HwGANSAXsx5I0lK30sO/zvYV7s5gXf7gZR7r/1BmZ2ju7RGH1lnc6bpBc6nL61yW+PsAQ==} dependencies: '@vue/compiler-core': 3.4.5 '@vue/shared': 3.4.5 + dev: true /@vue/compiler-sfc@2.7.16: resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==} @@ -9742,6 +9758,20 @@ packages: prettier: 2.8.8 dev: true + /@vue/compiler-sfc@3.3.4: + resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/compiler-core': 3.3.4 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-ssr': 3.3.4 + '@vue/reactivity-transform': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.5 + postcss: 8.4.33 + source-map-js: 1.0.2 + /@vue/compiler-sfc@3.4.5: resolution: {integrity: sha512-jauvkDuSSUbP0ebhfNqljhShA90YEfX/0wZ+w40oZF43IjGyWYjqYaJbvMJwGOd+9+vODW6eSvnk28f0SGV7OQ==} dependencies: @@ -9754,35 +9784,72 @@ packages: magic-string: 0.30.5 postcss: 8.4.33 source-map-js: 1.0.2 + dev: true + + /@vue/compiler-ssr@3.3.4: + resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/shared': 3.3.4 /@vue/compiler-ssr@3.4.5: resolution: {integrity: sha512-DDdEcDzj2lWTMfUMMtEpLDhURai9LhM0zSZ219jCt7b2Vyl0/jy3keFgCPMitG0V1S1YG4Cmws3lWHWdxHQOpg==} dependencies: '@vue/compiler-dom': 3.4.5 '@vue/shared': 3.4.5 + dev: true - /@vue/composition-api@1.7.2(vue@3.4.5): + /@vue/composition-api@1.7.2(vue@3.3.4): resolution: {integrity: sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw==} peerDependencies: vue: '>= 2.5 < 2.7' dependencies: - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 dev: false /@vue/devtools-api@6.5.1: resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} dev: true + /@vue/reactivity-transform@3.3.4: + resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.5 + + /@vue/reactivity@3.3.4: + resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} + dependencies: + '@vue/shared': 3.3.4 + /@vue/reactivity@3.4.5: resolution: {integrity: sha512-BcWkKvjdvqJwb7BhhFkXPLDCecX4d4a6GATvCduJQDLv21PkPowAE5GKuIE5p6RC07/Lp9FMkkq4AYCTVF5KlQ==} dependencies: '@vue/shared': 3.4.5 + dev: true + + /@vue/runtime-core@3.3.4: + resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} + dependencies: + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 /@vue/runtime-core@3.4.5: resolution: {integrity: sha512-wh9ELIOQKeWT9SaUPdLrsxRkZv14jp+SJm9aiQGWio+/MWNM3Lib0wE6CoKEqQ9+SCYyGjDBhTOTtO47kCgbkg==} dependencies: '@vue/reactivity': 3.4.5 '@vue/shared': 3.4.5 + dev: true + + /@vue/runtime-dom@3.3.4: + resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} + dependencies: + '@vue/runtime-core': 3.3.4 + '@vue/shared': 3.3.4 + csstype: 3.1.3 /@vue/runtime-dom@3.4.5: resolution: {integrity: sha512-n5ewvOjyG3IEpqGBahdPXODFSpVlSz3H4LF76Sx0XAqpIOqyJ5bIb2PrdYuH2ogBMAQPh+o5tnoH4nJpBr8U0Q==} @@ -9790,6 +9857,16 @@ packages: '@vue/runtime-core': 3.4.5 '@vue/shared': 3.4.5 csstype: 3.1.3 + dev: true + + /@vue/server-renderer@3.3.4(vue@3.3.4): + resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} + peerDependencies: + vue: 3.3.4 + dependencies: + '@vue/compiler-ssr': 3.3.4 + '@vue/shared': 3.3.4 + vue: 3.3.4 /@vue/server-renderer@3.4.5(vue@3.4.5): resolution: {integrity: sha512-jOFc/VE87yvifQpNju12VcqimH8pBLxdcT+t3xMeiED1K6DfH9SORyhFEoZlW5TG2Vwfn3Ul5KE+1aC99xnSBg==} @@ -9798,10 +9875,15 @@ packages: dependencies: '@vue/compiler-ssr': 3.4.5 '@vue/shared': 3.4.5 - vue: 3.4.5(typescript@5.3.3) + vue: 3.4.5 + dev: true + + /@vue/shared@3.3.4: + resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} /@vue/shared@3.4.5: resolution: {integrity: sha512-6XptuzlMvN4l4cDnDw36pdGEV+9njYkQ1ZE0Q6iZLwrKefKaOJyiFmcP3/KBDHbt72cJZGtllAc1GaHe6XGAyg==} + dev: true /@webassemblyjs/ast@1.11.6: resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==} @@ -13203,6 +13285,7 @@ packages: /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + dev: true /env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} @@ -14883,7 +14966,7 @@ packages: /flatted@3.2.9: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} - /floating-vue@2.0.0-beta.24(vue@3.4.5): + /floating-vue@2.0.0-beta.24(vue@3.3.4): resolution: {integrity: sha512-URSzP6YXaF4u1oZ9XGL8Sn8puuM7ivp5jkOUrpy5Q1mfo9BfGppJOn+ierTmsSUfJEeHBae8KT7r5DeI3vQIEw==} peerDependencies: '@nuxt/kit': ^3.2.0 @@ -14893,8 +14976,8 @@ packages: optional: true dependencies: '@floating-ui/dom': 1.1.1 - vue: 3.4.5(typescript@5.3.3) - vue-resize: 2.0.0-alpha.1(vue@3.4.5) + vue: 3.3.4 + vue-resize: 2.0.0-alpha.1(vue@3.3.4) dev: false /flow-parser@0.225.1: @@ -20488,10 +20571,10 @@ packages: '@nuxt/schema': 3.7.4 '@nuxt/telemetry': 2.5.3 '@nuxt/ui-templates': 1.3.1 - '@nuxt/vite-builder': 3.7.4(eslint@8.46.0)(vue@3.4.5) + '@nuxt/vite-builder': 3.7.4(eslint@8.46.0)(vue@3.3.4) '@unhead/dom': 1.8.9 '@unhead/ssr': 1.8.9 - '@unhead/vue': 1.8.9(vue@3.4.5) + '@unhead/vue': 1.8.9(vue@3.3.4) '@vue/shared': 3.4.5 acorn: 8.10.0 c12: 1.6.1 @@ -20531,12 +20614,12 @@ packages: unenv: 1.9.0 unimport: 3.7.1(rollup@4.9.4) unplugin: 1.6.0 - unplugin-vue-router: 0.7.0(vue-router@4.2.5)(vue@3.4.5) + unplugin-vue-router: 0.7.0(vue-router@4.2.5)(vue@3.3.4) untyped: 1.4.0 - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 vue-bundle-renderer: 2.0.0 vue-devtools-stub: 0.1.0 - vue-router: 4.2.5(vue@3.4.5) + vue-router: 4.2.5(vue@3.3.4) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -25592,7 +25675,7 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - /unplugin-vue-router@0.7.0(vue-router@4.2.5)(vue@3.4.5): + /unplugin-vue-router@0.7.0(vue-router@4.2.5)(vue@3.3.4): resolution: {integrity: sha512-ddRreGq0t5vlSB7OMy4e4cfU1w2AwBQCwmvW3oP/0IHQiokzbx4hd3TpwBu3eIAFVuhX2cwNQwp1U32UybTVCw==} peerDependencies: vue-router: ^4.1.0 @@ -25602,7 +25685,7 @@ packages: dependencies: '@babel/types': 7.23.6 '@rollup/pluginutils': 5.1.0(rollup@4.9.4) - '@vue-macros/common': 1.10.0(vue@3.4.5) + '@vue-macros/common': 1.10.0(vue@3.3.4) ast-walker-scope: 0.5.0 chokidar: 3.5.3 fast-glob: 3.3.2 @@ -25612,14 +25695,14 @@ packages: pathe: 1.1.1 scule: 1.1.1 unplugin: 1.6.0 - vue-router: 4.2.5(vue@3.4.5) + vue-router: 4.2.5(vue@3.3.4) yaml: 2.3.4 transitivePeerDependencies: - rollup - vue dev: true - /unplugin-vue@4.5.2(vite@4.5.1)(vue@3.4.5): + /unplugin-vue@4.5.2(vite@4.5.1)(vue@3.3.4): resolution: {integrity: sha512-cFbTsWuhA2c3pQdJLePBbSS0+l7a5TEd8A3kxMLPb6smP/OU1U+dzB7f3sjyKTuWnSo8wdDfS+k+Xny1Cc8ytg==} engines: {node: '>=16.14.0'} peerDependencies: @@ -25632,7 +25715,7 @@ packages: debug: 4.3.4 unplugin: 1.5.1 vite: 4.5.1(@types/node@20.10.7)(sass@1.69.7) - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 transitivePeerDependencies: - supports-color dev: true @@ -26267,7 +26350,7 @@ packages: ufo: 1.3.2 dev: true - /vue-demi@0.14.6(@vue/composition-api@1.7.2)(vue@3.4.5): + /vue-demi@0.14.6(@vue/composition-api@1.7.2)(vue@3.3.4): resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} engines: {node: '>=12'} hasBin: true @@ -26279,29 +26362,38 @@ packages: '@vue/composition-api': optional: true dependencies: - '@vue/composition-api': 1.7.2(vue@3.4.5) - vue: 3.4.5(typescript@5.3.3) + '@vue/composition-api': 1.7.2(vue@3.3.4) + vue: 3.3.4 dev: false /vue-devtools-stub@0.1.0: resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} dev: true - /vue-resize@2.0.0-alpha.1(vue@3.4.5): + /vue-resize@2.0.0-alpha.1(vue@3.3.4): resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} peerDependencies: vue: ^3.0.0 dependencies: - vue: 3.4.5(typescript@5.3.3) + vue: 3.3.4 dev: false + /vue-router@4.2.5(vue@3.3.4): + resolution: {integrity: sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.5.1 + vue: 3.3.4 + dev: true + /vue-router@4.2.5(vue@3.4.5): resolution: {integrity: sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==} peerDependencies: vue: ^3.2.0 dependencies: '@vue/devtools-api': 6.5.1 - vue: 3.4.5(typescript@5.3.3) + vue: 3.4.5 dev: true /vue@2.7.16: @@ -26312,7 +26404,16 @@ packages: csstype: 3.1.3 dev: true - /vue@3.4.5(typescript@5.3.3): + /vue@3.3.4: + resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 + '@vue/runtime-dom': 3.3.4 + '@vue/server-renderer': 3.3.4(vue@3.3.4) + '@vue/shared': 3.3.4 + + /vue@3.4.5: resolution: {integrity: sha512-VH6nHFhLPjgu2oh5vEBXoNZxsGHuZNr3qf4PHClwJWw6IDqw6B3x+4J+ABdoZ0aJuT8Zi0zf3GpGlLQCrGWHrw==} peerDependencies: typescript: '*' @@ -26325,7 +26426,7 @@ packages: '@vue/runtime-dom': 3.4.5 '@vue/server-renderer': 3.4.5(vue@3.4.5) '@vue/shared': 3.4.5 - typescript: 5.3.3 + dev: true /w3c-xmlserializer@4.0.0: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}