feat: 기능 추가 과정중

This commit is contained in:
donghyeon-ka
2026-07-30 15:58:20 +09:00
parent d3ef801fe6
commit 6c52cdb916
648 changed files with 126325 additions and 6680 deletions
@@ -0,0 +1,112 @@
export type ResumableUploadRuntimePolicy = Readonly<{
partSizeBytes: number;
maxFileBytes: number;
maxPartCount: number;
maxConcurrency: number;
maxInFlightBytes: number;
partBufferCopyFactor: number;
maxSourceChunkBytes: number;
maxRetries: number;
retryBaseDelayMs: number;
retryMaxDelayMs: number;
maxRetryAfterMs: number;
capabilityRefreshSkewMs: number;
maxSessionLifetimeMs: number;
providerAttemptTimeoutMs: number;
}>;
const MIB = 1024 * 1024;
const GIB = 1024 * MIB;
const ABSOLUTE_LIMITS = Object.freeze({
maxPartSizeBytes: 64 * MIB,
maxFileBytes: 100 * GIB,
maxPartCount: 10_000,
maxConcurrency: 8,
maxInFlightBytes: 256 * MIB,
maxPartBufferCopyFactor: 8,
maxSourceChunkBytes: 64 * MIB,
maxRetries: 8,
maxRetryDelayMs: 60_000,
maxRetryAfterMs: 60_000,
maxCapabilityRefreshSkewMs: 5 * 60_000,
maxSessionLifetimeMs: 7 * 24 * 60 * 60_000,
maxProviderAttemptTimeoutMs: 2 * 60_000,
});
const DEFAULT_POLICY: ResumableUploadRuntimePolicy = Object.freeze({
partSizeBytes: 5 * MIB,
maxFileBytes: 5 * GIB,
maxPartCount: 1_024,
maxConcurrency: 3,
maxInFlightBytes: 20 * MIB,
partBufferCopyFactor: 4,
maxSourceChunkBytes: 8 * MIB,
maxRetries: 3,
retryBaseDelayMs: 250,
retryMaxDelayMs: 5_000,
maxRetryAfterMs: 30_000,
capabilityRefreshSkewMs: 5_000,
maxSessionLifetimeMs: 24 * 60 * 60_000,
providerAttemptTimeoutMs: 30_000,
});
export function resolveResumableUploadRuntimePolicy(
input: Partial<ResumableUploadRuntimePolicy> = {},
): ResumableUploadRuntimePolicy {
const policy: ResumableUploadRuntimePolicy = Object.freeze({
...DEFAULT_POLICY,
...input,
});
if (
!positiveSafeInteger(policy.partSizeBytes) ||
policy.partSizeBytes > ABSOLUTE_LIMITS.maxPartSizeBytes ||
!positiveSafeInteger(policy.maxFileBytes) ||
policy.maxFileBytes > ABSOLUTE_LIMITS.maxFileBytes ||
!positiveSafeInteger(policy.maxPartCount) ||
policy.maxPartCount > ABSOLUTE_LIMITS.maxPartCount ||
!positiveSafeInteger(policy.maxConcurrency) ||
policy.maxConcurrency > ABSOLUTE_LIMITS.maxConcurrency ||
!positiveSafeInteger(policy.maxInFlightBytes) ||
policy.maxInFlightBytes > ABSOLUTE_LIMITS.maxInFlightBytes ||
!positiveSafeInteger(policy.partBufferCopyFactor) ||
policy.partBufferCopyFactor >
ABSOLUTE_LIMITS.maxPartBufferCopyFactor ||
policy.maxInFlightBytes <
policy.partSizeBytes * policy.partBufferCopyFactor ||
!positiveSafeInteger(policy.maxSourceChunkBytes) ||
policy.maxSourceChunkBytes >
ABSOLUTE_LIMITS.maxSourceChunkBytes ||
!nonNegativeSafeInteger(policy.maxRetries) ||
policy.maxRetries > ABSOLUTE_LIMITS.maxRetries ||
!positiveSafeInteger(policy.retryBaseDelayMs) ||
policy.retryBaseDelayMs > ABSOLUTE_LIMITS.maxRetryDelayMs ||
!positiveSafeInteger(policy.retryMaxDelayMs) ||
policy.retryMaxDelayMs > ABSOLUTE_LIMITS.maxRetryDelayMs ||
policy.retryBaseDelayMs > policy.retryMaxDelayMs ||
!nonNegativeSafeInteger(policy.maxRetryAfterMs) ||
policy.maxRetryAfterMs > ABSOLUTE_LIMITS.maxRetryAfterMs ||
!nonNegativeSafeInteger(policy.capabilityRefreshSkewMs) ||
policy.capabilityRefreshSkewMs >
ABSOLUTE_LIMITS.maxCapabilityRefreshSkewMs ||
!positiveSafeInteger(policy.maxSessionLifetimeMs) ||
policy.maxSessionLifetimeMs >
ABSOLUTE_LIMITS.maxSessionLifetimeMs ||
!positiveSafeInteger(policy.providerAttemptTimeoutMs) ||
policy.providerAttemptTimeoutMs >
ABSOLUTE_LIMITS.maxProviderAttemptTimeoutMs ||
Math.ceil(policy.maxFileBytes / policy.partSizeBytes) >
policy.maxPartCount
) {
throw new TypeError("Resumable upload policy is invalid.");
}
return policy;
}
function positiveSafeInteger(value: number): boolean {
return Number.isSafeInteger(value) && value > 0;
}
function nonNegativeSafeInteger(value: number): boolean {
return Number.isSafeInteger(value) && value >= 0;
}