polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
176 lines • 7.22 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.VariableResolver = void 0;
const crypto = __importStar(require("crypto"));
const MS_PER_DAY = 24 * 60 * 60 * 1000;
const MAX_RANDOM_LENGTH = 10000;
const MAX_DAY_OFFSET = 3650;
class VariableResolver {
constructor() {
this.baseTimestamp = Date.now();
}
resetTimestamp() {
this.baseTimestamp = Date.now();
}
resolve(template, outputs) {
let result = template;
const openBraces = (template.match(/\{/g) || []).length;
const closeBraces = (template.match(/\}/g) || []).length;
if (openBraces !== closeBraces) {
throw new Error('Malformed variable syntax: unclosed braces');
}
result = result.replace(/\{timestamp\}/g, this.baseTimestamp.toString());
result = this.resolveNowVariables(result);
result = this.resolveRandomVariables(result);
if (outputs) {
result = this.resolveResourceReferences(result, outputs);
}
return result;
}
resolveObject(obj, outputs) {
const result = {};
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'string') {
result[key] = this.resolve(value, outputs);
}
else if (Array.isArray(value)) {
result[key] = value.map(item => {
if (typeof item === 'string') {
return this.resolve(item, outputs);
}
else if (typeof item === 'object' && item !== null) {
return this.resolveObject(item, outputs);
}
return item;
});
}
else if (typeof value === 'object' && value !== null) {
result[key] = this.resolveObject(value, outputs);
}
else {
result[key] = value;
}
}
return result;
}
renderTemplate(template, outputs) {
return this.resolve(template, outputs);
}
resolveNowVariables(template) {
const invalidNowPattern = /\{now\+([^}]+)\}/g;
let invalidMatch;
while ((invalidMatch = invalidNowPattern.exec(template)) !== null) {
const content = invalidMatch[1];
if (content && !/^\d+d$/.test(content)) {
throw new Error(`Invalid now offset format: {now+${content}}`);
}
}
const nowPlusPattern = /\{now\+(\d+)d\}/g;
let result = template.replace(nowPlusPattern, (_match, days) => {
const dayCount = parseInt(days, 10);
if (dayCount > MAX_DAY_OFFSET) {
throw new Error(`Invalid now offset: day count ${dayCount} exceeds maximum ${MAX_DAY_OFFSET}`);
}
return (this.baseTimestamp + dayCount * MS_PER_DAY).toString();
});
result = result.replace(/\{now\}/g, this.baseTimestamp.toString());
return result;
}
resolveRandomVariables(template) {
const randomPattern = /\{random:(\d+)-(\d+)\}/g;
return template.replace(randomPattern, (_match, minStr, maxStr) => {
const min = parseInt(minStr, 10);
const max = parseInt(maxStr, 10);
if (min < 1) {
throw new Error('Invalid random range: min must be >= 1');
}
if (min > max) {
throw new Error('Invalid random range: min must be <= max');
}
if (max > MAX_RANDOM_LENGTH) {
throw new Error(`Invalid random range: max ${max} exceeds maximum ${MAX_RANDOM_LENGTH}`);
}
const length = Math.floor(Math.random() * (max - min + 1)) + min;
return this.generateRandomString(length);
});
}
resolveResourceReferences(template, outputs) {
const refPattern = /\{([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*))\}/g;
return template.replace(refPattern, (_match, ref) => {
const parts = ref.split('.');
const resourceId = parts[0];
if (!resourceId) {
throw new Error('Invalid resource reference: empty resource id');
}
const fieldPath = parts.slice(1);
const resourceOutput = outputs[resourceId];
if (!resourceOutput) {
throw new Error(`Resource "${resourceId}" not found in outputs`);
}
let value = resourceOutput;
for (const field of fieldPath) {
if (value === undefined || value === null) {
throw new Error(`Field "${field}" not found in resource "${resourceId}" (value is undefined)`);
}
if (typeof value !== 'object') {
throw new Error(`Cannot access field "${field}" on non-object value in resource "${resourceId}"`);
}
value = value[field];
}
if (value === undefined) {
throw new Error(`Field "${fieldPath.join('.')}" not found in resource "${resourceId}"`);
}
if (typeof value === 'object') {
return JSON.stringify(value);
}
return String(value);
});
}
generateRandomString(length) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const randomBytes = crypto.randomBytes(length);
let result = '';
for (let i = 0; i < length; i++) {
const byte = randomBytes[i];
if (byte !== undefined) {
result += chars[byte % chars.length];
}
}
return result;
}
}
exports.VariableResolver = VariableResolver;
//# sourceMappingURL=variable-resolver.js.map