@avakado.ai/schemas 1.1.21 → 1.1.23
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.
- package/package.json +1 -1
- package/src/contactWindows.js +74 -0
- package/src/index.js +10 -0
- package/src/models/Leads.js +7 -1
- package/types.d.ts +1 -1
package/package.json
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Session chat Meta allows after the lead's last inbound message. */
|
|
2
|
+
export const CHAT_SESSION_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
/** Callback window after a user-initiated WhatsApp call. */
|
|
4
|
+
export const WHATSAPP_CALL_CALLBACK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
5
|
+
|
|
6
|
+
function windowUntil(mode, platform, at) {
|
|
7
|
+
const when = new Date(at);
|
|
8
|
+
if (mode === 'chat' && platform === 'telegram') return null;
|
|
9
|
+
if (mode === 'call' && platform === 'phone') return null;
|
|
10
|
+
if (mode === 'call' && platform === 'whatsapp') return new Date(when.getTime() + WHATSAPP_CALL_CALLBACK_MS);
|
|
11
|
+
return new Date(when.getTime() + CHAT_SESSION_MS);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function contactWindowValue(mode, platform, at) {
|
|
15
|
+
return { allowed: true, validUntil: windowUntil(mode, platform, at) };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Replace the matched handle's window. Use this when the user grants or refuses permission. */
|
|
19
|
+
export function setContactWindow(update, mode, platform, { allowed, validUntil = null }) {
|
|
20
|
+
const prefix = `contactDetails.${platform}.$.${mode}`;
|
|
21
|
+
update.$set ??= {};
|
|
22
|
+
update.$set[`${prefix}.allowed`] = Boolean(allowed);
|
|
23
|
+
update.$set[`${prefix}.validUntil`] = validUntil;
|
|
24
|
+
return update;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Merge a window refresh onto the matched contactDetails entry. The query must match that handle. A later inbound only extends validUntil. */
|
|
28
|
+
export function applyContactWindow(update, mode, platform, at) {
|
|
29
|
+
const prefix = `contactDetails.${platform}.$.${mode}`;
|
|
30
|
+
const until = windowUntil(mode, platform, at);
|
|
31
|
+
update.$set ??= {};
|
|
32
|
+
update.$set[`${prefix}.allowed`] = true;
|
|
33
|
+
if (!until) {
|
|
34
|
+
update.$set[`${prefix}.validUntil`] = null;
|
|
35
|
+
return update;
|
|
36
|
+
}
|
|
37
|
+
update.$max ??= {};
|
|
38
|
+
update.$max[`${prefix}.validUntil`] = until;
|
|
39
|
+
return update;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function contactWindowIsOpen(window, at = new Date()) {
|
|
43
|
+
if (!window?.allowed) return false;
|
|
44
|
+
if (!window.validUntil) return true;
|
|
45
|
+
return new Date(window.validUntil).getTime() > new Date(at).getTime();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function recordedWindow(window) {
|
|
49
|
+
if (!window || (window.allowed == null && window.validUntil == null)) return null;
|
|
50
|
+
return window;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The window on the primary handle, or the one that stays open longest. */
|
|
54
|
+
export function storedContactWindow(lead, mode, platform) {
|
|
55
|
+
const entries = lead?.contactDetails?.[platform];
|
|
56
|
+
if (!Array.isArray(entries)) return null;
|
|
57
|
+
const primary = recordedWindow(entries.find((entry) => entry.isPrimary)?.[mode]);
|
|
58
|
+
if (primary) return primary;
|
|
59
|
+
return entries.reduce((best, entry) => {
|
|
60
|
+
const window = recordedWindow(entry?.[mode]);
|
|
61
|
+
if (!window) return best;
|
|
62
|
+
if (!best) return window;
|
|
63
|
+
if (!window.validUntil) return window;
|
|
64
|
+
if (!best.validUntil) return best;
|
|
65
|
+
return new Date(window.validUntil) > new Date(best.validUntil) ? window : best;
|
|
66
|
+
}, null);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** True only when a stored window exists and is closed. A missing window is left to the caller. */
|
|
70
|
+
export function sessionChatClosed(lead, platform, at = new Date()) {
|
|
71
|
+
const window = storedContactWindow(lead, 'chat', platform);
|
|
72
|
+
if (!window) return false;
|
|
73
|
+
return !contactWindowIsOpen(window, at);
|
|
74
|
+
}
|
package/src/index.js
CHANGED
|
@@ -3,3 +3,13 @@ export * from "./models/index.js";
|
|
|
3
3
|
export * from "./enums/index.js";
|
|
4
4
|
export * from "./media.js";
|
|
5
5
|
export { configureSchemas, defineModel, getSchemaConfig } from "./runtime.js";
|
|
6
|
+
export {
|
|
7
|
+
CHAT_SESSION_MS,
|
|
8
|
+
WHATSAPP_CALL_CALLBACK_MS,
|
|
9
|
+
applyContactWindow,
|
|
10
|
+
contactWindowIsOpen,
|
|
11
|
+
contactWindowValue,
|
|
12
|
+
sessionChatClosed,
|
|
13
|
+
setContactWindow,
|
|
14
|
+
storedContactWindow,
|
|
15
|
+
} from "./contactWindows.js";
|
package/src/models/Leads.js
CHANGED
|
@@ -2,12 +2,18 @@ import { Schema } from "mongoose";
|
|
|
2
2
|
import { defineModel } from "../runtime.js";
|
|
3
3
|
import { LEAD_STATUS } from "../enums/index.js";
|
|
4
4
|
import { attachStatusChangeTrigger } from "../statusTrigger.js";
|
|
5
|
+
const contactWindowSchema = new Schema({
|
|
6
|
+
allowed: Boolean,
|
|
7
|
+
validUntil: Date,
|
|
8
|
+
}, { _id: false });
|
|
5
9
|
const platformEntrySchema = new Schema({
|
|
6
10
|
platform: { type: String, required: true }, // Phone,'Twitter', 'Instagram', 'Whatsapp', etc.
|
|
7
11
|
handle: { type: String, trim: true },
|
|
8
12
|
label: { type: String, trim: true }, // 'work', 'personal', 'brand'
|
|
9
13
|
isPrimary: { type: Boolean, default: false },
|
|
10
|
-
metadata: { type: Schema.Types.Mixed, default: {} }
|
|
14
|
+
metadata: { type: Schema.Types.Mixed, default: {} },
|
|
15
|
+
chat: contactWindowSchema,
|
|
16
|
+
call: contactWindowSchema,
|
|
11
17
|
}, { _id: false });
|
|
12
18
|
const contactDetailsSchema = new Schema({
|
|
13
19
|
whatsapp: [platformEntrySchema],
|
package/types.d.ts
CHANGED
|
@@ -304,7 +304,7 @@ export interface Lead {
|
|
|
304
304
|
business: Types.ObjectId;
|
|
305
305
|
createdBy?: Types.ObjectId;
|
|
306
306
|
name?: string;
|
|
307
|
-
contactDetails?: { whatsapp?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; telegram?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; email?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; phone?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; twitter?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; instagram?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; facebook?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; }[]; };
|
|
307
|
+
contactDetails?: { whatsapp?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; telegram?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; email?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; phone?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; twitter?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; instagram?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; facebook?: { platform: string; handle?: string; label?: string; isPrimary?: boolean; metadata?: any; chat?: { allowed?: boolean; validUntil?: Date; }; call?: { allowed?: boolean; validUntil?: Date; }; }[]; };
|
|
308
308
|
source?: string;
|
|
309
309
|
tags?: string[];
|
|
310
310
|
leadScore?: number;
|