Wrong queryString when building navigation plan in aurelia-router - aurelia

We're using aurelia-open-id-connect in our project and after successful login the redirect is removing the querystring from the url. I've debugged my way through the aurelia-router and I think I found something. Should'nt the queryString in redirectInstruction be used there?
export const buildRedirectPlan = (instruction: NavigationInstruction) => {
const config = instruction.config;
const router = instruction.router;
return router
._createNavigationInstruction(config.redirect)
.then(redirectInstruction => {
const params: Record<string, any> = {};
const originalInstructionParams = instruction.params;
const redirectInstructionParams = redirectInstruction.params;
for (let key in redirectInstructionParams) {
// If the param on the redirect points to another param, e.g. { route: first/:this, redirect: second/:this }
let val = redirectInstructionParams[key];
if (typeof val === 'string' && val[0] === ':') {
val = val.slice(1);
// And if that param is found on the original instruction then use it
if (val in originalInstructionParams) {
params[key] = originalInstructionParams[val];
}
} else {
params[key] = redirectInstructionParams[key];
}
}
let redirectLocation = router.generate(redirectInstruction.config, params, instruction.options);
// Special handling for child routes
for (let key in originalInstructionParams) {
redirectLocation = redirectLocation.replace(`:${key}`, originalInstructionParams[key]);
}
let queryString = instruction.queryString;
// use redirectInstruction.queryString instead?
if (queryString) {
redirectLocation += '?' + queryString;
}
return Promise.resolve(new Redirect(redirectLocation));
});
};

Related

vscode extension API editor.replace replace only first match while match 2 instances

developing an VS code extension where
search for color hex code in whole css document
replace the color hex code with variable name
although it match all color hex code but replace the only first instance and stops
below is the code snippet
export function activate(context: vscode.ExtensionContext) {
let activeEditor = vscode.window.activeTextEditor;
function replaceWithinDocument() {
if (!activeEditor) {
return;
}
const text = activeEditor.document.getText();
const reg = new RegExp('(?<color>#[0-9a-f]{3,6})', 'gim');
const matches = text.matchAll(reg);
const variableList = {};
let i = 0;
for (const match of matches) {
const { index, groups } = match;
i++;
console.log({ match });
const startPos = activeEditor.document.positionAt(index!);
const endPos = activeEditor.document.positionAt(index! + match[0].length);
console.log({ i, startPos, endPos });
//Creating a new range with startLine, startCharacter & endLine, endCharacter.
let range = new vscode.Range(startPos, endPos);
// eslint-disable-next-line #typescript-eslint/naming-convention
Object.assign(variableList, { [`--var-${i}`]: groups?.color });
activeEditor.edit(editBuilder => {
editBuilder.replace(range, `--var-${i}`);
});
}
console.log({ variableList });
}
function triggerUpdateDecorations(throttle = false) {
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
if (throttle) {
timeout = setTimeout(replaceWithinDocument, 500);
} else {
replaceWithinDocument();
}
}
if (activeEditor) {
triggerUpdateDecorations();
}
final document
body {
background-color: --var-1;
color: #223344;
}
you can see in the screenshot that console.log({ variableList }); have both color code in it
so what is wrong here?
See allow delay between edits via vscode extension api. Because of the particular nature of the editBuilder object
The editBuilder "expires" once you return from the callback passed to
TextEditor.edit.
you should put your matches loop inside the call to the edit call like this sample code:
// get your matches above first
editor.edit(editBuilder => {
let i = 0;
for (const match of matches) {
// build your replacement here
const matchStartPos = document.positionAt(match.index);
const matchEndPos = document.positionAt(match.index + match[0].length);
const matchRange = new Range(matchStartPos, matchEndPos);
editBuilder.replace(matchRange, resolvedReplace);
}
}).then(async (resolved) => {
});

Getting "spc message cannot be null" as response

Getting "spc message cannot be null" as response every time while providing implementation of Shaka player to play fairplay content on safari browser.Tried many ways to provide spc message in body and header also and we are actually sending it that i can see in network tab nut still cant find a solution. Here is the code below.
if (this.platform.getBrowserPlatform() === Constants.PLATFORMS.SAFARI_WEB) {
this.shakaPlayer.configure({
drm: {
servers: {
'com.apple.fps.1_0': `${this.config.baseUrl}${Constants.DRM_FAIRPLAY_LICENSE}`,
},
advanced: {
'com.apple.fps.1_0': {
serverCertificate: cert,
},
},
},
});
let that = this //,licenseUri;
this.shakaPlayer.configure('drm.initDataTransform', (initData) => {
const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
var contentId = skdUri.substring(skdUri.indexOf('skd://') + 6);
// licenseUri = skdUri.replace('skd://', 'https://');
const url = new URL(contentId);
const urlParams = new URLSearchParams(url.search);
const cert = that.shakaPlayer.drmInfo().serverCertificate;
let id = urlParams.get('contentId');
that.id = id;
return shaka.util.FairPlayUtils.initDataTransform(initData, id, cert);
// let skdUrl = shaka.util.StringUtils.fromBytesAutoDetect(initData);
// licenseUri = skdUrl.replace('skd://', 'https://');
// const cert = that.shakaPlayer.drmInfo().serverCertificate;
// return shaka.util.FairPlayUtils.initDataTransform(initData, licenseUri, cert);
});
this.shakaPlayer.getNetworkingEngine().registerRequestFilter((type, request) => {
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
return;
}
let token = localStorage.getItem('auth');
let testToken = JSON.parse(token);
const originalPayload = new Uint8Array(request.body);
const base64Payload = shaka.util.Uint8ArrayUtils.toBase64(originalPayload);
const params = `{ "spc": "${base64Payload}", "assetId":"${that.id}"}`;
request.body = shaka.util.StringUtils.toUTF8(params);
request.headers['Content-Type'] = 'application/json';
request.headers['Authorization'] = `JWT ${testToken.access_token}`
console.log("request.body", request.body)
});
this.shakaPlayer.getNetworkingEngine().registerResponseFilter((type, response) => {
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
return;
}
console.log("license passed")
let responseText = shaka.util.StringUtils.fromUTF8(response.data);
responseText = responseText.trim();
if (responseText.substr(0, 5) === '<ckc>' &&
responseText.substr(-6) === '</ckc>') {
responseText = responseText.slice(5, -6);
}
response.data = shaka.util.Uint8ArrayUtils.fromBase64(responseText).buffer;
});
this.shakaPlayer.load(this.getProgramUrl(channel, program, restart)).then(() => {
console.log('1', this.shakaPlayer.isTextTrackVisible());
console.log('2', this.shakaPlayer.getTextTracks());
console.log('3', this.shakaPlayer.getTextLanguages());
}).catch((error) => {
console.log(error);
});
Smooth play of fairplay content on safari or some advise what can i do in this case

Cloudflare ESI worker / TypeError: Body has already been used

I'm trying to use a CloudFlare worker to manage my backend ESI fragments but i get an error:
Uncaught (in promise) TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
Uncaught (in response) TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.
I don't find where the body has already been used
The process is:
get a response with the parts
Transform the body by replacing parts fragments with sub Backend calls (streamTransformBody function)
return the response
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
});
const esiHeaders = {
"user-agent": "cloudflare"
}
async function handleRequest(request) {
// get cookies from the request
if(cookie = request.headers.get("Cookie")) {
esiHeaders["Cookie"] = cookie
console.log(cookie)
}
// Clone the request so that it's no longer immutable
newRequest = new Request(request)
// remove cookie from request
newRequest.headers.delete('Cookie')
// Add header to get <esi>
newRequest.headers.set("Surrogate-Capability", "abc=ESI/1.0")
console.log(newRequest.url);
const response = await fetch(newRequest);
let contentType = response.headers.get('content-type')
if (!contentType || !contentType.startsWith("text/")) {
return response
}
// Clone the response so that it's no longer immutable
const newResponse = new Response(response.body, response);
let { readable, writable } = new TransformStream()
streamTransformBody(newResponse.body, writable)
newResponse.headers.append('x-workers-hello', 'Hello from
Cloudflare Workers');
return newResponse;
}
async function streamTransformBody(readable, writable) {
const startTag = "<".charCodeAt(0);
const endTag = ">".charCodeAt(0);
let reader = readable.getReader();
let writer = writable.getWriter();
let templateChunks = null;
while (true) {
let { done, value } = await reader.read();
if (done) break;
while (value.byteLength > 0) {
if (templateChunks) {
let end = value.indexOf(endTag);
if (end === -1) {
templateChunks.push(value);
break;
} else {
templateChunks.push(value.subarray(0, end));
await writer.write(await translate(templateChunks));
templateChunks = null;
value = value.subarray(end + 1);
}
}
let start = value.indexOf(startTag);
if (start === -1) {
await writer.write(value);
break;
} else {
await writer.write(value.subarray(0, start));
value = value.subarray(start + 1);
templateChunks = [];
}
}
}
await writer.close();
}
async function translate(chunks) {
const decoder = new TextDecoder();
let templateKey = chunks.reduce(
(accumulator, chunk) =>
accumulator + decoder.decode(chunk, { stream: true }),
""
);
templateKey += decoder.decode();
return handleTemplate(new TextEncoder(), templateKey);
}
async function handleTemplate(encoder, templateKey) {
const linkRegex = /(esi:include.*src="(.*?)".*\/)/gm
let result = linkRegex.exec(templateKey);
let esi
if (!result) {
return encoder.encode(`<${templateKey}>`);
}
if (result[2]) {
esi = await subRequests(result[2]);
}
return encoder.encode(
`${esi}`
);
}
async function subRequests(target){
target = esiHost + target
const init = {
method: 'GET',
headers: esiHeaders
}
let response = await fetch(target, init)
if (!response.ok) {
return ''
}
let text = await response.text()
return '<!--esi-->' + text + '<!--/esi-->'
}

How can I eject quasar cli and use Vue + Quasar UMD?

I'm using Quasar for SPA only. But I don't need all the things that come with Quasar CLI.
Is there a way to eject Quasar CLI and start using Vue + Quasar UMD?
Basically, stop using quasar dev and start using vue serve?
Yes, you can. The following changes should be made:
// vue.config.js
const QuasarLoader = require('./quasar-loader/index');
module.exports =
{
css:
{
loaderOptions:
{
scss:
{
prependData: `#import "~quasar/src/css/variables.sass";`
}
}
},
transpileDependencies: ['quasar'],
configureWebpack: (config) =>
{
if (!config.plugins) config.plugins = [];
config.plugins.push(new QuasarLoader());
},
}
// quasar-loader/auto-import.js
/**
* Quasar runtime for auto-importing
* components or directives.
*
* Warning! This file does NOT get transpiled by Babel
* but is included into the UI code.
*
* #param component {Vue} Component object
* #param type {String} One of 'components' or 'directives'
* #param items {Object} Object containing components or directives
*/
module.exports = function quasarLoader(component, type, items)
{
/* we use a workaround in functional templates
<template>
<component :is="$options.components.QBtn" ... />
</template>
*/
var target, i;
var opt = component.options;
if (!opt[type])
{
opt[type] = items
}
else
{
target = opt[type];
for (i in items)
{
if (!target[i])
{
target[i] = items[i]
}
}
}
};
// quasar-loader/index.js
const RuleSet = require('webpack/lib/RuleSet');
let vueLoaderPath;
try
{
vueLoaderPath = require.resolve('vue-loader');
}
catch (err)
{}
function isVueLoader(use)
{
return use.ident === 'vue-loader-options' ||
use.loader === 'vue-loader' ||
(vueLoaderPath && use.loader === vueLoaderPath)
}
class QuasarLoaderPlugin
{
constructor(options)
{
this.options = options || {}
}
apply(compiler)
{
// use webpack's RuleSet utility to normalize user rules
const rawRules = compiler.options.module.rules;
const { rules } = new RuleSet(rawRules);
// find the rule that applies to vue files
const vueRuleIndex = rules.findIndex(rule => rule.use && rule.use.find(isVueLoader));
const vueRule = rules[vueRuleIndex];
if (!vueRule)
{
throw new Error(
`[QuasarLoaderPlugin Error] No matching rule for vue-loader found.\n` +
`Make sure there is at least one root-level rule that uses vue-loader.`
)
}
vueRule.use.unshift({
loader: require.resolve('./loader'),
options: this.options || { nameCase: 'kebab' }
});
compiler.options.module.rules = rules;
}
}
module.exports = QuasarLoaderPlugin;
// quasar-loader/loader.js
const path = require('path');
const compiler = require('vue-template-compiler');
// const loaderOptions = require('loader-utils/lib/getOptions');
const stringifyRequest = require('loader-utils/lib/stringifyRequest');
const importData = require('quasar/dist/babel-transforms/auto-import.json');
const importTransform = require('quasar/dist/babel-transforms/imports.js');
const runtimePath = require.resolve('./auto-import.js');
// regex to match functional components
const funcCompRegex = new RegExp(
'var\\s+component\\s*=\\s*normalizer\\((?:[^,]+,){3}\\s*true,'
);
function transform(itemArray)
{
return itemArray
.map(name => `import ${name} from '${importTransform(name)}'`)
.join(`\n`)
}
module.exports = async function (content, sourceMap)
{
this.async();
this.cacheable();
if (!this.resourceQuery)
{
const readFile = path => new Promise((resolve, reject) =>
{
this.fs.readFile(path, function (err, data)
{
if (err) reject(err);
else resolve(data)
})
});
this.addDependency(this.resourcePath);
const tags = new Set();
const directives = new Set();
const file = (await readFile(this.resourcePath)).toString('utf8');
const component = compiler.parseComponent(file);
if (component.template)
{
if (component.template.src)
{
const externalFile = (await new Promise((resolve, reject) =>
this.resolve(path.dirname(this.resourcePath), component.template.src, (err, result) =>
{
if (err) reject(err);
else resolve(result)
})
));
component.template.content = (await readFile(externalFile)).toString('utf8'); // external content
}
const compRegexKebab = new RegExp('^' + importData.regex.kebabComponents + '$');
const compRegexPascal = new RegExp('^' + importData.regex.pascalComponents + '$');
const dirRegex = new RegExp('^' + importData.regex.directives + '$');
compiler.compile(component.template.content, {
modules: [{
postTransformNode: node =>
{
if ("directives" in node)
{
node.directives.forEach(({ name }) =>
{
if (dirRegex.test('v-' + name))
{
directives.add(importData.importName['v-' + name]);
}
});
}
if (compRegexKebab.test(node.tag))
{
tags.add(importData.importName[node.tag]);
}
else if (compRegexPascal.test(node.tag))
{
tags.add(node.tag);
}
}
}]
});
const arrTags = [...tags];
const arrDirs = [...directives];
if (arrTags.length > 0 || arrDirs.length > 0)
{
const functional = funcCompRegex.test(content);
let newContent = '/* quasar-loader */\n';
newContent += `import qInstall from ${stringifyRequest(this, runtimePath)}\n`;
if (arrTags.length > 0)
{
if (functional) console.error('Using workaround for local Vue components (' + arrTags.join(',') + ') in a functional template.');
newContent += transform(arrTags) + '\n';
newContent += `qInstall(component, "components", {${arrTags.join(",")}})\n`;
}
if (arrDirs.length > 0)
{
if (functional) console.error('Using local Vue directive (' + arrDirs.join(',') + ') in a functional component is not supported.');
newContent += transform(arrDirs) + '\n';
newContent += `qInstall(component, "directives", {${arrDirs.join(",")}})\n`;
}
// Insert our modification before the HMR code
const hotReload = content.indexOf('/* hot reload */');
if (hotReload > -1)
{
content = content.slice(0, hotReload) + newContent + '\n\n' + content.slice(hotReload)
}
else
{
content += '\n\n' + newContent
}
}
}
}
this.callback(null, content, sourceMap);
};
// src/main.js
import QuasarInstall from 'quasar/src/vue-plugin'
import iconSet from 'quasar/icon-set/svg-mdi-v5'
// import QuasarDialog from 'quasar/src/plugins/Dialog'
import '#/assets/scss/quasar.scss'
QuasarInstall.install(Vue, {
iconSet,
plugins:
{
// Dialog: QuasarDialog,
},
});
// src/assets/scss/quasar.scss
$primary : #409EFF;
$secondary : #26A69A;
$accent : #9C27B0;
$dark : #1D1D1D;
$positive : #20A835;
$negative : #F04025;
$info : #1975D0;
$warning : #F2C037;
#import '~quasar/src/css/index.sass';
If you want to use Quasar and Vue without CLI at all, you can check this starter project.
It's just Quasar UMD (ver.2) and vanilla Vue (ver.3).
Github: https://github.com/SaleCar/Quasar-UMD-Template
Demo: http://quasar.rf.gd/

React-Native componentWillRecieveProps rendering issue

In my RN project, I want to achieve this.
// componentWillReceiveProps
componentWillReceiveProps = async (nextProps) => {
let { searchText, peopleTab } = this.props;
let params = {};
if (peopleTab !== nextProps.peopleTab) {
params.peopleTab = nextProps.peopleTab;
}
// here i want to pass nextProps.searchText without a condition with the params like this.
// params.searchText = nextProps.searchText
if (Object.keys(params).length > 0) {
await this.props.fetchUnfollowedPeople(params);
}
}
I want to send nextProps.searchText with params object, if there is a new value. Otherwise I want to send this.props.searchText with the params object.
The above code, if I uncomment
// params.searchText = nextProps.searchText
it gives the infinity loop. How can I achieve this?
Setting the let { searchText, peopleTab } = this.props; in componentWillReceiveProps causes the new value to be pasted
componentWillMount() {
this.searchText = this.props.searchText ;
this.peopleTab = this.props.peopleTab ;
}
componentWillReceiveProps = async (nextProps) => {
const params = [];
if (this.peopleTab !== nextProps.peopleTab) {
params['peopleTab'] = nextProps.peopleTab ;
}
if (Object.keys(params).length > 0) {
await this.props.fetchUnfollowedPeople(params);
}
}