feat: add provider-backed microservices
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
export interface PreviewOptions {
|
||||
maxDepth?: number;
|
||||
maxArrayItems?: number;
|
||||
maxObjectKeys?: number;
|
||||
maxStringLength?: number;
|
||||
}
|
||||
|
||||
const DEFAULT_PREVIEW_OPTIONS: Required<PreviewOptions> = {
|
||||
maxDepth: 4,
|
||||
maxArrayItems: 6,
|
||||
maxObjectKeys: 32,
|
||||
maxStringLength: 1000,
|
||||
};
|
||||
|
||||
function optionsWithDefaults(options: PreviewOptions = {}): Required<PreviewOptions> {
|
||||
return {
|
||||
maxDepth: options.maxDepth ?? DEFAULT_PREVIEW_OPTIONS.maxDepth,
|
||||
maxArrayItems: options.maxArrayItems ?? DEFAULT_PREVIEW_OPTIONS.maxArrayItems,
|
||||
maxObjectKeys: options.maxObjectKeys ?? DEFAULT_PREVIEW_OPTIONS.maxObjectKeys,
|
||||
maxStringLength: options.maxStringLength ?? DEFAULT_PREVIEW_OPTIONS.maxStringLength,
|
||||
};
|
||||
}
|
||||
|
||||
export function jsonByteLength(value: unknown): number {
|
||||
try {
|
||||
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
||||
} catch {
|
||||
return Buffer.byteLength(String(value), "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
export function previewJson(value: unknown, options: PreviewOptions = {}, depth = 0): unknown {
|
||||
const limits = optionsWithDefaults(options);
|
||||
if (value === null || typeof value === "number" || typeof value === "boolean") return value;
|
||||
if (typeof value === "string") {
|
||||
if (value.length <= limits.maxStringLength) return value;
|
||||
return {
|
||||
_previewType: "string",
|
||||
length: value.length,
|
||||
text: value.slice(0, limits.maxStringLength),
|
||||
truncated: true,
|
||||
};
|
||||
}
|
||||
if (typeof value !== "object") return String(value);
|
||||
if (depth >= limits.maxDepth) {
|
||||
return {
|
||||
_previewType: Array.isArray(value) ? "array" : "object",
|
||||
truncated: true,
|
||||
...(Array.isArray(value) ? { length: value.length } : { keys: Object.keys(value as Record<string, unknown>).length }),
|
||||
};
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return {
|
||||
_previewType: "array",
|
||||
length: value.length,
|
||||
items: value.slice(0, limits.maxArrayItems).map((item) => previewJson(item, limits, depth + 1)),
|
||||
truncatedItems: Math.max(0, value.length - limits.maxArrayItems),
|
||||
};
|
||||
}
|
||||
const record = value as Record<string, unknown>;
|
||||
const entries = Object.entries(record);
|
||||
const preview: Record<string, unknown> = {};
|
||||
for (const [key, item] of entries.slice(0, limits.maxObjectKeys)) {
|
||||
preview[key] = previewJson(item, limits, depth + 1);
|
||||
}
|
||||
if (entries.length > limits.maxObjectKeys) {
|
||||
preview._preview = {
|
||||
truncatedKeys: entries.length - limits.maxObjectKeys,
|
||||
totalKeys: entries.length,
|
||||
};
|
||||
}
|
||||
return preview;
|
||||
}
|
||||
|
||||
export function boundedJsonDetail(value: unknown, maxBytes: number, options: PreviewOptions = {}): unknown {
|
||||
const originalBytes = jsonByteLength(value);
|
||||
if (originalBytes <= maxBytes) return value;
|
||||
return {
|
||||
_truncated: true,
|
||||
originalBytes,
|
||||
maxBytes,
|
||||
preview: previewJson(value, options),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user