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:
| Forma | Onde encontrá-la | Transporta |
|---|---|---|
Entidade (ITimeIntervalEntitySchedule) | attributeValues[marker].value[].values[] em páginas, produtos, blocos e conjuntos de atributos | um intervalo de datas com pares de horas |
Formulário (ITimeIntervalSchedule) | attributes[].localizeInfos.intervals[] em formulários | um 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' };
frometoaceitam umaData, 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.inEveryWeekrepete a cada 7 dias a partir da âncora.inEveryMonthrepete 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):
| Tipo | Descreve |
|---|---|
ITimeIntervalAttributeValue | Um IAttributeValue restringido a type: 'timeInterval', cujo value é um array de grupos |
ITimeIntervalGroup | Uma entrada do value do atributo — horários compartilhando um intervalId |
ITimeIntervalEntitySchedule | Um horário de entidade: dates, times, inEveryWeek, inEveryMonth |
ITimeIntervalSchedule | Um horário de formulário: range, intervals, inEveryWeek, inEveryMonth |
ITimeIntervalRange | Um intervalo diário com start, end e um período de slot em minutos (null quando não fatiado) |
ITimeIntervalPoint | Um ponto em um dia - { horas, minutos } |
ITimeIntervalWindow | A janela de expansão - { from, to } |
TimeIntervalPair | Um 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
- Valores de Atributo - a forma normalizada de cada valor de atributo
- Importando Tipos - importando
ITimeIntervalWindowe amigos - Módulo de Formulários - atributos de formulário que transportam
localizeInfos.intervals