use canonical_url for everything #187
|
@ -6,6 +6,7 @@
|
||||||
./flow-typed
|
./flow-typed
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
|
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe
|
||||||
module.system.node.resolve_dirname=./src
|
module.system.node.resolve_dirname=./src
|
||||||
module.name_mapper='^redux\(.*\)$' -> '<PROJECT_ROOT>/src/redux\1'
|
module.name_mapper='^redux\(.*\)$' -> '<PROJECT_ROOT>/src/redux\1'
|
||||||
module.name_mapper='^util\(.*\)$' -> '<PROJECT_ROOT>/src/util\1'
|
module.name_mapper='^util\(.*\)$' -> '<PROJECT_ROOT>/src/util\1'
|
||||||
|
|
353
dist/bundle.es.js
vendored
|
@ -897,45 +897,46 @@ const getSearchQueryString = (query, options = {}, includeUserOptions = false) =
|
||||||
|
|
||||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||||
|
|
||||||
|
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
||||||
const channelNameMinLength = 1;
|
const channelNameMinLength = 1;
|
||||||
const claimIdMaxLength = 40;
|
const claimIdMaxLength = 40;
|
||||||
|
|
||||||
// see https://spec.lbry.com/#urls
|
// see https://spec.lbry.com/#urls
|
||||||
const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
|
const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
|
||||||
const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
|
const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
|
||||||
|
const regexPartProtocol = '^((?:lbry://)?)';
|
||||||
|
const regexPartStreamOrChannelName = '([^:$#/]*)';
|
||||||
|
const regexPartModifierSeparator = '([:$#]?)([^/]*)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a LBRY name into its component parts. Throws errors with user-friendly
|
* Parses a LBRY name into its component parts. Throws errors with user-friendly
|
||||||
* messages for invalid names.
|
* messages for invalid names.
|
||||||
*
|
*
|
||||||
* N.B. that "name" indicates the value in the name position of the URI. For
|
|
||||||
* claims for channel content, this will actually be the channel name, and
|
|
||||||
* the content name is in the path (e.g. lbry://@channel/content)
|
|
||||||
*
|
|
||||||
* In most situations, you'll want to use the contentName and channelName keys
|
|
||||||
* and ignore the name key.
|
|
||||||
*
|
|
||||||
* Returns a dictionary with keys:
|
* Returns a dictionary with keys:
|
||||||
* - name (string): The value in the "name" position in the URI. Note that this
|
* - path (string)
|
||||||
* could be either content name or channel name; see above.
|
|
||||||
* - path (string, if persent)
|
|
||||||
* - claimSequence (int, if present)
|
|
||||||
* - bidPosition (int, if present)
|
|
||||||
* - claimId (string, if present)
|
|
||||||
* - isChannel (boolean)
|
* - isChannel (boolean)
|
||||||
* - contentName (string): For anon claims, the name; for channel claims, the path
|
* - streamName (string, if present)
|
||||||
* - channelName (string, if present): Channel name without @
|
* - streamClaimId (string, if present)
|
||||||
|
* - channelName (string, if present)
|
||||||
|
* - channelClaimId (string, if present)
|
||||||
|
* - primaryClaimSequence (int, if present)
|
||||||
|
* - secondaryClaimSequence (int, if present)
|
||||||
|
* - primaryBidPosition (int, if present)
|
||||||
|
* - secondaryBidPosition (int, if present)
|
||||||
*/
|
*/
|
||||||
function parseURI(URI, requireProto = false) {
|
|
||||||
// Break into components. Empty sub-matches are converted to null
|
|
||||||
const componentsRegex = new RegExp('^((?:lbry://)?)' + // protocol
|
|
||||||
'([^:$#/]*)' + // claim name (stops at the first separator or end)
|
|
||||||
'([:$#]?)([^/]*)' + // modifier separator, modifier (stops at the first path separator or end)
|
|
||||||
'(/?)(.*)' // path separator, path
|
|
||||||
);
|
|
||||||
const [proto, claimName, modSep, modVal, pathSep, path] = componentsRegex.exec(URI).slice(1).map(match => match || null);
|
|
||||||
|
|
||||||
let contentName;
|
function parseURI(URL, requireProto = false) {
|
||||||
|
// Break into components. Empty sub-matches are converted to null
|
||||||
|
const componentsRegex = new RegExp(regexPartProtocol + // protocol
|
||||||
|
regexPartStreamOrChannelName + // stream or channel name (stops at the first separator or end)
|
||||||
|
regexPartModifierSeparator + // modifier separator, modifier (stops at the first path separator or end)
|
||||||
|
'(/?)' + // path separator, there should only be one (optional) slash to separate the stream and channel parts
|
||||||
|
regexPartStreamOrChannelName + regexPartModifierSeparator);
|
||||||
|
|
||||||
|
const regexMatch = componentsRegex.exec(URL) || [];
|
||||||
|
const [proto, ...rest] = regexMatch.slice(1).map(match => match || null);
|
||||||
|
const path = rest.join('');
|
||||||
|
const [streamNameOrChannelName, primaryModSeparator, primaryModValue, pathSep, possibleStreamName, secondaryModSeparator, secondaryModValue] = rest;
|
||||||
|
|
||||||
// Validate protocol
|
// Validate protocol
|
||||||
if (requireProto && !proto) {
|
if (requireProto && !proto) {
|
||||||
|
@ -943,14 +944,15 @@ function parseURI(URI, requireProto = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and process name
|
// Validate and process name
|
||||||
if (!claimName) {
|
if (!streamNameOrChannelName) {
|
||||||
throw new Error(__('URI does not include name.'));
|
throw new Error(__('URI does not include name.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const isChannel = claimName.startsWith('@');
|
const includesChannel = streamNameOrChannelName.startsWith('@');
|
||||||
const channelName = isChannel ? claimName.slice(1) : claimName;
|
const isChannel = streamNameOrChannelName.startsWith('@') && !possibleStreamName;
|
||||||
|
const channelName = includesChannel && streamNameOrChannelName.slice(1);
|
||||||
|
|
||||||
if (isChannel) {
|
if (includesChannel) {
|
||||||
if (!channelName) {
|
if (!channelName) {
|
||||||
throw new Error(__('No channel name after @.'));
|
throw new Error(__('No channel name after @.'));
|
||||||
}
|
}
|
||||||
|
@ -958,30 +960,42 @@ function parseURI(URI, requireProto = false) {
|
||||||
if (channelName.length < channelNameMinLength) {
|
if (channelName.length < channelNameMinLength) {
|
||||||
throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength));
|
throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
contentName = path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameBadChars = (channelName || claimName).match(regexInvalidURI);
|
// Validate and process modifier
|
||||||
if (nameBadChars) {
|
const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier(primaryModSeparator, primaryModValue);
|
||||||
throw new Error(__(`Invalid character %s in name: %s.`, nameBadChars.length === 1 ? '' : 's', nameBadChars.join(', ')));
|
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier(secondaryModSeparator, secondaryModValue);
|
||||||
}
|
const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName;
|
||||||
|
const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId;
|
||||||
|
const channelClaimId = includesChannel && primaryClaimId;
|
||||||
|
|
||||||
// Validate and process modifier (claim ID, bid position or claim sequence)
|
return _extends({
|
||||||
|
isChannel,
|
||||||
|
path
|
||||||
|
}, streamName ? { streamName } : {}, streamClaimId ? { streamClaimId } : {}, channelName ? { channelName } : {}, channelClaimId ? { channelClaimId } : {}, primaryClaimSequence ? { primaryClaimSequence: parseInt(primaryClaimSequence, 10) } : {}, secondaryClaimSequence ? { secondaryClaimSequence: parseInt(secondaryClaimSequence, 10) } : {}, primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}, secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}, {
|
||||||
|
|
||||||
|
// The values below should not be used for new uses of parseURI
|
||||||
|
// They will not work properly with canonical_urls
|
||||||
|
claimName: streamNameOrChannelName,
|
||||||
|
claimId: primaryClaimId
|
||||||
|
}, streamName ? { contentName: streamName } : {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseURIModifier(modSeperator, modValue) {
|
||||||
let claimId;
|
let claimId;
|
||||||
let claimSequence;
|
let claimSequence;
|
||||||
let bidPosition;
|
let bidPosition;
|
||||||
if (modSep) {
|
if (modSeperator) {
|
||||||
if (!modVal) {
|
if (!modValue) {
|
||||||
throw new Error(__(`No modifier provided after separator %s.`, modSep));
|
throw new Error(__(`No modifier provided after separator %s.`, modSeperator));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modSep === '#') {
|
if (modSeperator === '#') {
|
||||||
claimId = modVal;
|
claimId = modValue;
|
||||||
} else if (modSep === ':') {
|
} else if (modSeperator === ':') {
|
||||||
claimSequence = modVal;
|
claimSequence = modValue;
|
||||||
} else if (modSep === '$') {
|
} else if (modSeperator === '$') {
|
||||||
bidPosition = modVal;
|
bidPosition = modValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -997,27 +1011,7 @@ function parseURI(URI, requireProto = false) {
|
||||||
throw new Error(__('Bid position must be a number.'));
|
throw new Error(__('Bid position must be a number.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and process path
|
return [claimId, claimSequence, bidPosition];
|
||||||
if (path) {
|
|
||||||
if (!isChannel) {
|
|
||||||
throw new Error(__('Only channel URIs may have a path.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathBadChars = path.match(regexInvalidURI);
|
|
||||||
if (pathBadChars) {
|
|
||||||
throw new Error(__(`Invalid character in path: %s`, pathBadChars.join(', ')));
|
|
||||||
}
|
|
||||||
|
|
||||||
contentName = path;
|
|
||||||
} else if (pathSep) {
|
|
||||||
throw new Error(__('No path provided after /'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _extends({
|
|
||||||
claimName,
|
|
||||||
path,
|
|
||||||
isChannel
|
|
||||||
}, contentName ? { contentName } : {}, channelName ? { channelName } : {}, claimSequence ? { claimSequence: parseInt(claimSequence, 10) } : {}, bidPosition ? { bidPosition: parseInt(bidPosition, 10) } : {}, claimId ? { claimId } : {}, path ? { path } : {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1025,67 +1019,107 @@ function parseURI(URI, requireProto = false) {
|
||||||
*
|
*
|
||||||
* The channelName key will accept names with or without the @ prefix.
|
* The channelName key will accept names with or without the @ prefix.
|
||||||
*/
|
*/
|
||||||
function buildURI(URIObj, includeProto = true, protoDefault = 'lbry://') {
|
function buildURI(UrlObj, includeProto = true, protoDefault = 'lbry://') {
|
||||||
const { claimId, claimSequence, bidPosition, contentName, channelName } = URIObj;
|
const {
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryClaimSequence,
|
||||||
|
primaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
secondaryBidPosition
|
||||||
|
} = UrlObj,
|
||||||
|
deprecatedParts = _objectWithoutProperties(UrlObj, ['streamName', 'streamClaimId', 'channelName', 'channelClaimId', 'primaryClaimSequence', 'primaryBidPosition', 'secondaryClaimSequence', 'secondaryBidPosition']);
|
||||||
|
const { claimId, claimName, contentName } = deprecatedParts;
|
||||||
|
|
||||||
let { claimName, path } = URIObj;
|
if (!claimName && !channelName && !streamName) {
|
||||||
|
throw new Error(__("'claimName', 'channelName', and 'streamName' are all empty. One must be present to build a url."));
|
||||||
if (channelName) {
|
|
||||||
const channelNameFormatted = channelName.startsWith('@') ? channelName : `@${channelName}`;
|
|
||||||
if (!claimName) {
|
|
||||||
claimName = channelNameFormatted;
|
|
||||||
} else if (claimName !== channelNameFormatted) {
|
|
||||||
throw new Error(__('Received a channel content URI, but claim name and channelName do not match. "name" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentName) {
|
const formattedChannelName = channelName && (channelName.startsWith('@') ? channelName : `@${channelName}`);
|
||||||
if (!claimName) {
|
const primaryClaimName = claimName || contentName || formattedChannelName || streamName;
|
||||||
claimName = contentName;
|
const primaryClaimId = claimId || (formattedChannelName ? channelClaimId : streamClaimId);
|
||||||
} else if (!path) {
|
const secondaryClaimName = !claimName && contentName || (formattedChannelName ? streamName : null);
|
||||||
path = contentName;
|
const secondaryClaimId = secondaryClaimName && streamClaimId;
|
||||||
}
|
|
||||||
if (path && path !== contentName) {
|
|
||||||
throw new Error(__('Path and contentName do not match. Only one is required; most likely you wanted contentName.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (includeProto ? protoDefault : '') + claimName + (claimId ? `#${claimId}` : '') + (claimSequence ? `:${claimSequence}` : '') + (bidPosition ? `${bidPosition}` : '') + (path ? `/${path}` : '');
|
return (includeProto ? protoDefault : '') +
|
||||||
|
// primaryClaimName will always exist here because we throw above if there is no "name" value passed in
|
||||||
|
// $FlowFixMe
|
||||||
|
primaryClaimName + (primaryClaimId ? `#${primaryClaimId}` : '') + (primaryClaimSequence ? `:${primaryClaimSequence}` : '') + (primaryBidPosition ? `${primaryBidPosition}` : '') + (secondaryClaimName ? `/${secondaryClaimName}` : '') + (secondaryClaimId ? `#${secondaryClaimId}` : '') + (secondaryClaimSequence ? `:${secondaryClaimSequence}` : '') + (secondaryBidPosition ? `${secondaryBidPosition}` : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes a parseable LBRY URI and converts it to standard, canonical format */
|
/* Takes a parseable LBRY URL and converts it to standard, canonical format */
|
||||||
function normalizeURI(URI) {
|
function normalizeURI(URL) {
|
||||||
const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI);
|
const {
|
||||||
return buildURI({ claimName, path, claimSequence, bidPosition, claimId });
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryClaimSequence,
|
||||||
|
primaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
secondaryBidPosition
|
||||||
|
} = parseURI(URL);
|
||||||
|
|
||||||
|
return buildURI({
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryClaimSequence,
|
||||||
|
primaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
secondaryBidPosition
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isURIValid(URI) {
|
function isURIValid(URL) {
|
||||||
let parts;
|
|
||||||
try {
|
try {
|
||||||
parts = parseURI(normalizeURI(URI));
|
parseURI(normalizeURI(URL));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return parts && parts.claimName;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNameValid(claimName) {
|
function isNameValid(claimName) {
|
||||||
return !regexInvalidURI.test(claimName);
|
return !regexInvalidURI.test(claimName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isURIClaimable(URI) {
|
function isURIClaimable(URL) {
|
||||||
let parts;
|
let parts;
|
||||||
try {
|
try {
|
||||||
parts = parseURI(normalizeURI(URI));
|
parts = parseURI(normalizeURI(URL));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return parts && parts.claimName && !parts.claimId && !parts.bidPosition && !parts.claimSequence && !parts.isChannel && !parts.path;
|
|
||||||
|
return parts && parts.streamName && !parts.streamClaimId && !parts.isChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToShareLink(URI) {
|
function convertToShareLink(URL) {
|
||||||
const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI);
|
const {
|
||||||
return buildURI({ claimName, path, claimSequence, bidPosition, claimId }, true, 'https://open.lbry.com/');
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryBidPosition,
|
||||||
|
primaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
secondaryClaimSequence
|
||||||
|
} = parseURI(URL);
|
||||||
|
return buildURI({
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryBidPosition,
|
||||||
|
primaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
secondaryClaimSequence
|
||||||
|
}, true, 'https://open.lbry.com/');
|
||||||
}
|
}
|
||||||
|
|
||||||
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||||
|
@ -1130,13 +1164,13 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec
|
||||||
let searchSuggestions = [];
|
let searchSuggestions = [];
|
||||||
try {
|
try {
|
||||||
const uri = normalizeURI(query);
|
const uri = normalizeURI(query);
|
||||||
const { claimName, isChannel } = parseURI(uri);
|
const { channelName, streamName, isChannel } = parseURI(uri);
|
||||||
searchSuggestions.push({
|
searchSuggestions.push({
|
||||||
value: claimName,
|
value: streamName,
|
||||||
type: SEARCH_TYPES.SEARCH
|
type: SEARCH_TYPES.SEARCH
|
||||||
}, {
|
}, {
|
||||||
value: uri,
|
value: uri,
|
||||||
shorthand: isChannel ? claimName.slice(1) : claimName,
|
shorthand: isChannel ? channelName : streamName,
|
||||||
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE
|
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1157,11 +1191,11 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec
|
||||||
// determine if it's a channel
|
// determine if it's a channel
|
||||||
try {
|
try {
|
||||||
const uri = normalizeURI(suggestion);
|
const uri = normalizeURI(suggestion);
|
||||||
const { claimName, isChannel } = parseURI(uri);
|
const { channelName, streamName, isChannel } = parseURI(uri);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value: uri,
|
value: uri,
|
||||||
shorthand: isChannel ? claimName.slice(1) : claimName,
|
shorthand: isChannel ? channelName : streamName,
|
||||||
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE
|
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1377,7 +1411,7 @@ const selectTransactionListFilter = reselect.createSelector(selectState$1, state
|
||||||
|
|
||||||
var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||||
|
|
||||||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
||||||
|
|
||||||
const matureTagMap = MATURE_TAGS.reduce((acc, tag) => _extends$2({}, acc, { [tag]: true }), {});
|
const matureTagMap = MATURE_TAGS.reduce((acc, tag) => _extends$2({}, acc, { [tag]: true }), {});
|
||||||
|
|
||||||
|
@ -1404,7 +1438,7 @@ const isClaimNsfw = claim => {
|
||||||
function createNormalizedClaimSearchKey(options) {
|
function createNormalizedClaimSearchKey(options) {
|
||||||
// Ignore page because we don't care what the last page searched was, we want everything
|
// Ignore page because we don't care what the last page searched was, we want everything
|
||||||
// Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567"
|
// Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567"
|
||||||
const rest = _objectWithoutProperties(options, ['page', 'release_time']);
|
const rest = _objectWithoutProperties$1(options, ['page', 'release_time']);
|
||||||
const query = JSON.stringify(rest);
|
const query = JSON.stringify(rest);
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
@ -1445,8 +1479,10 @@ const selectPendingClaims = reselect.createSelector(selectState$2, state => Obje
|
||||||
|
|
||||||
const makeSelectClaimIsPending = uri => reselect.createSelector(selectPendingById, pendingById => {
|
const makeSelectClaimIsPending = uri => reselect.createSelector(selectPendingById, pendingById => {
|
||||||
let claimId;
|
let claimId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
({ claimId } = parseURI(uri));
|
const { isChannel, channelClaimId, streamClaimId } = parseURI(uri);
|
||||||
|
claimId = isChannel ? channelClaimId : streamClaimId;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (claimId) {
|
if (claimId) {
|
||||||
|
@ -1455,7 +1491,8 @@ const makeSelectClaimIsPending = uri => reselect.createSelector(selectPendingByI
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeSelectPendingByUri = uri => reselect.createSelector(selectPendingById, pendingById => {
|
const makeSelectPendingByUri = uri => reselect.createSelector(selectPendingById, pendingById => {
|
||||||
const { claimId } = parseURI(uri);
|
const { isChannel, channelClaimId, streamClaimId } = parseURI(uri);
|
||||||
|
const claimId = isChannel ? channelClaimId : streamClaimId;
|
||||||
return pendingById[claimId];
|
return pendingById[claimId];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1464,13 +1501,16 @@ const makeSelectClaimForUri = uri => reselect.createSelector(selectClaimsByUri,
|
||||||
// It won't be in claimsByUri because resolving it will return nothing
|
// It won't be in claimsByUri because resolving it will return nothing
|
||||||
|
|
||||||
let valid;
|
let valid;
|
||||||
let claimId;
|
let channelClaimId;
|
||||||
|
let streamClaimId;
|
||||||
|
let isChannel;
|
||||||
try {
|
try {
|
||||||
({ claimId } = parseURI(uri));
|
({ isChannel, channelClaimId, streamClaimId } = parseURI(uri));
|
||||||
valid = true;
|
valid = true;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
const claimId = isChannel ? channelClaimId : streamClaimId;
|
||||||
const pendingClaim = pendingById[claimId];
|
const pendingClaim = pendingById[claimId];
|
||||||
|
|
||||||
if (pendingClaim) {
|
if (pendingClaim) {
|
||||||
|
@ -1720,15 +1760,18 @@ const selectClaimSearchByQueryLastPageReached = reselect.createSelector(selectSt
|
||||||
|
|
||||||
const makeSelectShortUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.short_url);
|
const makeSelectShortUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.short_url);
|
||||||
|
|
||||||
|
const makeSelectCanonicalUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.canonical_url);
|
||||||
|
|
||||||
const makeSelectSupportsForUri = uri => reselect.createSelector(selectSupportsByOutpoint, makeSelectClaimForUri(uri), (byOutpoint, claim) => {
|
const makeSelectSupportsForUri = uri => reselect.createSelector(selectSupportsByOutpoint, makeSelectClaimForUri(uri), (byOutpoint, claim) => {
|
||||||
if (!claim || !claim.is_mine) {
|
if (!claim || !claim.is_mine) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { claim_id: claimId } = claim;
|
const { claim_id: claimId } = claim;
|
||||||
let total = parseFloat("0.0");
|
let total = 0;
|
||||||
|
|
||||||
Object.values(byOutpoint).forEach(support => {
|
Object.values(byOutpoint).forEach(support => {
|
||||||
|
// $FlowFixMe
|
||||||
const { claim_id, amount } = support;
|
const { claim_id, amount } = support;
|
||||||
total = claim_id === claimId && amount ? total + parseFloat(amount) : total;
|
total = claim_id === claimId && amount ? total + parseFloat(amount) : total;
|
||||||
});
|
});
|
||||||
|
@ -2433,10 +2476,10 @@ function doClaimSearch(options = {
|
||||||
|
|
||||||
const success = data => {
|
const success = data => {
|
||||||
const resolveInfo = {};
|
const resolveInfo = {};
|
||||||
const uris = [];
|
const urls = [];
|
||||||
data.items.forEach(stream => {
|
data.items.forEach(stream => {
|
||||||
resolveInfo[stream.permanent_url] = { stream };
|
resolveInfo[stream.canonical_url] = { stream };
|
||||||
uris.push(stream.permanent_url);
|
urls.push(stream.canonical_url);
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -2444,7 +2487,7 @@ function doClaimSearch(options = {
|
||||||
data: {
|
data: {
|
||||||
query,
|
query,
|
||||||
resolveInfo,
|
resolveInfo,
|
||||||
uris,
|
urls,
|
||||||
append: options.page && options.page !== 1,
|
append: options.page && options.page !== 1,
|
||||||
pageSize: options.page_size
|
pageSize: options.page_size
|
||||||
}
|
}
|
||||||
|
@ -2858,12 +2901,12 @@ function doSetFileListSort(page, value) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
function _objectWithoutProperties$2(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
||||||
|
|
||||||
const selectState$5 = state => state.publish || {};
|
const selectState$5 = state => state.publish || {};
|
||||||
|
|
||||||
const selectPublishFormValues = reselect.createSelector(selectState$5, state => {
|
const selectPublishFormValues = reselect.createSelector(selectState$5, state => {
|
||||||
const formValues = _objectWithoutProperties$1(state, ['pendingPublish']);
|
const formValues = _objectWithoutProperties$2(state, ['pendingPublish']);
|
||||||
return formValues;
|
return formValues;
|
||||||
});
|
});
|
||||||
const makeSelectPublishFormValue = item => reselect.createSelector(selectState$5, state => state[item]);
|
const makeSelectPublishFormValue = item => reselect.createSelector(selectState$5, state => state[item]);
|
||||||
|
@ -2876,8 +2919,16 @@ const selectIsStillEditing = reselect.createSelector(selectPublishFormValues, pu
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isChannel: currentIsChannel, claimName: currentClaimName, contentName: currentContentName } = parseURI(uri);
|
const {
|
||||||
const { isChannel: editIsChannel, claimName: editClaimName, contentName: editContentName } = parseURI(editingURI);
|
isChannel: currentIsChannel,
|
||||||
|
claimName: currentClaimName,
|
||||||
|
contentName: currentContentName
|
||||||
|
} = parseURI(uri);
|
||||||
|
const {
|
||||||
|
isChannel: editIsChannel,
|
||||||
|
claimName: editClaimName,
|
||||||
|
contentName: editContentName
|
||||||
|
} = parseURI(editingURI);
|
||||||
|
|
||||||
// Depending on the previous/current use of a channel, we need to compare different things
|
// Depending on the previous/current use of a channel, we need to compare different things
|
||||||
// ex: going from a channel to anonymous, the new uri won't return contentName, so we need to use claimName
|
// ex: going from a channel to anonymous, the new uri won't return contentName, so we need to use claimName
|
||||||
|
@ -2904,7 +2955,7 @@ const selectIsResolvingPublishUris = reselect.createSelector(selectState$5, sele
|
||||||
|
|
||||||
let isResolvingShortUri;
|
let isResolvingShortUri;
|
||||||
if (isChannel) {
|
if (isChannel) {
|
||||||
const shortUri = buildURI({ contentName: name });
|
const shortUri = buildURI({ streamName: name });
|
||||||
isResolvingShortUri = resolvingUris.includes(shortUri);
|
isResolvingShortUri = resolvingUris.includes(shortUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3376,13 +3427,21 @@ from, isBackgroundSearch = false) => (dispatch, getState) => {
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
|
||||||
data.forEach(result => {
|
data.forEach(result => {
|
||||||
if (result.name) {
|
if (result) {
|
||||||
const uri = buildURI({
|
const { name, claimId } = result;
|
||||||
claimName: result.name,
|
const urlObj = {};
|
||||||
claimId: result.claimId
|
|
||||||
});
|
if (name.startsWith('@')) {
|
||||||
actions.push(doResolveUri(uri));
|
urlObj.channelName = name;
|
||||||
uris.push(uri);
|
urlObj.channelClaimId = claimId;
|
||||||
|
} else {
|
||||||
|
urlObj.streamName = name;
|
||||||
|
urlObj.streamClaimId = claimId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = buildURI(urlObj);
|
||||||
|
actions.push(doResolveUri(url));
|
||||||
|
uris.push(url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3561,26 +3620,25 @@ function handleClaimAction(state, action) {
|
||||||
const byId = Object.assign({}, state.byId);
|
const byId = Object.assign({}, state.byId);
|
||||||
const channelClaimCounts = Object.assign({}, state.channelClaimCounts);
|
const channelClaimCounts = Object.assign({}, state.channelClaimCounts);
|
||||||
|
|
||||||
Object.entries(resolveInfo).forEach(([uri, resolveResponse]) => {
|
Object.entries(resolveInfo).forEach(([url, resolveResponse]) => {
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
if (resolveResponse.claimsInChannel) {
|
const { claimsInChannel, stream, channel } = resolveResponse;
|
||||||
// $FlowFixMe
|
if (claimsInChannel) {
|
||||||
channelClaimCounts[uri] = resolveResponse.claimsInChannel;
|
channelClaimCounts[url] = claimsInChannel;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// $FlowFixMe
|
|
||||||
Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => {
|
|
||||||
if (stream) {
|
if (stream) {
|
||||||
byId[stream.claim_id] = stream;
|
byId[stream.claim_id] = stream;
|
||||||
byUri[uri] = stream.claim_id;
|
byUri[url] = stream.claim_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel) {
|
if (channel) {
|
||||||
byId[channel.claim_id] = channel;
|
byId[channel.claim_id] = channel;
|
||||||
byUri[stream ? channel.permanent_url : uri] = channel.claim_id;
|
byUri[stream ? channel.canonical_url : url] = channel.claim_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream && !channel) {
|
if (!stream && !channel) {
|
||||||
byUri[uri] = null;
|
byUri[url] = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3792,17 +3850,17 @@ reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => {
|
||||||
const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
|
const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery);
|
||||||
const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery);
|
const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery);
|
||||||
const claimSearchByQueryLastPageReached = Object.assign({}, state.claimSearchByQueryLastPageReached);
|
const claimSearchByQueryLastPageReached = Object.assign({}, state.claimSearchByQueryLastPageReached);
|
||||||
const { append, query, uris, pageSize } = action.data;
|
const { append, query, urls, pageSize } = action.data;
|
||||||
|
|
||||||
if (append) {
|
if (append) {
|
||||||
// todo: check for duplicate uris when concatenating?
|
// todo: check for duplicate urls when concatenating?
|
||||||
claimSearchByQuery[query] = claimSearchByQuery[query] && claimSearchByQuery[query].length ? claimSearchByQuery[query].concat(uris) : uris;
|
claimSearchByQuery[query] = claimSearchByQuery[query] && claimSearchByQuery[query].length ? claimSearchByQuery[query].concat(urls) : urls;
|
||||||
} else {
|
} else {
|
||||||
claimSearchByQuery[query] = uris;
|
claimSearchByQuery[query] = urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the returned number of uris is less than the page size, so we're on the last page
|
// the returned number of urls is less than the page size, so we're on the last page
|
||||||
claimSearchByQueryLastPageReached[query] = uris.length < pageSize;
|
claimSearchByQueryLastPageReached[query] = urls.length < pageSize;
|
||||||
|
|
||||||
delete fetchingClaimSearchByQuery[query];
|
delete fetchingClaimSearchByQuery[query];
|
||||||
|
|
||||||
|
@ -4232,7 +4290,7 @@ const notificationsReducer = handleActions({
|
||||||
|
|
||||||
var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||||
|
|
||||||
function _objectWithoutProperties$2(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
function _objectWithoutProperties$3(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
||||||
|
|
||||||
const defaultState$6 = {
|
const defaultState$6 = {
|
||||||
editingURI: undefined,
|
editingURI: undefined,
|
||||||
|
@ -4282,7 +4340,7 @@ const publishReducer = handleActions({
|
||||||
publishSuccess: true
|
publishSuccess: true
|
||||||
}),
|
}),
|
||||||
[DO_PREPARE_EDIT]: (state, action) => {
|
[DO_PREPARE_EDIT]: (state, action) => {
|
||||||
const publishData = _objectWithoutProperties$2(action.data, []);
|
const publishData = _objectWithoutProperties$3(action.data, []);
|
||||||
const { channel, name, uri } = publishData;
|
const { channel, name, uri } = publishData;
|
||||||
|
|
||||||
// The short uri is what is presented to the user
|
// The short uri is what is presented to the user
|
||||||
|
@ -4892,6 +4950,7 @@ exports.isNameValid = isNameValid;
|
||||||
exports.isURIClaimable = isURIClaimable;
|
exports.isURIClaimable = isURIClaimable;
|
||||||
exports.isURIValid = isURIValid;
|
exports.isURIValid = isURIValid;
|
||||||
exports.makeSelectAmountForUri = makeSelectAmountForUri;
|
exports.makeSelectAmountForUri = makeSelectAmountForUri;
|
||||||
|
exports.makeSelectCanonicalUrlForUri = makeSelectCanonicalUrlForUri;
|
||||||
exports.makeSelectChannelForClaimUri = makeSelectChannelForClaimUri;
|
exports.makeSelectChannelForClaimUri = makeSelectChannelForClaimUri;
|
||||||
exports.makeSelectClaimForUri = makeSelectClaimForUri;
|
exports.makeSelectClaimForUri = makeSelectClaimForUri;
|
||||||
exports.makeSelectClaimIsMine = makeSelectClaimIsMine;
|
exports.makeSelectClaimIsMine = makeSelectClaimIsMine;
|
||||||
|
|
1
dist/flow-typed/Claim.js
vendored
|
@ -23,6 +23,7 @@ declare type GenericClaim = {
|
||||||
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
||||||
timestamp?: number, // date of last transaction
|
timestamp?: number, // date of last transaction
|
||||||
height: number, // block height the tx was confirmed
|
height: number, // block height the tx was confirmed
|
||||||
|
is_mine: boolean,
|
||||||
name: string,
|
name: string,
|
||||||
normalized_name: string, // `name` normalized via unicode NFD spec,
|
normalized_name: string, // `name` normalized via unicode NFD spec,
|
||||||
nout: number, // index number for an output of a tx
|
nout: number, // index number for an output of a tx
|
||||||
|
|
2
dist/flow-typed/Lbry.js
vendored
|
@ -65,7 +65,7 @@ declare type VersionResponse = {
|
||||||
|
|
||||||
declare type ResolveResponse = {
|
declare type ResolveResponse = {
|
||||||
// Keys are the url(s) passed to resolve
|
// Keys are the url(s) passed to resolve
|
||||||
[string]: Claim | { error?: {} },
|
[string]: { error?: {}, stream?: StreamClaim, channel?: ChannelClaim, claimsInChannel?: number },
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type GetResponse = FileListItem & { error?: string };
|
declare type GetResponse = FileListItem & { error?: string };
|
||||||
|
|
2
dist/flow-typed/i18n.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// @flow
|
||||||
|
declare function __(a: string, b?: string | number): string;
|
1
flow-typed/Claim.js
vendored
|
@ -23,6 +23,7 @@ declare type GenericClaim = {
|
||||||
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
||||||
timestamp?: number, // date of last transaction
|
timestamp?: number, // date of last transaction
|
||||||
height: number, // block height the tx was confirmed
|
height: number, // block height the tx was confirmed
|
||||||
|
is_mine: boolean,
|
||||||
name: string,
|
name: string,
|
||||||
normalized_name: string, // `name` normalized via unicode NFD spec,
|
normalized_name: string, // `name` normalized via unicode NFD spec,
|
||||||
nout: number, // index number for an output of a tx
|
nout: number, // index number for an output of a tx
|
||||||
|
|
2
flow-typed/Lbry.js
vendored
|
@ -65,7 +65,7 @@ declare type VersionResponse = {
|
||||||
|
|
||||||
declare type ResolveResponse = {
|
declare type ResolveResponse = {
|
||||||
// Keys are the url(s) passed to resolve
|
// Keys are the url(s) passed to resolve
|
||||||
[string]: Claim | { error?: {} },
|
[string]: { error?: {}, stream?: StreamClaim, channel?: ChannelClaim, claimsInChannel?: number },
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type GetResponse = FileListItem & { error?: string };
|
declare type GetResponse = FileListItem & { error?: string };
|
||||||
|
|
2
flow-typed/i18n.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// @flow
|
||||||
|
declare function __(a: string, b?: string | number): string;
|
20
flow-typed/lbryURI.js
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// @flow
|
||||||
|
declare type LbryUrlObj = {
|
||||||
|
// Path and channel will always exist when calling parseURI
|
||||||
|
// But they may not exist when code calls buildURI
|
||||||
|
isChannel?: boolean,
|
||||||
|
path?: string,
|
||||||
|
streamName?: string,
|
||||||
|
streamClaimId?: string,
|
||||||
|
channelName?: string,
|
||||||
|
channelClaimId?: string,
|
||||||
|
primaryClaimSequence?: number,
|
||||||
|
secondaryClaimSequence?: number,
|
||||||
|
primaryBidPosition?: number,
|
||||||
|
secondaryBidPosition?: number,
|
||||||
|
|
||||||
|
// Below are considered deprecated and should not be used due to unreliableness with claim.canonical_url
|
||||||
|
claimName?: string,
|
||||||
|
claimId?: string,
|
||||||
|
contentName?: string,
|
||||||
|
};
|
|
@ -21,7 +21,7 @@
|
||||||
"main": "dist/bundle.es.js",
|
"main": "dist/bundle.es.js",
|
||||||
"module": "dist/bundle.es.js",
|
"module": "dist/bundle.es.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup --config",
|
"build": "NODE_ENV=production rollup --config",
|
||||||
"dev": "rollup --config --watch",
|
"dev": "rollup --config --watch",
|
||||||
"precommit": "flow check && lint-staged",
|
"precommit": "flow check && lint-staged",
|
||||||
"lint": "eslint 'src/**/*.js' --fix",
|
"lint": "eslint 'src/**/*.js' --fix",
|
||||||
|
@ -59,7 +59,8 @@
|
||||||
"rollup-plugin-copy": "^1.1.0",
|
"rollup-plugin-copy": "^1.1.0",
|
||||||
"rollup-plugin-eslint": "^5.1.0",
|
"rollup-plugin-eslint": "^5.1.0",
|
||||||
"rollup-plugin-flow": "^1.1.1",
|
"rollup-plugin-flow": "^1.1.1",
|
||||||
"rollup-plugin-includepaths": "^0.2.3"
|
"rollup-plugin-includepaths": "^0.2.3",
|
||||||
|
"rollup-plugin-replace": "^2.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"yarn": "^1.3"
|
"yarn": "^1.3"
|
||||||
|
|
|
@ -2,6 +2,7 @@ import babel from 'rollup-plugin-babel';
|
||||||
import flow from 'rollup-plugin-flow';
|
import flow from 'rollup-plugin-flow';
|
||||||
import includePaths from 'rollup-plugin-includepaths';
|
import includePaths from 'rollup-plugin-includepaths';
|
||||||
import copy from 'rollup-plugin-copy';
|
import copy from 'rollup-plugin-copy';
|
||||||
|
import replace from 'rollup-plugin-replace';
|
||||||
|
|
||||||
let includePathOptions = {
|
let includePathOptions = {
|
||||||
include: {},
|
include: {},
|
||||||
|
@ -10,6 +11,8 @@ let includePathOptions = {
|
||||||
extensions: ['.js'],
|
extensions: ['.js'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const production = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
input: 'src/index.js',
|
input: 'src/index.js',
|
||||||
output: {
|
output: {
|
||||||
|
@ -24,5 +27,10 @@ export default {
|
||||||
presets: ['stage-2'],
|
presets: ['stage-2'],
|
||||||
}),
|
}),
|
||||||
copy({ targets: ['flow-typed'] }),
|
copy({ targets: ['flow-typed'] }),
|
||||||
|
replace({
|
||||||
|
'process.env.NODE_ENV': production
|
||||||
|
? JSON.stringify('production')
|
||||||
|
: JSON.stringify('development'),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -172,6 +172,7 @@ export {
|
||||||
makeSelectPendingByUri,
|
makeSelectPendingByUri,
|
||||||
makeSelectClaimsInChannelForCurrentPageState,
|
makeSelectClaimsInChannelForCurrentPageState,
|
||||||
makeSelectShortUrlForUri,
|
makeSelectShortUrlForUri,
|
||||||
|
makeSelectCanonicalUrlForUri,
|
||||||
makeSelectSupportsForUri,
|
makeSelectSupportsForUri,
|
||||||
selectPendingById,
|
selectPendingById,
|
||||||
selectClaimsById,
|
selectClaimsById,
|
||||||
|
|
310
src/lbryURI.js
|
@ -1,46 +1,55 @@
|
||||||
|
// @flow
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
const channelNameMinLength = 1;
|
const channelNameMinLength = 1;
|
||||||
const claimIdMaxLength = 40;
|
const claimIdMaxLength = 40;
|
||||||
|
|
||||||
// see https://spec.lbry.com/#urls
|
// see https://spec.lbry.com/#urls
|
||||||
export const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
|
export const regexInvalidURI = /[ =&#:$@%?;/\\"<>%{}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u;
|
||||||
export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
|
export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
|
||||||
|
const regexPartProtocol = '^((?:lbry://)?)';
|
||||||
|
const regexPartStreamOrChannelName = '([^:$#/]*)';
|
||||||
|
const regexPartModifierSeparator = '([:$#]?)([^/]*)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a LBRY name into its component parts. Throws errors with user-friendly
|
* Parses a LBRY name into its component parts. Throws errors with user-friendly
|
||||||
* messages for invalid names.
|
* messages for invalid names.
|
||||||
*
|
*
|
||||||
* N.B. that "name" indicates the value in the name position of the URI. For
|
|
||||||
* claims for channel content, this will actually be the channel name, and
|
|
||||||
* the content name is in the path (e.g. lbry://@channel/content)
|
|
||||||
*
|
|
||||||
* In most situations, you'll want to use the contentName and channelName keys
|
|
||||||
* and ignore the name key.
|
|
||||||
*
|
|
||||||
* Returns a dictionary with keys:
|
* Returns a dictionary with keys:
|
||||||
* - name (string): The value in the "name" position in the URI. Note that this
|
* - path (string)
|
||||||
* could be either content name or channel name; see above.
|
|
||||||
* - path (string, if persent)
|
|
||||||
* - claimSequence (int, if present)
|
|
||||||
* - bidPosition (int, if present)
|
|
||||||
* - claimId (string, if present)
|
|
||||||
* - isChannel (boolean)
|
* - isChannel (boolean)
|
||||||
* - contentName (string): For anon claims, the name; for channel claims, the path
|
* - streamName (string, if present)
|
||||||
* - channelName (string, if present): Channel name without @
|
* - streamClaimId (string, if present)
|
||||||
|
* - channelName (string, if present)
|
||||||
|
* - channelClaimId (string, if present)
|
||||||
|
* - primaryClaimSequence (int, if present)
|
||||||
|
* - secondaryClaimSequence (int, if present)
|
||||||
|
* - primaryBidPosition (int, if present)
|
||||||
|
* - secondaryBidPosition (int, if present)
|
||||||
*/
|
*/
|
||||||
export function parseURI(URI, requireProto = false) {
|
|
||||||
|
export function parseURI(URL: string, requireProto: boolean = false): LbryUrlObj {
|
||||||
// Break into components. Empty sub-matches are converted to null
|
// Break into components. Empty sub-matches are converted to null
|
||||||
const componentsRegex = new RegExp(
|
const componentsRegex = new RegExp(
|
||||||
'^((?:lbry://)?)' + // protocol
|
regexPartProtocol + // protocol
|
||||||
'([^:$#/]*)' + // claim name (stops at the first separator or end)
|
regexPartStreamOrChannelName + // stream or channel name (stops at the first separator or end)
|
||||||
'([:$#]?)([^/]*)' + // modifier separator, modifier (stops at the first path separator or end)
|
regexPartModifierSeparator + // modifier separator, modifier (stops at the first path separator or end)
|
||||||
'(/?)(.*)' // path separator, path
|
'(/?)' + // path separator, there should only be one (optional) slash to separate the stream and channel parts
|
||||||
|
regexPartStreamOrChannelName +
|
||||||
|
regexPartModifierSeparator
|
||||||
);
|
);
|
||||||
const [proto, claimName, modSep, modVal, pathSep, path] = componentsRegex
|
|
||||||
.exec(URI)
|
|
||||||
.slice(1)
|
|
||||||
.map(match => match || null);
|
|
||||||
|
|
||||||
let contentName;
|
const regexMatch = componentsRegex.exec(URL) || [];
|
||||||
|
const [proto, ...rest] = regexMatch.slice(1).map(match => match || null);
|
||||||
|
const path = rest.join('');
|
||||||
|
const [
|
||||||
|
streamNameOrChannelName,
|
||||||
|
primaryModSeparator,
|
||||||
|
primaryModValue,
|
||||||
|
pathSep,
|
||||||
|
possibleStreamName,
|
||||||
|
secondaryModSeparator,
|
||||||
|
secondaryModValue,
|
||||||
|
] = rest;
|
||||||
|
|
||||||
// Validate protocol
|
// Validate protocol
|
||||||
if (requireProto && !proto) {
|
if (requireProto && !proto) {
|
||||||
|
@ -48,14 +57,15 @@ export function parseURI(URI, requireProto = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and process name
|
// Validate and process name
|
||||||
if (!claimName) {
|
if (!streamNameOrChannelName) {
|
||||||
throw new Error(__('URI does not include name.'));
|
throw new Error(__('URI does not include name.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const isChannel = claimName.startsWith('@');
|
const includesChannel = streamNameOrChannelName.startsWith('@');
|
||||||
I like removing validation from this. We already have I like removing validation from this. We already have `isURIValid` to validate
|
|||||||
const channelName = isChannel ? claimName.slice(1) : claimName;
|
const isChannel = streamNameOrChannelName.startsWith('@') && !possibleStreamName;
|
||||||
|
const channelName = includesChannel && streamNameOrChannelName.slice(1);
|
||||||
|
|
||||||
if (isChannel) {
|
if (includesChannel) {
|
||||||
if (!channelName) {
|
if (!channelName) {
|
||||||
Not sure the best way to do this. Should Not sure the best way to do this.
Should `path` include the claimId? Should there be `path` and `pathClaimId`?
According to https://lbry.tech/spec#urls, the Channel name, claim name, and any modifiers would be sub-properties of the path (and could potentially be returned/parsed out by this function as well). @lyoshenka, please correct me if I'm wrong about this. @seanyesmunt we should try to have this function use the same names and standards that the spec specifies. If you think we should do something different than what the spec says, we can also consider amending the spec. According to https://lbry.tech/spec#urls, the `path` should include the channel name, claim name, and any modifiers. The path is everything between the scheme and any query parameters.
Channel name, claim name, and any modifiers would be sub-properties of the path (and could potentially be returned/parsed out by this function as well).
@lyoshenka, please correct me if I'm wrong about this.
@seanyesmunt we should try to have this function use the same names and standards that the spec specifies. If you think we should do something different than what the spec says, we can also consider amending the spec.
|
|||||||
throw new Error(__('No channel name after @.'));
|
throw new Error(__('No channel name after @.'));
|
||||||
}
|
}
|
||||||
|
@ -63,36 +73,58 @@ export function parseURI(URI, requireProto = false) {
|
||||||
if (channelName.length < channelNameMinLength) {
|
if (channelName.length < channelNameMinLength) {
|
||||||
throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength));
|
throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
contentName = path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameBadChars = (channelName || claimName).match(regexInvalidURI);
|
// Validate and process modifier
|
||||||
if (nameBadChars) {
|
const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier(
|
||||||
throw new Error(
|
primaryModSeparator,
|
||||||
__(
|
primaryModValue
|
||||||
`Invalid character %s in name: %s.`,
|
|
||||||
nameBadChars.length === 1 ? '' : 's',
|
|
||||||
nameBadChars.join(', ')
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier(
|
||||||
|
secondaryModSeparator,
|
||||||
|
secondaryModValue
|
||||||
|
);
|
||||||
|
const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName;
|
||||||
|
const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId;
|
||||||
|
const channelClaimId = includesChannel && primaryClaimId;
|
||||||
|
|
||||||
// Validate and process modifier (claim ID, bid position or claim sequence)
|
return {
|
||||||
|
isChannel,
|
||||||
|
path,
|
||||||
|
...(streamName ? { streamName } : {}),
|
||||||
|
...(streamClaimId ? { streamClaimId } : {}),
|
||||||
|
...(channelName ? { channelName } : {}),
|
||||||
|
...(channelClaimId ? { channelClaimId } : {}),
|
||||||
|
...(primaryClaimSequence ? { primaryClaimSequence: parseInt(primaryClaimSequence, 10) } : {}),
|
||||||
|
...(secondaryClaimSequence
|
||||||
|
? { secondaryClaimSequence: parseInt(secondaryClaimSequence, 10) }
|
||||||
|
: {}),
|
||||||
|
...(primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}),
|
||||||
|
...(secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}),
|
||||||
|
|
||||||
|
// The values below should not be used for new uses of parseURI
|
||||||
|
// They will not work properly with canonical_urls
|
||||||
|
claimName: streamNameOrChannelName,
|
||||||
|
claimId: primaryClaimId,
|
||||||
|
...(streamName ? { contentName: streamName } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseURIModifier(modSeperator: ?string, modValue: ?string) {
|
||||||
let claimId;
|
let claimId;
|
||||||
let claimSequence;
|
let claimSequence;
|
||||||
let bidPosition;
|
let bidPosition;
|
||||||
if (modSep) {
|
if (modSeperator) {
|
||||||
if (!modVal) {
|
if (!modValue) {
|
||||||
throw new Error(__(`No modifier provided after separator %s.`, modSep));
|
throw new Error(__(`No modifier provided after separator %s.`, modSeperator));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modSep === '#') {
|
if (modSeperator === '#') {
|
||||||
claimId = modVal;
|
claimId = modValue;
|
||||||
} else if (modSep === ':') {
|
} else if (modSeperator === ':') {
|
||||||
claimSequence = modVal;
|
claimSequence = modValue;
|
||||||
} else if (modSep === '$') {
|
} else if (modSeperator === '$') {
|
||||||
bidPosition = modVal;
|
bidPosition = modValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,33 +140,7 @@ export function parseURI(URI, requireProto = false) {
|
||||||
throw new Error(__('Bid position must be a number.'));
|
throw new Error(__('Bid position must be a number.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and process path
|
return [claimId, claimSequence, bidPosition];
|
||||||
if (path) {
|
|
||||||
if (!isChannel) {
|
|
||||||
throw new Error(__('Only channel URIs may have a path.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathBadChars = path.match(regexInvalidURI);
|
|
||||||
if (pathBadChars) {
|
|
||||||
throw new Error(__(`Invalid character in path: %s`, pathBadChars.join(', ')));
|
|
||||||
}
|
|
||||||
|
|
||||||
contentName = path;
|
|
||||||
} else if (pathSep) {
|
|
||||||
throw new Error(__('No path provided after /'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
claimName,
|
|
||||||
path,
|
|
||||||
isChannel,
|
|
||||||
...(contentName ? { contentName } : {}),
|
|
||||||
...(channelName ? { channelName } : {}),
|
|
||||||
...(claimSequence ? { claimSequence: parseInt(claimSequence, 10) } : {}),
|
|
||||||
...(bidPosition ? { bidPosition: parseInt(bidPosition, 10) } : {}),
|
|
||||||
...(claimId ? { claimId } : {}),
|
|
||||||
...(path ? { path } : {}),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,91 +148,145 @@ export function parseURI(URI, requireProto = false) {
|
||||||
*
|
*
|
||||||
* The channelName key will accept names with or without the @ prefix.
|
* The channelName key will accept names with or without the @ prefix.
|
||||||
*/
|
*/
|
||||||
export function buildURI(URIObj, includeProto = true, protoDefault = 'lbry://') {
|
export function buildURI(
|
||||||
const { claimId, claimSequence, bidPosition, contentName, channelName } = URIObj;
|
UrlObj: LbryUrlObj,
|
||||||
|
includeProto: boolean = true,
|
||||||
|
protoDefault: string = 'lbry://'
|
||||||
|
): string {
|
||||||
|
const {
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryClaimSequence,
|
||||||
|
primaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
...deprecatedParts
|
||||||
|
} = UrlObj;
|
||||||
|
const { claimId, claimName, contentName } = deprecatedParts;
|
||||||
|
|
||||||
let { claimName, path } = URIObj;
|
if (!isProduction) {
|
||||||
|
if (claimId) {
|
||||||
if (channelName) {
|
console.error(
|
||||||
const channelNameFormatted = channelName.startsWith('@') ? channelName : `@${channelName}`;
|
__("'claimId' should no longer be used. Use 'streamClaimId' or 'channelClaimId' instead")
|
||||||
if (!claimName) {
|
);
|
||||||
claimName = channelNameFormatted;
|
}
|
||||||
} else if (claimName !== channelNameFormatted) {
|
if (claimName) {
|
||||||
throw new Error(
|
console.error(
|
||||||
__(
|
__(
|
||||||
'Received a channel content URI, but claim name and channelName do not match. "name" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.'
|
"'claimName' should no longer be used. Use 'streamClaimName' or 'channelClaimName' instead"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (contentName) {
|
if (contentName) {
|
||||||
if (!claimName) {
|
console.error(__("'contentName' should no longer be used. Use 'streamName' instead"));
|
||||||
claimName = contentName;
|
|
||||||
} else if (!path) {
|
|
||||||
path = contentName;
|
|
||||||
}
|
}
|
||||||
if (path && path !== contentName) {
|
}
|
||||||
|
|
||||||
|
if (!claimName && !channelName && !streamName) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
__(
|
__(
|
||||||
'Path and contentName do not match. Only one is required; most likely you wanted contentName.'
|
"'claimName', 'channelName', and 'streamName' are all empty. One must be present to build a url."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const formattedChannelName =
|
||||||
|
channelName && (channelName.startsWith('@') ? channelName : `@${channelName}`);
|
||||||
|
const primaryClaimName = claimName || contentName || formattedChannelName || streamName;
|
||||||
|
const primaryClaimId = claimId || (formattedChannelName ? channelClaimId : streamClaimId);
|
||||||
|
const secondaryClaimName =
|
||||||
|
(!claimName && contentName) || (formattedChannelName ? streamName : null);
|
||||||
|
const secondaryClaimId = secondaryClaimName && streamClaimId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(includeProto ? protoDefault : '') +
|
(includeProto ? protoDefault : '') +
|
||||||
claimName +
|
// primaryClaimName will always exist here because we throw above if there is no "name" value passed in
|
||||||
(claimId ? `#${claimId}` : '') +
|
// $FlowFixMe
|
||||||
(claimSequence ? `:${claimSequence}` : '') +
|
primaryClaimName +
|
||||||
(bidPosition ? `${bidPosition}` : '') +
|
(primaryClaimId ? `#${primaryClaimId}` : '') +
|
||||||
(path ? `/${path}` : '')
|
(primaryClaimSequence ? `:${primaryClaimSequence}` : '') +
|
||||||
|
(primaryBidPosition ? `${primaryBidPosition}` : '') +
|
||||||
|
(secondaryClaimName ? `/${secondaryClaimName}` : '') +
|
||||||
|
(secondaryClaimId ? `#${secondaryClaimId}` : '') +
|
||||||
|
(secondaryClaimSequence ? `:${secondaryClaimSequence}` : '') +
|
||||||
|
(secondaryBidPosition ? `${secondaryBidPosition}` : '')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes a parseable LBRY URI and converts it to standard, canonical format */
|
/* Takes a parseable LBRY URL and converts it to standard, canonical format */
|
||||||
export function normalizeURI(URI) {
|
export function normalizeURI(URL: string) {
|
||||||
const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI);
|
const {
|
||||||
return buildURI({ claimName, path, claimSequence, bidPosition, claimId });
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryClaimSequence,
|
||||||
|
primaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
} = parseURI(URL);
|
||||||
|
|
||||||
|
return buildURI({
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryClaimSequence,
|
||||||
|
primaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isURIValid(URI) {
|
export function isURIValid(URL: string): boolean {
|
||||||
let parts;
|
|
||||||
try {
|
try {
|
||||||
parts = parseURI(normalizeURI(URI));
|
parseURI(normalizeURI(URL));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return parts && parts.claimName;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNameValid(claimName) {
|
export function isNameValid(claimName: string) {
|
||||||
return !regexInvalidURI.test(claimName);
|
return !regexInvalidURI.test(claimName);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isURIClaimable(URI) {
|
export function isURIClaimable(URL: string) {
|
||||||
let parts;
|
let parts;
|
||||||
try {
|
try {
|
||||||
parts = parseURI(normalizeURI(URI));
|
parts = parseURI(normalizeURI(URL));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
parts &&
|
return parts && parts.streamName && !parts.streamClaimId && !parts.isChannel;
|
||||||
parts.claimName &&
|
|
||||||
!parts.claimId &&
|
|
||||||
!parts.bidPosition &&
|
|
||||||
!parts.claimSequence &&
|
|
||||||
!parts.isChannel &&
|
|
||||||
!parts.path
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertToShareLink(URI) {
|
export function convertToShareLink(URL: string) {
|
||||||
const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI);
|
const {
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryBidPosition,
|
||||||
|
primaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
} = parseURI(URL);
|
||||||
return buildURI(
|
return buildURI(
|
||||||
{ claimName, path, claimSequence, bidPosition, claimId },
|
{
|
||||||
|
streamName,
|
||||||
|
streamClaimId,
|
||||||
|
channelName,
|
||||||
|
channelClaimId,
|
||||||
|
primaryBidPosition,
|
||||||
|
primaryClaimSequence,
|
||||||
|
secondaryBidPosition,
|
||||||
|
secondaryClaimSequence,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
'https://open.lbry.com/'
|
'https://open.lbry.com/'
|
||||||
);
|
);
|
||||||
|
|
|
@ -328,10 +328,10 @@ export function doClaimSearch(
|
||||||
|
|
||||||
why keep two sets of URIs? why keep two sets of URIs?
|
|||||||
const success = (data: ClaimSearchResponse) => {
|
const success = (data: ClaimSearchResponse) => {
|
||||||
const resolveInfo = {};
|
const resolveInfo = {};
|
||||||
const uris = [];
|
const urls = [];
|
||||||
data.items.forEach((stream: Claim) => {
|
data.items.forEach((stream: Claim) => {
|
||||||
resolveInfo[stream.permanent_url] = { stream };
|
resolveInfo[stream.canonical_url] = { stream };
|
||||||
uris.push(stream.permanent_url);
|
urls.push(stream.canonical_url);
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -339,7 +339,7 @@ export function doClaimSearch(
|
||||||
data: {
|
data: {
|
||||||
query,
|
query,
|
||||||
resolveInfo,
|
resolveInfo,
|
||||||
uris,
|
urls,
|
||||||
append: options.page && options.page !== 1,
|
append: options.page && options.page !== 1,
|
||||||
pageSize: options.page_size,
|
pageSize: options.page_size,
|
||||||
},
|
},
|
||||||
|
|
|
@ -112,18 +112,26 @@ export const doSearch = (
|
||||||
|
|
||||||
fetch(`${CONNECTION_STRING}search?${queryWithOptions}`)
|
fetch(`${CONNECTION_STRING}search?${queryWithOptions}`)
|
||||||
.then(handleFetchResponse)
|
.then(handleFetchResponse)
|
||||||
.then((data: Array<{ name: String, claimId: string }>) => {
|
.then((data: Array<{ name: string, claimId: string }>) => {
|
||||||
const uris = [];
|
const uris = [];
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
|
||||||
data.forEach(result => {
|
data.forEach(result => {
|
||||||
if (result.name) {
|
if (result) {
|
||||||
const uri = buildURI({
|
const { name, claimId } = result;
|
||||||
claimName: result.name,
|
const urlObj: LbryUrlObj = {};
|
||||||
claimId: result.claimId,
|
|
||||||
});
|
if (name.startsWith('@')) {
|
||||||
actions.push(doResolveUri(uri));
|
urlObj.channelName = name;
|
||||||
uris.push(uri);
|
urlObj.channelClaimId = claimId;
|
||||||
|
} else {
|
||||||
|
urlObj.streamName = name;
|
||||||
|
urlObj.streamClaimId = claimId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = buildURI(urlObj);
|
||||||
|
actions.push(doResolveUri(url));
|
||||||
|
uris.push(url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -66,26 +66,25 @@ function handleClaimAction(state: State, action: any): State {
|
||||||
const byId = Object.assign({}, state.byId);
|
const byId = Object.assign({}, state.byId);
|
||||||
const channelClaimCounts = Object.assign({}, state.channelClaimCounts);
|
const channelClaimCounts = Object.assign({}, state.channelClaimCounts);
|
||||||
URI or URL? are we consistent with when we use one vs. the other? URI or URL? are we consistent with when we use one vs. the other?
|
|||||||
|
|
||||||
Object.entries(resolveInfo).forEach(([uri: string, resolveResponse: Claim]) => {
|
Object.entries(resolveInfo).forEach(([url: string, resolveResponse: ResolveResponse]) => {
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
if (resolveResponse.claimsInChannel) {
|
const { claimsInChannel, stream, channel } = resolveResponse;
|
||||||
// $FlowFixMe
|
if (claimsInChannel) {
|
||||||
channelClaimCounts[uri] = resolveResponse.claimsInChannel;
|
channelClaimCounts[url] = claimsInChannel;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// $FlowFixMe
|
|
||||||
Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => {
|
|
||||||
if (stream) {
|
if (stream) {
|
||||||
byId[stream.claim_id] = stream;
|
byId[stream.claim_id] = stream;
|
||||||
byUri[uri] = stream.claim_id;
|
byUri[url] = stream.claim_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel) {
|
if (channel) {
|
||||||
byId[channel.claim_id] = channel;
|
byId[channel.claim_id] = channel;
|
||||||
byUri[stream ? channel.permanent_url : uri] = channel.claim_id;
|
byUri[stream ? channel.canonical_url : url] = channel.claim_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream && !channel) {
|
if (!stream && !channel) {
|
||||||
byUri[uri] = null;
|
byUri[url] = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -305,20 +304,20 @@ reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State =>
|
||||||
{},
|
{},
|
||||||
state.claimSearchByQueryLastPageReached
|
state.claimSearchByQueryLastPageReached
|
||||||
);
|
);
|
||||||
const { append, query, uris, pageSize } = action.data;
|
const { append, query, urls, pageSize } = action.data;
|
||||||
|
|
||||||
if (append) {
|
if (append) {
|
||||||
// todo: check for duplicate uris when concatenating?
|
// todo: check for duplicate urls when concatenating?
|
||||||
claimSearchByQuery[query] =
|
claimSearchByQuery[query] =
|
||||||
claimSearchByQuery[query] && claimSearchByQuery[query].length
|
claimSearchByQuery[query] && claimSearchByQuery[query].length
|
||||||
? claimSearchByQuery[query].concat(uris)
|
? claimSearchByQuery[query].concat(urls)
|
||||||
: uris;
|
: urls;
|
||||||
} else {
|
} else {
|
||||||
claimSearchByQuery[query] = uris;
|
claimSearchByQuery[query] = urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the returned number of uris is less than the page size, so we're on the last page
|
// the returned number of urls is less than the page size, so we're on the last page
|
||||||
claimSearchByQueryLastPageReached[query] = uris.length < pageSize;
|
claimSearchByQueryLastPageReached[query] = urls.length < pageSize;
|
||||||
|
|
||||||
delete fetchingClaimSearchByQuery[query];
|
delete fetchingClaimSearchByQuery[query];
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,10 @@ export const makeSelectClaimIsPending = (uri: string) =>
|
||||||
selectPendingById,
|
selectPendingById,
|
||||||
pendingById => {
|
pendingById => {
|
||||||
let claimId;
|
let claimId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
({ claimId } = parseURI(uri));
|
const { isChannel, channelClaimId, streamClaimId } = parseURI(uri);
|
||||||
|
claimId = isChannel ? channelClaimId : streamClaimId;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (claimId) {
|
if (claimId) {
|
||||||
|
@ -76,7 +78,8 @@ export const makeSelectPendingByUri = (uri: string) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
selectPendingById,
|
selectPendingById,
|
||||||
pendingById => {
|
pendingById => {
|
||||||
const { claimId } = parseURI(uri);
|
const { isChannel, channelClaimId, streamClaimId } = parseURI(uri);
|
||||||
|
const claimId = isChannel ? channelClaimId : streamClaimId;
|
||||||
return pendingById[claimId];
|
return pendingById[claimId];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -90,13 +93,16 @@ export const makeSelectClaimForUri = (uri: string) =>
|
||||||
// It won't be in claimsByUri because resolving it will return nothing
|
// It won't be in claimsByUri because resolving it will return nothing
|
||||||
|
|
||||||
let valid;
|
let valid;
|
||||||
let claimId;
|
let channelClaimId;
|
||||||
|
let streamClaimId;
|
||||||
|
let isChannel;
|
||||||
try {
|
try {
|
||||||
({ claimId } = parseURI(uri));
|
({ isChannel, channelClaimId, streamClaimId } = parseURI(uri));
|
||||||
valid = true;
|
valid = true;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
const claimId = isChannel ? channelClaimId : streamClaimId;
|
||||||
const pendingClaim = pendingById[claimId];
|
const pendingClaim = pendingById[claimId];
|
||||||
|
|
||||||
if (pendingClaim) {
|
if (pendingClaim) {
|
||||||
|
@ -521,23 +527,18 @@ export const selectClaimSearchByQueryLastPageReached = createSelector(
|
||||||
state => state.claimSearchByQueryLastPageReached || {}
|
state => state.claimSearchByQueryLastPageReached || {}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const makeSelectClaimSearchUrisByOptions = (options: {}) =>
|
|
||||||
createSelector(
|
|
||||||
selectClaimSearchByQuery,
|
|
||||||
byQuery => {
|
|
||||||
// We don't care what options are passed to this selector. Just forward them.
|
|
||||||
// $FlowFixMe
|
|
||||||
const query = createNormalizedClaimSearchKey(options);
|
|
||||||
return byQuery[query];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeSelectShortUrlForUri = (uri: string) =>
|
export const makeSelectShortUrlForUri = (uri: string) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
makeSelectClaimForUri(uri),
|
makeSelectClaimForUri(uri),
|
||||||
claim => claim && claim.short_url
|
claim => claim && claim.short_url
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const makeSelectCanonicalUrlForUri = (uri: string) =>
|
||||||
|
createSelector(
|
||||||
|
makeSelectClaimForUri(uri),
|
||||||
|
claim => claim && claim.canonical_url
|
||||||
|
);
|
||||||
|
|
||||||
export const makeSelectSupportsForUri = (uri: string) =>
|
export const makeSelectSupportsForUri = (uri: string) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
selectSupportsByOutpoint,
|
selectSupportsByOutpoint,
|
||||||
|
@ -548,11 +549,12 @@ export const makeSelectSupportsForUri = (uri: string) =>
|
||||||
}
|
}
|
||||||
|
|
||||||
const { claim_id: claimId } = claim;
|
const { claim_id: claimId } = claim;
|
||||||
let total = parseFloat("0.0");
|
let total = 0;
|
||||||
|
|
||||||
Object.values(byOutpoint).forEach(support => {
|
Object.values(byOutpoint).forEach(support => {
|
||||||
const { claim_id, amount } = support
|
// $FlowFixMe
|
||||||
total = (claim_id === claimId && amount) ? total + parseFloat(amount) : total;
|
const { claim_id, amount } = support;
|
||||||
|
total = claim_id === claimId && amount ? total + parseFloat(amount) : total;
|
||||||
});
|
});
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
|
|
|
@ -33,8 +33,16 @@ export const selectIsStillEditing = createSelector(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isChannel: currentIsChannel, claimName: currentClaimName, contentName: currentContentName } = parseURI(uri);
|
const {
|
||||||
const { isChannel: editIsChannel, claimName: editClaimName, contentName: editContentName } = parseURI(editingURI);
|
isChannel: currentIsChannel,
|
||||||
|
claimName: currentClaimName,
|
||||||
|
contentName: currentContentName,
|
||||||
|
} = parseURI(uri);
|
||||||
|
const {
|
||||||
|
isChannel: editIsChannel,
|
||||||
|
claimName: editClaimName,
|
||||||
|
contentName: editContentName,
|
||||||
|
} = parseURI(editingURI);
|
||||||
|
|
||||||
// Depending on the previous/current use of a channel, we need to compare different things
|
// Depending on the previous/current use of a channel, we need to compare different things
|
||||||
// ex: going from a channel to anonymous, the new uri won't return contentName, so we need to use claimName
|
// ex: going from a channel to anonymous, the new uri won't return contentName, so we need to use claimName
|
||||||
|
@ -60,7 +68,9 @@ export const selectMyClaimForUri = createSelector(
|
||||||
return isStillEditing
|
return isStillEditing
|
||||||
? claimsById[editClaimId]
|
? claimsById[editClaimId]
|
||||||
: myClaims.find(claim =>
|
: myClaims.find(claim =>
|
||||||
!contentName ? claim.name === claimName : claim.name === contentName || claim.name === claimName
|
!contentName
|
||||||
|
? claim.name === claimName
|
||||||
|
: claim.name === contentName || claim.name === claimName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -75,7 +85,7 @@ export const selectIsResolvingPublishUris = createSelector(
|
||||||
|
|
||||||
let isResolvingShortUri;
|
let isResolvingShortUri;
|
||||||
if (isChannel) {
|
if (isChannel) {
|
||||||
const shortUri = buildURI({ contentName: name });
|
const shortUri = buildURI({ streamName: name });
|
||||||
isResolvingShortUri = resolvingUris.includes(shortUri);
|
isResolvingShortUri = resolvingUris.includes(shortUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,15 +77,15 @@ export const selectSearchSuggestions: Array<SearchSuggestion> = createSelector(
|
||||||
let searchSuggestions = [];
|
let searchSuggestions = [];
|
||||||
try {
|
try {
|
||||||
const uri = normalizeURI(query);
|
const uri = normalizeURI(query);
|
||||||
const { claimName, isChannel } = parseURI(uri);
|
const { channelName, streamName, isChannel } = parseURI(uri);
|
||||||
searchSuggestions.push(
|
searchSuggestions.push(
|
||||||
{
|
{
|
||||||
value: claimName,
|
value: streamName,
|
||||||
type: SEARCH_TYPES.SEARCH,
|
type: SEARCH_TYPES.SEARCH,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: uri,
|
value: uri,
|
||||||
shorthand: isChannel ? claimName.slice(1) : claimName,
|
shorthand: isChannel ? channelName : streamName,
|
||||||
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE,
|
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -110,11 +110,11 @@ export const selectSearchSuggestions: Array<SearchSuggestion> = createSelector(
|
||||||
// determine if it's a channel
|
// determine if it's a channel
|
||||||
try {
|
try {
|
||||||
const uri = normalizeURI(suggestion);
|
const uri = normalizeURI(suggestion);
|
||||||
const { claimName, isChannel } = parseURI(uri);
|
const { channelName, streamName, isChannel } = parseURI(uri);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value: uri,
|
value: uri,
|
||||||
shorthand: isChannel ? claimName.slice(1) : claimName,
|
shorthand: isChannel ? channelName : streamName,
|
||||||
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE,
|
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { parseURI } from 'lbryURI';
|
|
||||||
|
|
||||||
export const formatLbryUriForWeb = (uri: string) => {
|
|
||||||
const { claimName, claimId } = parseURI(uri);
|
|
||||||
|
|
||||||
let webUrl = `/${claimName}`;
|
|
||||||
if (claimId) {
|
|
||||||
webUrl += `/${claimId}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return webUrl;
|
|
||||||
};
|
|
32
yarn.lock
|
@ -1911,6 +1911,11 @@ estree-walker@^0.6.0:
|
||||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.0.tgz#5d865327c44a618dde5699f763891ae31f257dae"
|
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.0.tgz#5d865327c44a618dde5699f763891ae31f257dae"
|
||||||
integrity sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw==
|
integrity sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw==
|
||||||
|
|
||||||
|
estree-walker@^0.6.1:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
|
||||||
|
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
|
||||||
|
|
||||||
esutils@^2.0.2:
|
esutils@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||||
|
@ -3440,6 +3445,13 @@ lru-cache@^4.0.1:
|
||||||
pseudomap "^1.0.2"
|
pseudomap "^1.0.2"
|
||||||
yallist "^2.1.2"
|
yallist "^2.1.2"
|
||||||
|
|
||||||
|
magic-string@^0.25.2:
|
||||||
|
version "0.25.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.3.tgz#34b8d2a2c7fec9d9bdf9929a3fd81d271ef35be9"
|
||||||
|
integrity sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==
|
||||||
|
dependencies:
|
||||||
|
sourcemap-codec "^1.4.4"
|
||||||
|
|
||||||
make-dir@^1.0.0:
|
make-dir@^1.0.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
|
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
|
||||||
|
@ -4379,6 +4391,14 @@ rollup-plugin-includepaths@^0.2.3:
|
||||||
resolved "https://registry.yarnpkg.com/rollup-plugin-includepaths/-/rollup-plugin-includepaths-0.2.3.tgz#244d21b9669a0debe476d825e4a02ed08c06b258"
|
resolved "https://registry.yarnpkg.com/rollup-plugin-includepaths/-/rollup-plugin-includepaths-0.2.3.tgz#244d21b9669a0debe476d825e4a02ed08c06b258"
|
||||||
integrity sha512-4QbSIZPDT+FL4SViEVCRi4cGCA64zQJu7u5qmCkO3ecHy+l9EQBsue15KfCpddfb6Br0q47V/v2+E2YUiqts9g==
|
integrity sha512-4QbSIZPDT+FL4SViEVCRi4cGCA64zQJu7u5qmCkO3ecHy+l9EQBsue15KfCpddfb6Br0q47V/v2+E2YUiqts9g==
|
||||||
|
|
||||||
|
rollup-plugin-replace@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz#f41ae5372e11e7a217cde349c8b5d5fd115e70e3"
|
||||||
|
integrity sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==
|
||||||
|
dependencies:
|
||||||
|
magic-string "^0.25.2"
|
||||||
|
rollup-pluginutils "^2.6.0"
|
||||||
|
|
||||||
rollup-pluginutils@^1.5.0, rollup-pluginutils@^1.5.1:
|
rollup-pluginutils@^1.5.0, rollup-pluginutils@^1.5.1:
|
||||||
version "1.5.2"
|
version "1.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408"
|
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408"
|
||||||
|
@ -4395,6 +4415,13 @@ rollup-pluginutils@^2.3.0:
|
||||||
estree-walker "^0.6.0"
|
estree-walker "^0.6.0"
|
||||||
micromatch "^3.1.10"
|
micromatch "^3.1.10"
|
||||||
|
|
||||||
|
rollup-pluginutils@^2.6.0:
|
||||||
|
version "2.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97"
|
||||||
|
integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==
|
||||||
|
dependencies:
|
||||||
|
estree-walker "^0.6.1"
|
||||||
|
|
||||||
rollup@^1.8.0:
|
rollup@^1.8.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.8.0.tgz#e3ce8b708ad4325166717f74f244f691595d35e2"
|
resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.8.0.tgz#e3ce8b708ad4325166717f74f244f691595d35e2"
|
||||||
|
@ -4613,6 +4640,11 @@ source-map@^0.6.0, source-map@~0.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
sourcemap-codec@^1.4.4:
|
||||||
|
version "1.4.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9"
|
||||||
|
integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==
|
||||||
|
|
||||||
spdx-correct@^3.0.0:
|
spdx-correct@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82"
|
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82"
|
||||||
|
|
This could possibly be removed or moved. The function is called parseURI, not parseAndValidateURI. It's one thing to error if invalid characters make it impossible to parse, but I think erroring on a validly structured URI is probably incorrect here.