Compare commits
13 Commits
fix_xovmdk
...
xen-api-un
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f72b9ca4ca | ||
|
|
0d69e2396f | ||
|
|
c20b43e230 | ||
|
|
5aa6298dd9 | ||
|
|
6ab93c78fe | ||
|
|
8eda65ab88 | ||
|
|
589228eb9e | ||
|
|
be86c0dd32 | ||
|
|
11f67b1039 | ||
|
|
cd767256d1 | ||
|
|
64448426cd | ||
|
|
54d1785e08 | ||
|
|
1ed98d3607 |
@@ -31,7 +31,7 @@ export class PoolMetadataBackup {
|
||||
const poolDir = `${DIR_XO_POOL_METADATA_BACKUPS}/${schedule.id}/${pool.$id}`
|
||||
const dir = `${poolDir}/${formatFilenameDate(timestamp)}`
|
||||
|
||||
const stream = await this._exportPoolMetadata()
|
||||
const stream = (await this._exportPoolMetadata()).body
|
||||
const fileName = `${dir}/data`
|
||||
|
||||
const metadata = JSON.stringify(
|
||||
|
||||
@@ -108,10 +108,12 @@ class Vdi {
|
||||
} else {
|
||||
// raw export without nbd or vhd exports needs a resource stream
|
||||
const vdiName = await this.getField('VDI', ref, 'name_label')
|
||||
stream = await this.getResource(cancelToken, '/export_raw_vdi/', {
|
||||
stream = (
|
||||
await this.getResource(cancelToken, '/export_raw_vdi/', {
|
||||
query,
|
||||
task: await this.task_create(`Exporting content of VDI ${vdiName}`),
|
||||
task: await this.task_create(`Exporting content of VDI ${vdiName)}`),
|
||||
})
|
||||
).body
|
||||
if (nbdClient !== undefined && format === VDI_FORMAT_VHD) {
|
||||
const taskRef = await this.task_create(`Exporting content of VDI ${vdiName} using NBD`)
|
||||
stream = await createNbdVhdStream(nbdClient, stream)
|
||||
|
||||
@@ -502,13 +502,15 @@ class Vm {
|
||||
exportedVmRef = vmRef
|
||||
}
|
||||
try {
|
||||
const stream = await this.getResource(cancelToken, '/export/', {
|
||||
const stream = (
|
||||
await this.getResource(cancelToken, '/export/', {
|
||||
query: {
|
||||
ref: exportedVmRef,
|
||||
use_compression: compress === 'zstd' ? 'zstd' : compress === true || compress === 'gzip' ? 'true' : 'false',
|
||||
},
|
||||
task: taskRef,
|
||||
})
|
||||
).body
|
||||
|
||||
if (useSnapshot) {
|
||||
stream.once('end', destroySnapshot).once('error', destroySnapshot)
|
||||
|
||||
@@ -44,14 +44,14 @@ defer(async ($defer, rawArgs) => {
|
||||
const vdi = await resolveRecord(xapi, 'VDI', args[1])
|
||||
|
||||
// https://xapi-project.github.io/xen-api/snapshots.html#downloading-a-disk-or-snapshot
|
||||
const exportStream = await xapi.getResource(token, '/export_raw_vdi/', {
|
||||
const response = await xapi.getResource(token, '/export_raw_vdi/', {
|
||||
query: {
|
||||
format: raw ? 'raw' : 'vhd',
|
||||
vdi: vdi.$ref,
|
||||
},
|
||||
})
|
||||
|
||||
console.warn('Export task:', exportStream.headers['task-id'])
|
||||
console.warn('Export task:', response.headers['task-id'])
|
||||
|
||||
const top = createTop()
|
||||
const progressStream = createProgress()
|
||||
@@ -63,5 +63,5 @@ defer(async ($defer, rawArgs) => {
|
||||
}, 1e3)
|
||||
)
|
||||
|
||||
await pipeline(exportStream, progressStream, throttle(bps), createOutputStream(args[2]))
|
||||
await pipeline(response.body, progressStream, throttle(bps), createOutputStream(args[2]))
|
||||
})(process.argv.slice(2)).catch(console.error.bind(console, 'error'))
|
||||
|
||||
@@ -37,17 +37,17 @@ defer(async ($defer, rawArgs) => {
|
||||
process.on('SIGINT', cancel)
|
||||
|
||||
// https://xapi-project.github.io/xen-api/importexport.html
|
||||
const exportStream = await xapi.getResource(token, '/export/', {
|
||||
const response = await xapi.getResource(token, '/export/', {
|
||||
query: {
|
||||
ref: (await resolveRecord(xapi, 'VM', args[1])).$ref,
|
||||
use_compression: zstd ? 'zstd' : gzip ? 'true' : 'false',
|
||||
},
|
||||
})
|
||||
|
||||
console.warn('Export task:', exportStream.headers['task-id'])
|
||||
console.warn('Export task:', response.headers['task-id'])
|
||||
|
||||
await pipeline(
|
||||
exportStream,
|
||||
response.body,
|
||||
createProgress({ time: 1e3 }, p => console.warn(formatProgress(p))),
|
||||
createOutputStream(args[2])
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import ms from 'ms'
|
||||
import httpRequest from 'http-request-plus'
|
||||
import map from 'lodash/map.js'
|
||||
import noop from 'lodash/noop.js'
|
||||
import { Client } from 'undici'
|
||||
import { coalesceCalls } from '@vates/coalesce-calls'
|
||||
import { Collection } from 'xo-collection'
|
||||
import { EventEmitter } from 'events'
|
||||
@@ -394,37 +395,54 @@ export class Xapi extends EventEmitter {
|
||||
}
|
||||
|
||||
let url = new URL('http://localhost')
|
||||
url.protocol = this._url.protocol
|
||||
url.pathname = pathname
|
||||
url.search = new URLSearchParams(query)
|
||||
await this._setHostAddressInUrl(url, host)
|
||||
|
||||
const response = await this._addSyncStackTrace(
|
||||
pRetry(
|
||||
async () =>
|
||||
httpRequest(url, {
|
||||
async () => {
|
||||
const client = new Client(url, {
|
||||
connect: {
|
||||
rejectUnauthorized: !this._allowUnauthorized,
|
||||
|
||||
// this is an inactivity timeout (unclear in Node doc)
|
||||
timeout: this._httpInactivityTimeout,
|
||||
|
||||
maxRedirects: 0,
|
||||
|
||||
// Support XS <= 6.5 with Node => 12
|
||||
minVersion: 'TLSv1',
|
||||
},
|
||||
})
|
||||
|
||||
return client
|
||||
.request({
|
||||
method: 'GET',
|
||||
path: pathname,
|
||||
query,
|
||||
maxRedirections: 0,
|
||||
headersTimeout: this._httpInactivityTimeout,
|
||||
bodyTimeout: this._httpInactivityTimeout,
|
||||
agent: this.httpAgent,
|
||||
|
||||
signal: $cancelToken,
|
||||
}),
|
||||
})
|
||||
.then(response => {
|
||||
const { statusCode } = response
|
||||
if (((statusCode / 100) | 0) === 2) {
|
||||
return response
|
||||
}
|
||||
const error = new Error(`${response.statusCode} ${response.statusMessage}`)
|
||||
Object.defineProperty(error, 'response', { value: response })
|
||||
throw error
|
||||
})
|
||||
},
|
||||
{
|
||||
when: error => error.response !== undefined && error.response.statusCode === 302,
|
||||
onRetry: async error => {
|
||||
const response = error.response
|
||||
if (response === undefined) {
|
||||
if (response === undefined || response.body === undefined) {
|
||||
throw error
|
||||
}
|
||||
response.destroy()
|
||||
response.body.on('error', noop)
|
||||
response.body.destroy()
|
||||
url = await this._replaceHostAddressInUrl(new URL(response.headers.location, url))
|
||||
query = Object.fromEntries(url.searchParams.entries())
|
||||
pathname = url.pathname
|
||||
url.pathname = url.search = ''
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -945,14 +963,18 @@ export class Xapi extends EventEmitter {
|
||||
const { hostname } = url
|
||||
url.hostnameRaw = hostname[0] === '[' ? hostname.slice(1, -1) : hostname
|
||||
|
||||
this._humanId = `${this._auth.user ?? 'unknown'}@${url.hostname}`
|
||||
this._transport = this._createTransport({
|
||||
secureOptions: {
|
||||
const client = new Client(url, {
|
||||
connect: {
|
||||
minVersion: 'TLSv1',
|
||||
rejectUnauthorized: !this._allowUnauthorized,
|
||||
},
|
||||
url,
|
||||
})
|
||||
|
||||
this._humanId = `${this._auth.user ?? 'unknown'}@${url.hostname}`
|
||||
this._transport = this._createTransport({
|
||||
agent: this.httpAgent,
|
||||
client,
|
||||
url,
|
||||
})
|
||||
this._url = url
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"xen-api": "./cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vates/coalesce-calls": "^0.1.0",
|
||||
@@ -48,7 +48,8 @@
|
||||
"promise-toolbox": "^0.21.0",
|
||||
"proxy-agent": "^6.3.1",
|
||||
"pw": "0.0.4",
|
||||
"xmlrpc": "^1.3.2",
|
||||
"undici": "^6.2.1",
|
||||
"xmlrpc-parser": "^1.0.3",
|
||||
"xo-collection": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import httpRequestPlus from 'http-request-plus'
|
||||
import { format, parse } from 'json-rpc-protocol'
|
||||
|
||||
import XapiError from '../_XapiError.mjs'
|
||||
@@ -6,18 +5,19 @@ import XapiError from '../_XapiError.mjs'
|
||||
import UnsupportedTransport from './_UnsupportedTransport.mjs'
|
||||
|
||||
// https://github.com/xenserver/xenadmin/blob/0df39a9d83cd82713f32d24704852a0fd57b8a64/XenModel/XenAPI/Session.cs#L403-L433
|
||||
export default ({ secureOptions, url, agent }) => {
|
||||
export default ({ agent, client, url }) => {
|
||||
url = new URL('./jsonrpc', Object.assign(new URL('http://localhost'), url))
|
||||
const path = url.pathname + url.search
|
||||
|
||||
return async function (method, args) {
|
||||
const res = await httpRequestPlus(url, {
|
||||
...secureOptions,
|
||||
const res = await client.request({
|
||||
body: format.request(0, method, args),
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
path,
|
||||
agent,
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@ export default ({ secureOptions, url, agent }) => {
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
const response = parse(await res.text())
|
||||
const response = parse(await res.body.text())
|
||||
|
||||
if (response.type === 'response') {
|
||||
return response.result
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
import xmlrpc from 'xmlrpc'
|
||||
import { promisify } from 'promise-toolbox'
|
||||
|
||||
import XapiError from '../_XapiError.mjs'
|
||||
import { XmlRpcMessage, XmlRpcResponse } from 'xmlrpc-parser'
|
||||
|
||||
import prepareXmlRpcParams from './_prepareXmlRpcParams.mjs'
|
||||
|
||||
const logError = error => {
|
||||
if (error.res) {
|
||||
console.error('XML-RPC Error: %s (response status %s)', error.message, error.res.statusCode)
|
||||
console.error('%s', error.body)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
import XapiError from '../_XapiError.mjs'
|
||||
import UnsupportedTransport from './_UnsupportedTransport.mjs'
|
||||
|
||||
const parseResult = result => {
|
||||
const status = result.Status
|
||||
@@ -30,16 +20,31 @@ const parseResult = result => {
|
||||
return result.Value
|
||||
}
|
||||
|
||||
export default ({ secureOptions, url: { hostnameRaw, pathname, port, protocol }, agent }) => {
|
||||
const secure = protocol === 'https:'
|
||||
const client = (secure ? xmlrpc.createSecureClient : xmlrpc.createClient)({
|
||||
...(secure ? secureOptions : undefined),
|
||||
agent,
|
||||
host: hostnameRaw,
|
||||
pathname,
|
||||
port,
|
||||
})
|
||||
const call = promisify(client.methodCall, client)
|
||||
export default ({ agent, client, url }) => {
|
||||
url = new URL('./xmlrpc', Object.assign(new URL('http://localhost'), url))
|
||||
const path = url.pathname + url.search
|
||||
|
||||
return (method, args) => call(method, prepareXmlRpcParams(args)).then(parseResult, logError)
|
||||
return async function (method, args) {
|
||||
const message = new XmlRpcMessage(method, prepareXmlRpcParams(args))
|
||||
|
||||
const res = await client.request({
|
||||
body: message.xml(),
|
||||
headers: {
|
||||
Accept: 'text/xml',
|
||||
'Content-Type': 'text/xml',
|
||||
},
|
||||
method: 'POST',
|
||||
path,
|
||||
agent,
|
||||
})
|
||||
|
||||
if (res.headers['content-type'] !== 'text/xml' && res.headers['content-type'] !== 'application/xml') {
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
const xml = await res.body.text()
|
||||
const response = await new XmlRpcResponse().parse(xml)
|
||||
|
||||
return parseResult(response.params[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,7 +693,7 @@ ${entriesWithMissingStats.map(({ listItem }) => listItem).join('\n')}`
|
||||
payload.vm_uuid = xapiObject.uuid
|
||||
}
|
||||
// JSON is not well formed, can't use the default node parser
|
||||
return JSON5.parse(await (await xapi.getResource('/rrd_updates', payload)).text())
|
||||
return JSON5.parse(await (await xapi.getResource('/rrd_updates', payload)).body.text())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ export default class XapiStats {
|
||||
start: timestamp,
|
||||
},
|
||||
})
|
||||
.then(response => response.text().then(JSON5.parse))
|
||||
.then(response => response.body.text().then(JSON5.parse))
|
||||
.catch(err => {
|
||||
delete this.#hostCache[hostUuid][step]
|
||||
throw err
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
exportPoolMetadata($cancelToken) {
|
||||
return this.getResource($cancelToken, PATH_DB_DUMP, {
|
||||
task: this.task_create('Export pool metadata'),
|
||||
})
|
||||
}).then(response => response.body)
|
||||
},
|
||||
|
||||
// Restore the XAPI database from an XML backup
|
||||
|
||||
@@ -187,14 +187,14 @@ export default class RestApi {
|
||||
const host = req.xapiObject
|
||||
|
||||
res.setHeader('content-type', 'text/plain')
|
||||
await pipeline(await host.$xapi.getResource('/audit_log', { host }), compressMaybe(req, res))
|
||||
await pipeline((await host.$xapi.getResource('/audit_log', { host })).body, compressMaybe(req, res))
|
||||
},
|
||||
|
||||
async 'logs.tar'(req, res) {
|
||||
const host = req.xapiObject
|
||||
|
||||
res.setHeader('content-type', 'application/x-tar')
|
||||
await pipeline(await host.$xapi.getResource('/host_logs_download', { host }), compressMaybe(req, res))
|
||||
await pipeline((await host.$xapi.getResource('/host_logs_download', { host })).body, compressMaybe(req, res))
|
||||
},
|
||||
|
||||
async missing_patches(req, res) {
|
||||
|
||||
47
yarn.lock
47
yarn.lock
@@ -2107,6 +2107,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6"
|
||||
integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==
|
||||
|
||||
"@fastify/busboy@^2.0.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff"
|
||||
integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==
|
||||
|
||||
"@fontsource/poppins@^5.0.8":
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/poppins/-/poppins-5.0.8.tgz#a1c5540aedb3719a36eba5c7c5dfaa3aed3c9f80"
|
||||
@@ -18842,16 +18847,21 @@ sass@^1.38.1:
|
||||
immutable "^4.0.0"
|
||||
source-map-js ">=0.6.2 <2.0.0"
|
||||
|
||||
sax@1.2.x, sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
sax-parser@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/sax-parser/-/sax-parser-2.0.2.tgz#7b3b4a25fc69bf4e729ad5f0f98430205d461689"
|
||||
integrity sha512-EjLxlFjZdmv/cpOwV+klYEeOYjR2Dc9C495d2Ruk+N6xknrOnIfjSum2a63hfi9Vox2fCsjYc3NuDVo0YkGpjg==
|
||||
|
||||
sax@>=0.6, sax@>=0.6.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
|
||||
integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
|
||||
|
||||
sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
scheduler@^0.20.2:
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
|
||||
@@ -20889,6 +20899,13 @@ undici-types@~5.26.4:
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
undici@^6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/undici/-/undici-6.2.1.tgz#554293044619e065d986c37a4c92185c3bc02121"
|
||||
integrity sha512-7Wa9thEM6/LMnnKtxJHlc8SrTlDmxqJecgz1iy8KlsN0/iskQXOQCuPkrZLXbElPaSw5slFFyKIKXyJ3UtbApw==
|
||||
dependencies:
|
||||
"@fastify/busboy" "^2.0.0"
|
||||
|
||||
unicode-canonical-property-names-ecmascript@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
|
||||
@@ -21113,6 +21130,11 @@ use@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
|
||||
|
||||
utf8-base64@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/utf8-base64/-/utf8-base64-0.1.2.tgz#555806c458f9ba3f089c3ebe0c5f6198348bb57b"
|
||||
integrity sha512-DNeEx/I7HruiVsfk/DbEl4bpdRR/mv5p6FGDFZVyA8wqdMOqYp0CeCgW4/DzsPIW/skOq5Bxv49/eYfvAYJTWg==
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
@@ -22064,11 +22086,6 @@ xml2js@^0.4.19, xml2js@^0.4.23:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~11.0.0"
|
||||
|
||||
xmlbuilder@8.2.x:
|
||||
version "8.2.2"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
|
||||
integrity sha512-eKRAFz04jghooy8muekqzo8uCSVNeyRedbuJrp0fovbLIi7wlsYtdUn3vBAAPq2Y3/0xMz2WMEUQ8yhVVO9Stw==
|
||||
|
||||
xmlbuilder@^15.1.1:
|
||||
version "15.1.1"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
|
||||
@@ -22079,13 +22096,13 @@ xmlbuilder@~11.0.0:
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
|
||||
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
|
||||
|
||||
xmlrpc@^1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/xmlrpc/-/xmlrpc-1.3.2.tgz#26b2ea347848d028aac7e7514b5351976de3e83d"
|
||||
integrity sha512-jQf5gbrP6wvzN71fgkcPPkF4bF/Wyovd7Xdff8d6/ihxYmgETQYSuTc+Hl+tsh/jmgPLro/Aro48LMFlIyEKKQ==
|
||||
xmlrpc-parser@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/xmlrpc-parser/-/xmlrpc-parser-1.0.3.tgz#94f21bb74daaa2290a51471635c73f8b6dc1f3d9"
|
||||
integrity sha512-0197DF6MrKFoiaccl2GuB5mcc3F0jSebPLHIqsahpau4yyztg34bVZDhc6HGzs5hji801prnytCKTo4Kdpa7Rw==
|
||||
dependencies:
|
||||
sax "1.2.x"
|
||||
xmlbuilder "8.2.x"
|
||||
sax-parser "^2.0.2"
|
||||
utf8-base64 "^0.1.2"
|
||||
|
||||
xok@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
||||
Reference in New Issue
Block a user