diff --git a/src/shared/agent-status-child-work-alias.ts b/src/shared/agent-status-child-work-alias.ts index 0442b4310a1..1544c864231 100644 --- a/src/shared/agent-status-child-work-alias.ts +++ b/src/shared/agent-status-child-work-alias.ts @@ -4,6 +4,7 @@ import type { AgentChildWorkKind } from './agent-status-child-work' import { parseAgentChildWorkInvocationFence } from './agent-status-child-work-codec' +import { isBoundedString } from './agent-status-child-work-value-guards' import { deserializeAgentStatusSubject, parseAgentStatusSubject, @@ -65,24 +66,6 @@ function hasOnlyKeys( ) } -function isBoundedString(value: unknown): value is string { - if ( - typeof value !== 'string' || - value.length === 0 || - value.length > MAX_ALIAS_PART_LENGTH || - value !== value.trim() - ) { - return false - } - for (let index = 0; index < value.length; index += 1) { - const code = value.charCodeAt(index) - if (code <= 0x1f || code === 0x7f) { - return false - } - } - return true -} - function isRevision(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 } @@ -114,12 +97,12 @@ export function parseAgentChildWorkAliasInput(value: unknown): AgentChildWorkAli 'childWorkId', 'fence' ]) || - !isBoundedString(value.provider) || - !isBoundedString(value.segmentId) || + !isBoundedString(value.provider, MAX_ALIAS_PART_LENGTH) || + !isBoundedString(value.segmentId, MAX_ALIAS_PART_LENGTH) || !isKind(value.kind) || !isAliasKind(value.aliasKind) || - !isBoundedString(value.alias) || - !isBoundedString(value.childWorkId) + !isBoundedString(value.alias, MAX_ALIAS_PART_LENGTH) || + !isBoundedString(value.childWorkId, MAX_ALIAS_PART_LENGTH) ) { return null } diff --git a/src/shared/agent-status-store-codec.ts b/src/shared/agent-status-store-codec.ts index ba060180f5c..c41e71b3a22 100644 --- a/src/shared/agent-status-store-codec.ts +++ b/src/shared/agent-status-store-codec.ts @@ -2,6 +2,7 @@ import { parseAgentChildWorkAliasInput, parseAgentChildWorkAliasRecord } from './agent-status-child-work-alias' +import { isBoundedString } from './agent-status-child-work-value-guards' import { parseAgentChildWorkInput, parseAgentChildWorkRecord @@ -49,26 +50,8 @@ function isRevision(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 } -function isBoundedKey(value: unknown, maxLength: number): value is string { - if ( - typeof value !== 'string' || - value.length === 0 || - value.length > maxLength || - value !== value.trim() - ) { - return false - } - for (let index = 0; index < value.length; index += 1) { - const code = value.charCodeAt(index) - if (code <= 0x1f || code === 0x7f) { - return false - } - } - return true -} - export function isAgentStatusStoreEpoch(value: unknown): value is string { - return isBoundedKey(value, MAX_EPOCH_LENGTH) + return isBoundedString(value, MAX_EPOCH_LENGTH) } function isTombstoneEntity(value: unknown): value is AgentStatusTombstoneEntity { @@ -80,7 +63,7 @@ export function parseAgentStatusTombstoneInput(value: unknown): AgentStatusTombs !isRecord(value) || !hasOnlyKeys(value, ['entity', 'key']) || !isTombstoneEntity(value.entity) || - !isBoundedKey(value.key, MAX_TOMBSTONE_KEY_LENGTH) + !isBoundedString(value.key, MAX_TOMBSTONE_KEY_LENGTH) ) { return null } @@ -118,7 +101,7 @@ function parseArray( function parseStringArray(value: unknown): string[] | null { return parseArray(value, (candidate) => - isBoundedKey(candidate, MAX_TOMBSTONE_KEY_LENGTH) ? candidate : null + isBoundedString(candidate, MAX_TOMBSTONE_KEY_LENGTH) ? candidate : null ) } diff --git a/src/shared/agent-status-store-fact-codec.ts b/src/shared/agent-status-store-fact-codec.ts index 09b5d76a236..9e57e502611 100644 --- a/src/shared/agent-status-store-fact-codec.ts +++ b/src/shared/agent-status-store-fact-codec.ts @@ -4,6 +4,7 @@ import type { AgentStatusFactRecord, AgentStatusFactValue } from './agent-status-store-contract' +import { isBoundedString } from './agent-status-child-work-value-guards' import { deserializeAgentStatusSubject, parseAgentStatusSubject, @@ -27,24 +28,6 @@ function isRevision(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 } -function isFactKey(value: unknown): value is string { - if ( - typeof value !== 'string' || - value.length === 0 || - value.length > MAX_FACT_KEY_LENGTH || - value !== value.trim() - ) { - return false - } - for (let index = 0; index < value.length; index += 1) { - const code = value.charCodeAt(index) - if (code <= 0x1f || code === 0x7f) { - return false - } - } - return true -} - function parseFactValue(value: unknown): AgentStatusFactValue | undefined { if (value === null || typeof value === 'boolean') { return value @@ -61,7 +44,7 @@ export function parseAgentStatusFactInput(value: unknown): AgentStatusFactInput } const subject = parseAgentStatusSubject(value.subject) const factValue = parseFactValue(value.value) - if (!subject || !isFactKey(value.key) || factValue === undefined) { + if (!subject || !isBoundedString(value.key, MAX_FACT_KEY_LENGTH) || factValue === undefined) { return null } return { subject, key: value.key, value: factValue } @@ -82,7 +65,9 @@ export function parseAgentStatusFactIdentity(value: unknown): AgentStatusFactIde return null } const subject = parseAgentStatusSubject(value.subject) - return subject && isFactKey(value.key) ? { subject, key: value.key } : null + return subject && isBoundedString(value.key, MAX_FACT_KEY_LENGTH) + ? { subject, key: value.key } + : null } export function serializeAgentStatusFactKey(fact: AgentStatusFactIdentity): string {