evo360-types 1.3.476 → 1.3.480

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -633,6 +633,7 @@ export declare const zAppointmentSchema: z.ZodObject<{
633
633
  isDraft: z.ZodDefault<z.ZodBoolean>;
634
634
  draftExpirationMinutes: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
635
635
  external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
636
+ status_external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
636
637
  tags: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
637
638
  name: z.ZodString;
638
639
  color: z.ZodOptional<z.ZodString>;
@@ -969,6 +970,7 @@ export declare const zAppointmentSchema: z.ZodObject<{
969
970
  isDraft: z.ZodDefault<z.ZodBoolean>;
970
971
  draftExpirationMinutes: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
971
972
  external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
973
+ status_external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
972
974
  tags: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
973
975
  name: z.ZodString;
974
976
  color: z.ZodOptional<z.ZodString>;
@@ -1305,6 +1307,7 @@ export declare const zAppointmentSchema: z.ZodObject<{
1305
1307
  isDraft: z.ZodDefault<z.ZodBoolean>;
1306
1308
  draftExpirationMinutes: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1307
1309
  external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1310
+ status_external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1308
1311
  tags: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
1309
1312
  name: z.ZodString;
1310
1313
  color: z.ZodOptional<z.ZodString>;
@@ -202,6 +202,15 @@ exports.zAppointmentSchema = zod_schemas_1.zFireDocSchema
202
202
  draftExpirationMinutes: zod_1.z.number().nullable().optional(), // tempo em minutos para expiração do rascunho
203
203
  // ID externo da consulta
204
204
  external_id: zod_1.z.string().nullable().optional(),
205
+ // ID do STATUS na agenda externa de origem — algumas agendas identificam o
206
+ // status por id além do rótulo (`status`), e os workflows n8n usam esse id
207
+ // pra reescrever o agendamento sem resolver o rótulo de volta.
208
+ //
209
+ // `coerce` de propósito: agenda externa que devolve id NUMÉRICO é caso
210
+ // conhecido nesta base (quebrou o `patient.create` uma vez). Com `z.string()`
211
+ // puro, um `4` faria o write-through reprovar com `contract_violation`.
212
+ // Nullable/optional resolvem ANTES da coerção — `null` continua `null`.
213
+ status_external_id: zod_1.z.coerce.string().nullable().optional(),
205
214
  tags: zod_1.z.array(zod_schemas_1.zTagSchema).nullable().optional(),
206
215
  })
207
216
  .passthrough();
@@ -223,6 +223,16 @@ export const zAppointmentSchema = zFireDocSchema
223
223
  // ID externo da consulta
224
224
  external_id: z.string().nullable().optional(),
225
225
 
226
+ // ID do STATUS na agenda externa de origem — algumas agendas identificam o
227
+ // status por id além do rótulo (`status`), e os workflows n8n usam esse id
228
+ // pra reescrever o agendamento sem resolver o rótulo de volta.
229
+ //
230
+ // `coerce` de propósito: agenda externa que devolve id NUMÉRICO é caso
231
+ // conhecido nesta base (quebrou o `patient.create` uma vez). Com `z.string()`
232
+ // puro, um `4` faria o write-through reprovar com `contract_violation`.
233
+ // Nullable/optional resolvem ANTES da coerção — `null` continua `null`.
234
+ status_external_id: z.coerce.string().nullable().optional(),
235
+
226
236
  tags: z.array(zTagSchema).nullable().optional(),
227
237
  })
228
238
  .passthrough();
@@ -159,11 +159,50 @@ export interface ICampaignSentToday {
159
159
  email?: number;
160
160
  };
161
161
  }
162
+ /**
163
+ * Where ONE channel stands in the dispatch queue (F3.3).
164
+ *
165
+ * The four pacing knobs are configured per channel, so the two channels advance through
166
+ * the audience at different speeds and each needs its own position. Both channels read
167
+ * the SAME queue (`dispatch_state == 'pending'` ordered by `__name__`); what separates
168
+ * them is the `startAfter` each one uses.
169
+ */
170
+ export interface ICampaignDispatchChannelState {
171
+ /**
172
+ * Last recipient id this channel dispatched — the `startAfter` of its own page.
173
+ * A channel held back by its window or its daily limit simply does NOT advance this,
174
+ * which is what records the legs it still owes.
175
+ */
176
+ cursor_doc_id?: string | null;
177
+ /**
178
+ * Earliest instant this channel may dispatch again (its own `batch_interval_minutes`).
179
+ * This is the AUTHORITY on the channel's turn: the scheduled `campaign.dispatch_batch`
180
+ * task is only a wake-up call and grants no permission by itself, so a batch that fires
181
+ * early (the feat-080 sweep reviving a chain, say) re-reads this and defers.
182
+ * Firestore returns a Timestamp — `.toDate()` before comparing.
183
+ */
184
+ next_at?: Date | null;
185
+ }
162
186
  export interface ICampaignDispatchState {
187
+ /**
188
+ * LEGACY (pre-F3.3): the single campaign-wide cursor. It no longer governs sending —
189
+ * `per_channel.{channel}.cursor_doc_id` does. It is still written, as the MINIMUM of
190
+ * the per-channel cursors, for two reasons: a campaign in flight when F3.3 deployed
191
+ * seeds both channels from it, and a rollback to the previous engine must resume
192
+ * BEHIND every channel rather than ahead of one (re-reading is inert — the send task
193
+ * is idempotent on `dedup_key` — whereas skipping loses a send silently).
194
+ * Do not read this to answer "how far has the campaign got": ask per channel.
195
+ */
163
196
  cursor_doc_id?: string | null;
164
197
  next_dispatch_task_id?: string | null;
165
198
  sent_today?: ICampaignSentToday;
166
199
  batches_dispatched?: number;
200
+ /** Per-channel queue position and turn (F3.3). Absent on a campaign that last ran
201
+ * under the pre-F3.3 engine; each channel then falls back to `cursor_doc_id`. */
202
+ per_channel?: {
203
+ whatsapp?: ICampaignDispatchChannelState;
204
+ email?: ICampaignDispatchChannelState;
205
+ };
167
206
  }
168
207
  export type CampaignPrevalidationStatus = "approved" | "warnings" | "blocked";
169
208
  export interface ICampaignPrevalidation {
@@ -231,11 +231,51 @@ export interface ICampaignSentToday {
231
231
  };
232
232
  }
233
233
 
234
+ /**
235
+ * Where ONE channel stands in the dispatch queue (F3.3).
236
+ *
237
+ * The four pacing knobs are configured per channel, so the two channels advance through
238
+ * the audience at different speeds and each needs its own position. Both channels read
239
+ * the SAME queue (`dispatch_state == 'pending'` ordered by `__name__`); what separates
240
+ * them is the `startAfter` each one uses.
241
+ */
242
+ export interface ICampaignDispatchChannelState {
243
+ /**
244
+ * Last recipient id this channel dispatched — the `startAfter` of its own page.
245
+ * A channel held back by its window or its daily limit simply does NOT advance this,
246
+ * which is what records the legs it still owes.
247
+ */
248
+ cursor_doc_id?: string | null;
249
+ /**
250
+ * Earliest instant this channel may dispatch again (its own `batch_interval_minutes`).
251
+ * This is the AUTHORITY on the channel's turn: the scheduled `campaign.dispatch_batch`
252
+ * task is only a wake-up call and grants no permission by itself, so a batch that fires
253
+ * early (the feat-080 sweep reviving a chain, say) re-reads this and defers.
254
+ * Firestore returns a Timestamp — `.toDate()` before comparing.
255
+ */
256
+ next_at?: Date | null;
257
+ }
258
+
234
259
  export interface ICampaignDispatchState {
260
+ /**
261
+ * LEGACY (pre-F3.3): the single campaign-wide cursor. It no longer governs sending —
262
+ * `per_channel.{channel}.cursor_doc_id` does. It is still written, as the MINIMUM of
263
+ * the per-channel cursors, for two reasons: a campaign in flight when F3.3 deployed
264
+ * seeds both channels from it, and a rollback to the previous engine must resume
265
+ * BEHIND every channel rather than ahead of one (re-reading is inert — the send task
266
+ * is idempotent on `dedup_key` — whereas skipping loses a send silently).
267
+ * Do not read this to answer "how far has the campaign got": ask per channel.
268
+ */
235
269
  cursor_doc_id?: string | null;
236
270
  next_dispatch_task_id?: string | null;
237
271
  sent_today?: ICampaignSentToday;
238
272
  batches_dispatched?: number;
273
+ /** Per-channel queue position and turn (F3.3). Absent on a campaign that last ran
274
+ * under the pre-F3.3 engine; each channel then falls back to `cursor_doc_id`. */
275
+ per_channel?: {
276
+ whatsapp?: ICampaignDispatchChannelState;
277
+ email?: ICampaignDispatchChannelState;
278
+ };
239
279
  }
240
280
 
241
281
  export type CampaignPrevalidationStatus = "approved" | "warnings" | "blocked";
@@ -159,6 +159,17 @@ export interface IAppointment extends IFireDoc {
159
159
  payment?: IAppointmentPayment | null;
160
160
  reschedules?: IAppointmentReschedule[] | null;
161
161
  external_id?: string | null;
162
+ /**
163
+ * ID do STATUS na agenda externa de origem. Algumas agendas identificam o
164
+ * status por id além do rótulo (`status`), e os workflows n8n precisam desse
165
+ * id pra reescrever o agendamento no externo sem ter que resolver o rótulo
166
+ * de volta.
167
+ *
168
+ * Opcional por natureza: só algumas agendas têm. Autoridade do externo — não
169
+ * declarado na base global de política, então resolve como `external`.
170
+ * Não replicado no embed do paciente (ver `IPatientAppointment`).
171
+ */
172
+ status_external_id?: string | null;
162
173
  isDraft: boolean;
163
174
  draftExpirationMinutes?: number | null;
164
175
  tags?: ITag[] | null;
@@ -201,6 +201,17 @@ export interface IAppointment extends IFireDoc {
201
201
  // Controle de remarcações
202
202
  reschedules?: IAppointmentReschedule[] | null;
203
203
  external_id?: string | null; // ID externo da consulta
204
+ /**
205
+ * ID do STATUS na agenda externa de origem. Algumas agendas identificam o
206
+ * status por id além do rótulo (`status`), e os workflows n8n precisam desse
207
+ * id pra reescrever o agendamento no externo sem ter que resolver o rótulo
208
+ * de volta.
209
+ *
210
+ * Opcional por natureza: só algumas agendas têm. Autoridade do externo — não
211
+ * declarado na base global de política, então resolve como `external`.
212
+ * Não replicado no embed do paciente (ver `IPatientAppointment`).
213
+ */
214
+ status_external_id?: string | null;
204
215
  // Propriedades para controle de rascunho
205
216
  isDraft: boolean;
206
217
  draftExpirationMinutes?: number | null; // tempo em minutos para expiração do rascunho
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evo360-types",
3
- "version": "1.3.476",
3
+ "version": "1.3.480",
4
4
  "description": "HREVO360 Shared Types",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",