Pular para o conteúdo principal

Intervalos de Tempo

Um atributo timeInterval é uma regra de recorrência, não uma lista de slots: uma data âncora, intervalos de tempo diários e flags de repetição. Resolva-o em pares concretos [início, fim] para a janela que você realmente renderiza com os helpers de nível superior expandAttributeTimeIntervals, expandTimeIntervals e o guardião de tipo isTimeIntervalAttribute.

import { expandAttributeTimeIntervals } from 'oneentry';

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});
// [['2025-04-14T09:00:00.000Z', '2025-04-14T10:00:00.000Z'], …]

Todos os três helpers são puros — eles não mutam sua entrada e não realizam requisições.

Onde os horários vivem

A API retorna horários em duas formas, e ambas são aceitas pelos helpers:

FormaOnde encontrá-laTransporta
Entidade (ITimeIntervalEntitySchedule)attributeValues[marker].value[].values[] em páginas, produtos, blocos e conjuntos de atributosum intervalo de datas com pares de horas
Formulário (ITimeIntervalSchedule)attributes[].localizeInfos.intervals[] em formuláriosum intervalo com intervalos que transportam um período em minutos

expandAttributeTimeIntervals(attr, window)

O caminho de uma chamada para atributos de entidade: ele percorre os grupos e horários do atributo, expande cada um deles e mescla os resultados. A mesclagem é importante — a deduplicação e a ordenação ocorrem apenas dentro de um único horário, então combinar grupos manualmente pode resultar em slots duplicados ou desordenados.

Qualquer coisa que não seja um atributo timeInterval gera um array vazio, então é seguro chamá-lo sem verificar type primeiro.

import { expandAttributeTimeIntervals } from 'oneentry';

const page = await Pages.getPageByUrl('booking');

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

expandTimeIntervals(schedule, window)

Resolve um único horário. Acesse-o quando você já tiver um — notavelmente em formulários, cujos horários já estão tipados em localizeInfos.intervals:

import { expandTimeIntervals } from 'oneentry';

const form = await Forms.getFormByMarker('booking_form');
const field = form.attributes.find((a) => a.marker === 'schedule');

const slots = (field?.localizeInfos.intervals ?? []).flatMap((schedule) =>
expandTimeIntervals(schedule, { from: '2025-05-01', to: '2025-05-31' }),
);

isTimeIntervalAttribute(attr)

IAttributeValue.value é tipado como unknown, porque sua forma depende de type. Este guardião de tipo restringe um atributo a ITimeIntervalAttributeValue, que é o que permite acessar os horários sem um cast:

import { isTimeIntervalAttribute } from 'oneentry';

const attr = page.attributeValues.interval;

if (isTimeIntervalAttribute(attr)) {
attr.value[0].values[0].dates; // fully typed
}

A janela

const window = { from: '2025-04-01', to: '2025-04-30' };
  • from e to aceitam uma Data, uma string ISO ou milissegundos de época.
  • Ambos os limites são inclusivos e comparados com granularidade de dia UTC — a parte de hora do dia de from/to é ignorada.
  • A janela é obrigatória: um horário é uma regra de recorrência de prazo aberto, e apenas você sabe até onde ela deve ser resolvida.

Semântica de Recorrência

  • dates[0] / range[0] é tanto a fase de recorrência quanto o primeiro dia válido — nada anterior é emitido, por mais ampla que seja a janela.
  • dates[1] / range[1] encerra a validade. Quando não se estende além do início, o horário está ancorado a esse único dia; com uma flag de recorrência definida, a recorrência é então de prazo aberto e a janela sozinha limita o resultado.
  • inEveryWeek repete a cada 7 dias a partir da âncora.
  • inEveryMonth repete no mesmo dia do mês, pulando meses que são muito curtos.
  • Com ambas as flags definidas, a regra semanal se aplica — que é o que sempre significou na prática.
  • Com nenhuma flag, o horário é um simples intervalo de datas: cada dia dele produz slots.
  • O resultado é deduplicado e ordenado por início, depois por fim.
  • Toda a aritmética é UTC, então o resultado não depende do fuso horário da máquina.

Migrando do campo timeIntervals

Versões anteriores do SDK injetavam um array timeIntervals computado em cada valor de atributo timeInterval. Esse campo não existe mais. Ele materializava um ano inteiro de slots, independentemente do que o chamador precisava — um único atributo com slots horários expandia para cerca de 2.000 linhas de JSON, e períodos de slots mais finos chegavam a megabytes, o suficiente para ultrapassar os limites de cache de dados do framework. Nunca foi declarado em nenhuma interface ou esquema também, então consumidores TypeScript só podiam acessá-lo através de um cast.

// before — read the pre-computed field
const slots = page.attributeValues.interval.value[0].values[0].timeIntervals;

// now — expand the window you actually render
import { expandAttributeTimeIntervals } from 'oneentry';

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

Os dados de origem sendo expandidos (dates/range, times/intervals, inEveryWeek, inEveryMonth) permanecem inalterados e ainda estão presentes em cada horário — nada se perde, é simplesmente resolvido sob demanda em vez de de forma ansiosa, e a regra compacta é o que é armazenado em cache.

Os métodos _addTimeIntervalsToSchedules e _addTimeIntervalsToFormSchedules foram removidos de todos os módulos também (apesar do prefixo _, eles eram chamáveis, por exemplo, Pages._addTimeIntervalsToSchedules). Use expandTimeIntervals em vez disso.

Tipos

Todos esses são exportados da raiz do pacote e de oneentry/types (veja Importando Tipos):

TipoDescreve
ITimeIntervalAttributeValueUm IAttributeValue restringido a type: 'timeInterval', cujo value é um array de grupos
ITimeIntervalGroupUma entrada do value do atributo — horários compartilhando um intervalId
ITimeIntervalEntityScheduleUm horário de entidade: dates, times, inEveryWeek, inEveryMonth
ITimeIntervalScheduleUm horário de formulário: range, intervals, inEveryWeek, inEveryMonth
ITimeIntervalRangeUm intervalo diário com start, end e um período de slot em minutos (null quando não fatiado)
ITimeIntervalPointUm ponto em um dia - { horas, minutos }
ITimeIntervalWindowA janela de expansão - { from, to }
TimeIntervalPairUm slot resolvido - [start, end], ambas strings ISO 8601 UTC

Exemplo: renderizando um mês de slots

import { expandAttributeTimeIntervals } from 'oneentry';

const page = await Pages.getPageByUrl('booking');

if ('statusCode' in page) {
throw new Error(page.message);
}

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

// Group the slots by day for a calendar view
const byDay = slots.reduce((acc, [start, end]) => {
const day = start.slice(0, 10);
(acc[day] ??= []).push([start, end]);
return acc;
}, {});

🔗 Documentação Relacionada