@awesomate/sdk 0.34.0 → 0.51.0
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/dist/index.d.ts +570 -18
- package/dist/index.js +121 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* Docs: https://hub.awesomate.ai/docs/sdk/
|
|
27
27
|
*/
|
|
28
28
|
/** This package's version, sent to the hub with every server call. */
|
|
29
|
-
export declare const VERSION = "0.
|
|
29
|
+
export declare const VERSION = "0.51.0";
|
|
30
30
|
/** Augmented by the generated awesomate.d.ts, so each kind's rows are typed. */
|
|
31
31
|
export interface Kinds {
|
|
32
32
|
}
|
|
@@ -135,7 +135,7 @@ export interface QueryOptions<T, S extends keyof T = keyof T> {
|
|
|
135
135
|
* read, tags included, any case. Narrows like where does, and the two combine.
|
|
136
136
|
*/
|
|
137
137
|
search?: string;
|
|
138
|
-
/** IANA zone for dates and time variables. Default
|
|
138
|
+
/** IANA zone for dates and time variables. Default: the business's time zone from Your business, Sydney if none is set. */
|
|
139
139
|
tz?: string;
|
|
140
140
|
}
|
|
141
141
|
/** What the hub assumed for a query (order, limit, time zone, what each time variable meant), so it can be said back. */
|
|
@@ -243,6 +243,28 @@ export interface TaskCard {
|
|
|
243
243
|
canDrop: boolean;
|
|
244
244
|
canEdit: boolean;
|
|
245
245
|
} | null;
|
|
246
|
+
/**
|
|
247
|
+
* Set for a task given to a role on the business map rather than a person (an agent's or a
|
|
248
|
+
* stage's): everyone in the role sees it until one of them takes it. `queued` while nobody has;
|
|
249
|
+
* `takenBy` once someone has; `mayTake` when this token's owner may take it with take(). Null or
|
|
250
|
+
* absent for every other card.
|
|
251
|
+
*/
|
|
252
|
+
role?: {
|
|
253
|
+
jobId: number;
|
|
254
|
+
slug: string | null;
|
|
255
|
+
title: string | null;
|
|
256
|
+
queued: boolean;
|
|
257
|
+
takenBy: TaskPerson | null;
|
|
258
|
+
/** Nobody took it in 4 business hours, so it went to the person responsible for the role. */
|
|
259
|
+
unclaimed?: boolean;
|
|
260
|
+
/** While it waits: when it goes to the person responsible if nobody takes it, and that as a sentence. */
|
|
261
|
+
goesTo?: {
|
|
262
|
+
at: string;
|
|
263
|
+
words: string;
|
|
264
|
+
} | null;
|
|
265
|
+
inRole: boolean;
|
|
266
|
+
mayTake: boolean;
|
|
267
|
+
} | null;
|
|
246
268
|
}
|
|
247
269
|
/** A card's one-tap action, by name (the hub page behind the card runs it). */
|
|
248
270
|
export type TaskCardAction = {
|
|
@@ -258,6 +280,11 @@ export type TaskCardAction = {
|
|
|
258
280
|
} | {
|
|
259
281
|
name: 'finish_task';
|
|
260
282
|
taskId: number;
|
|
283
|
+
}
|
|
284
|
+
/** A role's task nobody has taken yet: take() makes it yours. */
|
|
285
|
+
| {
|
|
286
|
+
name: 'take_task';
|
|
287
|
+
taskId: number;
|
|
261
288
|
} | {
|
|
262
289
|
name: 'approve_public_reply';
|
|
263
290
|
taskId: number;
|
|
@@ -337,6 +364,16 @@ export interface DecisionCard {
|
|
|
337
364
|
kind: 'person' | 'owners';
|
|
338
365
|
label: string;
|
|
339
366
|
};
|
|
367
|
+
/**
|
|
368
|
+
* A role's decision within the role's limits: anyone in `role` who can decide it may answer it, and
|
|
369
|
+
* the first answer decides it. `people` is how many may answer it now; `line` is the sentence the
|
|
370
|
+
* hub shows ("Any of you in Bookkeeping can answer."). Null or absent when only `decider` can.
|
|
371
|
+
*/
|
|
372
|
+
shared?: {
|
|
373
|
+
role: string;
|
|
374
|
+
people: number;
|
|
375
|
+
line: string;
|
|
376
|
+
} | null;
|
|
340
377
|
/** Work waits behind it: a yes lets it carry on. */
|
|
341
378
|
holdsWork: boolean;
|
|
342
379
|
/** What may be pressed now. Always empty for an account token: deciding is a person's tap in the hub. */
|
|
@@ -459,15 +496,49 @@ export interface TaskRecord {
|
|
|
459
496
|
handoffs: number;
|
|
460
497
|
};
|
|
461
498
|
}
|
|
462
|
-
/**
|
|
499
|
+
/**
|
|
500
|
+
* A task to give: to someone on the account by email, to a role on the business map by its key, or
|
|
501
|
+
* to the owner when both are left out. Send `forEmail` or `role`, never both.
|
|
502
|
+
*/
|
|
463
503
|
export interface GiveTask {
|
|
464
504
|
title: string;
|
|
465
505
|
detail?: string;
|
|
466
506
|
forEmail?: string;
|
|
507
|
+
/**
|
|
508
|
+
* A role on the business map, by its key (`slug` in `businessMap()`'s roles), instead of a person.
|
|
509
|
+
* Everyone in the role sees it until one of them takes it; a role with nobody in it who can act
|
|
510
|
+
* sends it to the owner. A role not on the map is refused (`serverCode: 'unknown_role'`, with the
|
|
511
|
+
* map's roles in the error's `roles`). Needs the business map (`business_map`).
|
|
512
|
+
*/
|
|
513
|
+
role?: string;
|
|
467
514
|
/** ISO time it is due. */
|
|
468
515
|
dueAt?: string;
|
|
469
516
|
/** A hub path the task points at, e.g. /contacts/people/... */
|
|
470
517
|
linkPath?: string;
|
|
518
|
+
/**
|
|
519
|
+
* Something that can't wait: a hot lead, a fault, a staff alert. It goes to the person's linked
|
|
520
|
+
* chats straight away, past their daily limit, and in their quiet hours only to the chat they chose
|
|
521
|
+
* to be woken in (or not until morning, if they chose none). At most five a day per person; urgent
|
|
522
|
+
* wears off a day after it is given. Leave it out for anything else.
|
|
523
|
+
*/
|
|
524
|
+
urgent?: boolean;
|
|
525
|
+
}
|
|
526
|
+
/** What `db.tasks.give()` answers. */
|
|
527
|
+
export interface GivenTask {
|
|
528
|
+
key: string;
|
|
529
|
+
id: number;
|
|
530
|
+
/** Who has it now: null only for a role's task still waiting for someone in the role to take it. */
|
|
531
|
+
holder: TaskPerson | null;
|
|
532
|
+
/** Whether the person it went to was emailed (the role's responsible person, for a role's task). */
|
|
533
|
+
emailed: boolean;
|
|
534
|
+
urgent: boolean;
|
|
535
|
+
/** Set when it was given to a role: `queued` while it waits in the role, false when the role had nobody and it went to the owner. */
|
|
536
|
+
role?: {
|
|
537
|
+
slug: string;
|
|
538
|
+
title: string;
|
|
539
|
+
queued: boolean;
|
|
540
|
+
};
|
|
541
|
+
note?: string;
|
|
471
542
|
}
|
|
472
543
|
/** A file or folder in the account's Files (the folders on its automation account: public/, private/, temp/). */
|
|
473
544
|
export interface FileEntry {
|
|
@@ -555,6 +626,11 @@ export interface AwesomateErrorDetails {
|
|
|
555
626
|
* unavailable when the hub said (serverCode crm_maintenance: the account's Contacts is being moved).
|
|
556
627
|
*/
|
|
557
628
|
retryAfter?: number;
|
|
629
|
+
/** With unknown_role (giving a task to a role not on the business map): the map's roles, by key and name. */
|
|
630
|
+
roles?: Array<{
|
|
631
|
+
slug: string;
|
|
632
|
+
title: string;
|
|
633
|
+
}>;
|
|
558
634
|
}
|
|
559
635
|
/**
|
|
560
636
|
* Every failure from the hub. `message` is for you, the developer; `personMessage`, when the hub
|
|
@@ -592,6 +668,11 @@ export declare class AwesomateError extends Error {
|
|
|
592
668
|
* being moved). Wait at least that long, then try once more; retrying at once only meets the same answer.
|
|
593
669
|
*/
|
|
594
670
|
readonly retryAfter?: number;
|
|
671
|
+
/** With serverCode unknown_role (`tasks.give({ role })` naming a role not on the business map): the map's roles, by key and name. */
|
|
672
|
+
readonly roles?: Array<{
|
|
673
|
+
slug: string;
|
|
674
|
+
title: string;
|
|
675
|
+
}>;
|
|
595
676
|
constructor(
|
|
596
677
|
/** Why it failed. */
|
|
597
678
|
code: ErrorCode, message: string,
|
|
@@ -722,6 +803,7 @@ export declare class AwesomateClient {
|
|
|
722
803
|
*
|
|
723
804
|
* @example
|
|
724
805
|
* await db.tasks.give({ title: 'Call Sam back about the leak', forEmail: 'jo@brightwater.example', dueAt: '2026-10-06T09:00:00+11:00' });
|
|
806
|
+
* await db.tasks.give({ title: 'Hot lead: Sam wants a quote today', forEmail: 'jo@brightwater.example', urgent: true });
|
|
725
807
|
*/
|
|
726
808
|
readonly tasks: {
|
|
727
809
|
/** The board: waiting now, put off, with someone else, recently decided. `all` shows everyone's, not only yours. hosting:read. */
|
|
@@ -745,15 +827,27 @@ export declare class AwesomateClient {
|
|
|
745
827
|
decisionRecord: (taskId: number | string) => Promise<TaskRecord & {
|
|
746
828
|
kind: "decision";
|
|
747
829
|
}>;
|
|
748
|
-
/**
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
|
|
830
|
+
/**
|
|
831
|
+
* Give a task. The person gets it on their board, an email when they are not the one giving it,
|
|
832
|
+
* and a card in any chat they linked, within their quiet hours and daily limit (`urgent` goes
|
|
833
|
+
* straight away). `urgent` in the result says whether it went as urgent: a person's sixth urgent
|
|
834
|
+
* task in a day goes as an ordinary one, and `note` says so. hosting:manage.
|
|
835
|
+
*/
|
|
836
|
+
give: (task: GiveTask) => Promise<GivenTask>;
|
|
837
|
+
/**
|
|
838
|
+
* Change a given task: whoever wrote it, or the owner. `urgent: false` takes urgent off; a task can
|
|
839
|
+
* only be marked urgent when it is given. hosting:manage.
|
|
840
|
+
*/
|
|
841
|
+
update: (id: number | string, patch: Partial<Omit<GiveTask, "forEmail" | "urgent">> & {
|
|
842
|
+
urgent?: false;
|
|
843
|
+
}) => Promise<void>;
|
|
844
|
+
/**
|
|
845
|
+
* Take a role's task (a card with `role.mayTake`): it becomes the owner's, and everyone else in
|
|
846
|
+
* the role sees who took it. Only someone in the role can take it, so this works for the owner
|
|
847
|
+
* only when they are in that role (serverCode `not_in_role` otherwise). Someone who got there
|
|
848
|
+
* first answers `taken`, with their name in the message. hosting:manage.
|
|
849
|
+
*/
|
|
850
|
+
take: (id: number | string) => Promise<void>;
|
|
757
851
|
/** Mark a given task done: the person who has it, whoever wrote it, or the owner. hosting:manage. */
|
|
758
852
|
done: (id: number | string) => Promise<void>;
|
|
759
853
|
/** Take a given task off the board without doing it: whoever wrote it, or the owner. hosting:manage. */
|
|
@@ -1022,6 +1116,27 @@ export declare class AwesomateClient {
|
|
|
1022
1116
|
addTags: (id: string, tags: string[]) => Promise<ContactTagsResult>;
|
|
1023
1117
|
/** Take tags off a person, up to 20 a call. Answers how many they had. */
|
|
1024
1118
|
removeTags: (id: string, tags: string[]) => Promise<ContactTagsResult>;
|
|
1119
|
+
/**
|
|
1120
|
+
* Record that the person asked to stop getting email, by reply, phone, in person or in writing
|
|
1121
|
+
* (`how`), at the time they asked (`askedAt`, default now, at most 30 days back). With no `list`
|
|
1122
|
+
* it stops every email, booking confirmations and other service emails included; with a list's
|
|
1123
|
+
* key, that list only. Recorded as the person's own withdrawal, so a later import never puts
|
|
1124
|
+
* them back. Answers `changed: false` when it was already recorded. The law gives 5 business
|
|
1125
|
+
* days from when they asked. A person with no email address is refused (validation).
|
|
1126
|
+
*/
|
|
1127
|
+
unsubscribe: (id: string, options: {
|
|
1128
|
+
how: ContactStopHow;
|
|
1129
|
+
list?: string;
|
|
1130
|
+
askedAt?: Date | string;
|
|
1131
|
+
}) => Promise<ContactUnsubscribeResult>;
|
|
1132
|
+
/**
|
|
1133
|
+
* Prepare an erasure, for when someone asks for their details to be deleted. Answers what
|
|
1134
|
+
* erasing the person would take (`counts`) and `finishInHub`, the hub link where an Owner of the
|
|
1135
|
+
* business finishes it, signed in as themselves, by typing the person's email address. Nothing
|
|
1136
|
+
* is erased here: no token can erase anyone, because an erasure can't be undone. Only an Owner's
|
|
1137
|
+
* token may prepare one (403 `owner_only`). Null when there is no such person.
|
|
1138
|
+
*/
|
|
1139
|
+
erasurePreview: (id: string) => Promise<ContactErasurePreview | null>;
|
|
1025
1140
|
/**
|
|
1026
1141
|
* Add a contact field. The hub makes its key from the label with a random part and answers it:
|
|
1027
1142
|
* use that key. Nothing here changes a field that exists. `ai_may_read` decides, once and now,
|
|
@@ -1151,6 +1266,18 @@ export declare class AwesomateClient {
|
|
|
1151
1266
|
get<K extends KindName>(kind: K, id: string, options?: {
|
|
1152
1267
|
tz?: string;
|
|
1153
1268
|
}): Promise<RowOf<K> | null>;
|
|
1269
|
+
/**
|
|
1270
|
+
* What points at one row: for each link from another kind (a job's customer, a memo's job), how
|
|
1271
|
+
* many rows point here and the newest of them (`limit`, default 20, at most 100), read as query()
|
|
1272
|
+
* reads that kind. Null when there is no such row. The account's token, crm:read.
|
|
1273
|
+
*
|
|
1274
|
+
* @example
|
|
1275
|
+
* const related = await db.related('contact', contactId);
|
|
1276
|
+
* for (const r of related ?? []) console.log(r.kind, r.link, r.count);
|
|
1277
|
+
*/
|
|
1278
|
+
related(kind: KindName, id: string, options?: {
|
|
1279
|
+
limit?: number;
|
|
1280
|
+
}): Promise<RelatedRows[] | null>;
|
|
1154
1281
|
/** The app kinds this account has defined. The account's token, crm:read, every plan; never an app key. */
|
|
1155
1282
|
kinds(): Promise<KindDescription[]>;
|
|
1156
1283
|
/**
|
|
@@ -1210,6 +1337,18 @@ export declare class AwesomateClient {
|
|
|
1210
1337
|
write<K extends KindName>(kind: K, data: Partial<RowOf<K>> | Record<string, unknown>, options?: WriteOptions): Promise<string>;
|
|
1211
1338
|
/** Archive a record: it leaves every read and is kept for a restore. Needs what write() needs. */
|
|
1212
1339
|
archive<K extends KindName>(kind: K, id: string): Promise<void>;
|
|
1340
|
+
/**
|
|
1341
|
+
* Create or change the record that mirrors one in another system, found by that system's name and
|
|
1342
|
+
* its id there (`ref.system`, lower case like `xero`; `ref.externalId`), so a sync run twice changes
|
|
1343
|
+
* the record instead of making a second one. The same checks as write(). A record with that id that
|
|
1344
|
+
* was archived is refused (`conflict`): a sync never undoes an archive or makes a second copy. Companies
|
|
1345
|
+
* are refused here: use companies.upsert(), which matches by ABN and name. The account's token only
|
|
1346
|
+
* (never an app key), crm:write, Support Plus and above.
|
|
1347
|
+
*
|
|
1348
|
+
* @example
|
|
1349
|
+
* const { id, created } = await db.upsertByRef('job', { system: 'servicem8', externalId: 'JOB-0042' }, { title: 'Possum in the roof' }, { links: { customer: contactId } });
|
|
1350
|
+
*/
|
|
1351
|
+
upsertByRef<K extends KindName>(kind: K, ref: RecordRef, data?: Partial<RowOf<K>> | Record<string, unknown>, options?: Omit<WriteOptions, 'id'>): Promise<UpsertByRefResult>;
|
|
1213
1352
|
/** The saved queries on this account. crm:read, every plan: the account's token or an app key. */
|
|
1214
1353
|
queries(): Promise<SavedQueryDescription[]>;
|
|
1215
1354
|
/**
|
|
@@ -1266,6 +1405,26 @@ export declare class AwesomateClient {
|
|
|
1266
1405
|
* the business map on the account.
|
|
1267
1406
|
*/
|
|
1268
1407
|
businessMapRole(slug: string): Promise<BusinessMapRoleDetail>;
|
|
1408
|
+
/**
|
|
1409
|
+
* The business's KPIs: each a number with a target and someone responsible for it, with where it
|
|
1410
|
+
* sits, who answers for it, its light against the target for the last complete period, the period
|
|
1411
|
+
* so far, a trend of up to 12 periods and where its figure comes from. A person's own key reads only the KPIs
|
|
1412
|
+
* they would see in the hub. `period` reads every KPI by the week, month or quarter (never finer than
|
|
1413
|
+
* its own period); left out, each by its own. hosting:read, every plan; `available` is false, with a
|
|
1414
|
+
* `reason`, where the account has no KPIs to read.
|
|
1415
|
+
*/
|
|
1416
|
+
businessKpis(opts?: {
|
|
1417
|
+
period?: 'week' | 'month' | 'quarter';
|
|
1418
|
+
}): Promise<BusinessKpis>;
|
|
1419
|
+
/**
|
|
1420
|
+
* Add figures for the business's KPIs from your own tool or script: totals per day, week or month,
|
|
1421
|
+
* into the business's own Your numbers, where a KPI reads them by name. Up to 100 a call; a figure
|
|
1422
|
+
* sent again for the same period replaces the one before. Each figure name belongs to the first
|
|
1423
|
+
* source that sends it (`serverCode: 'figure_owned'` for another). Totals only: a label that looks
|
|
1424
|
+
* like an email address, phone number or web address is refused. knowledge:write, Support Plus and
|
|
1425
|
+
* above (`feature_unavailable` below that), and Your numbers switched on for the business.
|
|
1426
|
+
*/
|
|
1427
|
+
addFigures(input: AddFigures): Promise<FiguresAdded>;
|
|
1269
1428
|
/**
|
|
1270
1429
|
* The business map in its first shape, where a department is a `division`, a sub-department a
|
|
1271
1430
|
* `department` and a role a `job`. hosting:read, the business map on the account.
|
|
@@ -1420,6 +1579,7 @@ export interface BusinessMapRole {
|
|
|
1420
1579
|
headsDepartment: boolean;
|
|
1421
1580
|
/** Runs its sub-department: the person responsible for it, and for its KPIs. */
|
|
1422
1581
|
headsSubDepartment: boolean;
|
|
1582
|
+
/** The sub-department's key (see BusinessMapSubDepartment.no): match it there for the name, never show it. */
|
|
1423
1583
|
subDepartmentNo: number | null;
|
|
1424
1584
|
reportsTo: {
|
|
1425
1585
|
id: number;
|
|
@@ -1436,17 +1596,91 @@ export interface BusinessMapRole {
|
|
|
1436
1596
|
level: BusinessMapLevel;
|
|
1437
1597
|
exceptions: string | null;
|
|
1438
1598
|
}>;
|
|
1599
|
+
/**
|
|
1600
|
+
* Its helpers. `look` says what the hub draws: an Awesomate agent's picture URL, a full link to the
|
|
1601
|
+
* hub (null: the hub draws its initials; always null when the account does not have Agents) and
|
|
1602
|
+
* whether it is on (null when that could not be read), an n8n agent's icon, an automation's bolt.
|
|
1603
|
+
*/
|
|
1439
1604
|
helpers: Array<BusinessMapHelper & {
|
|
1440
1605
|
id: number;
|
|
1441
1606
|
supervisor: string;
|
|
1442
1607
|
level: BusinessMapLevel | null;
|
|
1443
1608
|
exceptions: string | null;
|
|
1444
1609
|
minutesSavedPerRun: number | null;
|
|
1610
|
+
look: {
|
|
1611
|
+
kind: 'awesomate' | 'n8n' | 'automation' | 'external';
|
|
1612
|
+
picture: string | null;
|
|
1613
|
+
state: 'on' | 'off' | null;
|
|
1614
|
+
};
|
|
1445
1615
|
}>;
|
|
1446
1616
|
/** The tag this role's procedures carry in 1Brain, such as 'job:quotes'. The map keeps no procedure text. */
|
|
1447
1617
|
proceduresTag: string;
|
|
1448
1618
|
/** Quarterly priorities on this role, every quarter. */
|
|
1449
1619
|
priorities: BusinessMapPriority[];
|
|
1620
|
+
/** Its responsibilities as processes, in the same order: what writes each down and who does it. */
|
|
1621
|
+
processes: BusinessMapProcess[];
|
|
1622
|
+
/** How many processes it has, how many are written down, how many automated. */
|
|
1623
|
+
progress: {
|
|
1624
|
+
processes: number;
|
|
1625
|
+
written: number;
|
|
1626
|
+
automated: number;
|
|
1627
|
+
};
|
|
1628
|
+
/** Ready to hand over: the owner is still responsible for it and every process is written down or automated. */
|
|
1629
|
+
ready: boolean;
|
|
1630
|
+
/** The one line the map shows for it ("Booking reminders failed twice this week"), or null. */
|
|
1631
|
+
flag: string | null;
|
|
1632
|
+
}
|
|
1633
|
+
/** The one next step the map suggests, with its button's words and what the button does. */
|
|
1634
|
+
export interface BusinessMapNextStep {
|
|
1635
|
+
title: string;
|
|
1636
|
+
detail: string;
|
|
1637
|
+
button: string;
|
|
1638
|
+
action: {
|
|
1639
|
+
kind: 'hand_over';
|
|
1640
|
+
roleId: number;
|
|
1641
|
+
roleSlug: string;
|
|
1642
|
+
membershipId: number | null;
|
|
1643
|
+
} | {
|
|
1644
|
+
kind: 'open_role';
|
|
1645
|
+
roleId: number;
|
|
1646
|
+
roleSlug: string;
|
|
1647
|
+
} | {
|
|
1648
|
+
kind: 'link';
|
|
1649
|
+
path: string;
|
|
1650
|
+
} | {
|
|
1651
|
+
kind: 'add_role';
|
|
1652
|
+
departmentNo: number;
|
|
1653
|
+
} | {
|
|
1654
|
+
kind: 'edit_path';
|
|
1655
|
+
} | {
|
|
1656
|
+
kind: 'place_helpers';
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* One of a role's processes (a responsibility). Written down: a 1Brain page on the role's own list of
|
|
1661
|
+
* 1Brain systems is linked to it. Automated: an agent or automation on the role does it, at any level.
|
|
1662
|
+
*/
|
|
1663
|
+
export interface BusinessMapProcess {
|
|
1664
|
+
text: string;
|
|
1665
|
+
level: BusinessMapLevel;
|
|
1666
|
+
/** The 1Brain page that writes it down, by its ids and title; null when it is not written down yet. */
|
|
1667
|
+
procedure: {
|
|
1668
|
+
accountId: number;
|
|
1669
|
+
itemId: number;
|
|
1670
|
+
title: string;
|
|
1671
|
+
} | null;
|
|
1672
|
+
/** Who does it: the role's holder, or a helper on the role. */
|
|
1673
|
+
doneBy: {
|
|
1674
|
+
kind: 'holder';
|
|
1675
|
+
name: string | null;
|
|
1676
|
+
} | {
|
|
1677
|
+
kind: 'helper';
|
|
1678
|
+
helperId: number;
|
|
1679
|
+
label: string;
|
|
1680
|
+
helperKind: BusinessMapHelper['kind'];
|
|
1681
|
+
};
|
|
1682
|
+
/** How far whoever does it goes alone, in words: a helper's level, else the role's limits, else "A person". */
|
|
1683
|
+
mayActAlone: string;
|
|
1450
1684
|
}
|
|
1451
1685
|
/** A quarterly priority on a role: one of the few things it must move this quarter. */
|
|
1452
1686
|
export interface BusinessMapPriority {
|
|
@@ -1465,6 +1699,8 @@ export interface BusinessMapPathStep {
|
|
|
1465
1699
|
position: number;
|
|
1466
1700
|
label: string;
|
|
1467
1701
|
departmentNo: 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
1702
|
+
/** The department's plain name ("Sales"): what people read. */
|
|
1703
|
+
name: string;
|
|
1468
1704
|
verb: string;
|
|
1469
1705
|
/** The role that looks after the step, when the owner named one. */
|
|
1470
1706
|
role: {
|
|
@@ -1480,11 +1716,25 @@ export interface BusinessMapPathStep {
|
|
|
1480
1716
|
/** Where this step hands over to the next, in the owner's words. */
|
|
1481
1717
|
handoffRule: string | null;
|
|
1482
1718
|
}
|
|
1483
|
-
/**
|
|
1719
|
+
/**
|
|
1720
|
+
* A sub-department and who runs it: the holder of the role that heads it, else whoever runs the
|
|
1721
|
+
* department (byDefault). Each business names, orders and adds its own, so they come in the
|
|
1722
|
+
* business's order and by its names.
|
|
1723
|
+
*/
|
|
1484
1724
|
export interface BusinessMapSubDepartment {
|
|
1725
|
+
/**
|
|
1726
|
+
* A key, never shown to people: 1 to 21 for a standard sub-department, 1001 and up for one the
|
|
1727
|
+
* owner added. A role's subDepartmentNo is this key.
|
|
1728
|
+
*/
|
|
1485
1729
|
no: number;
|
|
1730
|
+
/** The business's name for it: show this. */
|
|
1486
1731
|
name: string;
|
|
1487
|
-
|
|
1732
|
+
/** The standard name, or null for one the owner added. Differs from name when the owner renamed it. */
|
|
1733
|
+
standardName: string | null;
|
|
1734
|
+
/** The owner added it. */
|
|
1735
|
+
custom: boolean;
|
|
1736
|
+
/** What a standard one covers; null for one the owner added. */
|
|
1737
|
+
gloss: string | null;
|
|
1488
1738
|
runBy: {
|
|
1489
1739
|
name: string;
|
|
1490
1740
|
byDefault: boolean;
|
|
@@ -1513,6 +1763,7 @@ export interface BusinessMapDepartment {
|
|
|
1513
1763
|
helpers: Array<BusinessMapHelper & {
|
|
1514
1764
|
placedBy: string;
|
|
1515
1765
|
}>;
|
|
1766
|
+
/** In the business's order, by its names. */
|
|
1516
1767
|
subDepartments: BusinessMapSubDepartment[];
|
|
1517
1768
|
ideas: Array<{
|
|
1518
1769
|
label: string;
|
|
@@ -1527,12 +1778,160 @@ export interface BusinessMapDepartment {
|
|
|
1527
1778
|
question: string;
|
|
1528
1779
|
/** 1Brain Departments whose procedures belong in this department. */
|
|
1529
1780
|
oneBrainDepartments: string[];
|
|
1530
|
-
/** People on the map who hold no role yet. They sit in
|
|
1781
|
+
/** People on the map who hold no role yet. They sit in Team and systems (department 1) for display; empty for every other department. */
|
|
1531
1782
|
noRoleYet: Array<{
|
|
1532
1783
|
id: number;
|
|
1533
1784
|
name: string;
|
|
1534
1785
|
}>;
|
|
1535
1786
|
}
|
|
1787
|
+
/**
|
|
1788
|
+
* A KPI's light. Say its word beside any colour: Act now, Watch, On track, Late, Not a KPI yet.
|
|
1789
|
+
* `not_due` is no light at all: the KPI is new and its first figure is not due yet, so it is never Late
|
|
1790
|
+
* before then; `lightWord` says when ("First figure due Mon 19 Oct") and `firstDue` what brings it.
|
|
1791
|
+
*/
|
|
1792
|
+
export type KpiLight = 'act_now' | 'watch' | 'on_track' | 'late' | 'no_target' | 'not_due';
|
|
1793
|
+
/** One period of a KPI's figures: first and last day (YYYY-MM-DD), a short label, its figure and target. */
|
|
1794
|
+
export interface KpiPeriodFigure {
|
|
1795
|
+
from: string;
|
|
1796
|
+
to: string;
|
|
1797
|
+
label: string;
|
|
1798
|
+
/** null: no figure for that period. */
|
|
1799
|
+
figure: number | null;
|
|
1800
|
+
target: number | null;
|
|
1801
|
+
}
|
|
1802
|
+
/** One KPI, as businessKpis() returns it. */
|
|
1803
|
+
export interface BusinessKpi {
|
|
1804
|
+
id: string;
|
|
1805
|
+
/** The hub's own KPIs only: fixed when it is added. */
|
|
1806
|
+
slug?: string;
|
|
1807
|
+
name: string;
|
|
1808
|
+
/** false: it points at a place the map no longer has. */
|
|
1809
|
+
onMap: boolean;
|
|
1810
|
+
place: {
|
|
1811
|
+
level: 'department' | 'sub_department' | 'role' | null;
|
|
1812
|
+
department: number | null;
|
|
1813
|
+
subDepartment: number | null;
|
|
1814
|
+
role: string | null;
|
|
1815
|
+
roleTitle: string | null;
|
|
1816
|
+
};
|
|
1817
|
+
/** Who answers for it now; forNow: nobody holds it, so it falls to whoever runs the department. */
|
|
1818
|
+
responsible: {
|
|
1819
|
+
name: string;
|
|
1820
|
+
forNow: boolean;
|
|
1821
|
+
} | null;
|
|
1822
|
+
light: KpiLight;
|
|
1823
|
+
lightWord: string;
|
|
1824
|
+
/** The judged period's figure and target (the last complete period). */
|
|
1825
|
+
figure: number | null;
|
|
1826
|
+
target: number | null;
|
|
1827
|
+
period: {
|
|
1828
|
+
from: string;
|
|
1829
|
+
to: string;
|
|
1830
|
+
} | null;
|
|
1831
|
+
kind: 'lead' | 'result' | null;
|
|
1832
|
+
critical: boolean;
|
|
1833
|
+
format: string | null;
|
|
1834
|
+
/** The rest is on the hub's own KPIs, not on those kept in Reports. */
|
|
1835
|
+
frequency?: 'daily' | 'weekly' | 'monthly';
|
|
1836
|
+
direction?: 'up' | 'down';
|
|
1837
|
+
aggregation?: 'sum' | 'mean' | 'last';
|
|
1838
|
+
/** The target per its own period, as typed: 40 for "40 a week". null: not a KPI yet. */
|
|
1839
|
+
targetPerPeriod?: number | null;
|
|
1840
|
+
targetWords?: string | null;
|
|
1841
|
+
watchPct?: number;
|
|
1842
|
+
source?: 'contacts' | 'collected' | 'entered' | 'other';
|
|
1843
|
+
/** "Entered weekly by Dave, from a task". */
|
|
1844
|
+
sourceLine?: string;
|
|
1845
|
+
sharedEveryone?: boolean;
|
|
1846
|
+
/** Why the reader sees it, in words. */
|
|
1847
|
+
because?: string[];
|
|
1848
|
+
/** The period so far: its figure and the target to date. Never lit. */
|
|
1849
|
+
soFar?: {
|
|
1850
|
+
period: {
|
|
1851
|
+
start: string;
|
|
1852
|
+
end: string;
|
|
1853
|
+
};
|
|
1854
|
+
value: number | null;
|
|
1855
|
+
targetToDate: number | null;
|
|
1856
|
+
};
|
|
1857
|
+
/** Up to 12 complete periods before this one, oldest first, starting where tracking began: shorter, or empty, for a new KPI. */
|
|
1858
|
+
trend?: KpiPeriodFigure[];
|
|
1859
|
+
/** "No figure since 6 Oct", "No figure yet", or null. */
|
|
1860
|
+
figureNote?: string | null;
|
|
1861
|
+
/** Set when the light is Late: since when, and what it needs in a sentence. */
|
|
1862
|
+
late?: {
|
|
1863
|
+
since: string | null;
|
|
1864
|
+
needs: string;
|
|
1865
|
+
task: null;
|
|
1866
|
+
} | null;
|
|
1867
|
+
/** Before last period's figure is due: when it is due. */
|
|
1868
|
+
dueNote?: string | null;
|
|
1869
|
+
/**
|
|
1870
|
+
* Set while the light is `not_due`: the day its first figure is due (YYYY-MM-DD), the words to show
|
|
1871
|
+
* ("First figure due Mon 19 Oct"), and what brings the figure ("No figure yet. Dave enters it each week,
|
|
1872
|
+
* from a task."). `arrived`: a figure for its first period is in already (entered before that period
|
|
1873
|
+
* ended), so `day` is the day it lights up, `words` read "Lights up Mon 19 Oct" and `note` says so.
|
|
1874
|
+
*/
|
|
1875
|
+
firstDue?: {
|
|
1876
|
+
day: string;
|
|
1877
|
+
words: string;
|
|
1878
|
+
note: string;
|
|
1879
|
+
arrived: boolean;
|
|
1880
|
+
} | null;
|
|
1881
|
+
}
|
|
1882
|
+
/** One figure for addFigures(): a total for a period, under a named figure a KPI can read. */
|
|
1883
|
+
export interface Figure {
|
|
1884
|
+
/** The named figure, two to four dotted parts in lower case: `xero.cash_received`. */
|
|
1885
|
+
key: string;
|
|
1886
|
+
/** Its name for people, when the key's last part does not say it well. */
|
|
1887
|
+
label?: string;
|
|
1888
|
+
unit: 'count' | 'money' | 'quantity';
|
|
1889
|
+
/** With money: a three-letter code, `AUD`. */
|
|
1890
|
+
currency?: string;
|
|
1891
|
+
/** How periods combine into a longer one: `sum` (the default), `mean`, or `last` for a balance or a rating. */
|
|
1892
|
+
aggregation?: 'sum' | 'mean' | 'last';
|
|
1893
|
+
grain: 'day' | 'week' | 'month';
|
|
1894
|
+
/** Any date in the period (`2026-10-08`), or an ISO time, read in the business's own time zone. Weeks start Monday. */
|
|
1895
|
+
period: string;
|
|
1896
|
+
value: number;
|
|
1897
|
+
}
|
|
1898
|
+
/** What addFigures() sends: where the figures come from, and the figures. */
|
|
1899
|
+
export interface AddFigures {
|
|
1900
|
+
/** The tool or script the figures come from, in a few plain words: `Xero`. */
|
|
1901
|
+
source: {
|
|
1902
|
+
name: string;
|
|
1903
|
+
};
|
|
1904
|
+
figures: Figure[];
|
|
1905
|
+
}
|
|
1906
|
+
/** What addFigures() answers: how many were added, and the Your numbers tables they went to. */
|
|
1907
|
+
export interface FiguresAdded {
|
|
1908
|
+
added: number;
|
|
1909
|
+
source: {
|
|
1910
|
+
name: string;
|
|
1911
|
+
slug: string;
|
|
1912
|
+
};
|
|
1913
|
+
/** One table per source and grain, `collected-<source>-<grain>`. */
|
|
1914
|
+
tables: Array<{
|
|
1915
|
+
slug: string;
|
|
1916
|
+
grain: 'day' | 'week' | 'month';
|
|
1917
|
+
figures: number;
|
|
1918
|
+
periods: number;
|
|
1919
|
+
}>;
|
|
1920
|
+
}
|
|
1921
|
+
/** The business's KPIs, as businessKpis() returns them. */
|
|
1922
|
+
export type BusinessKpis = {
|
|
1923
|
+
available: false;
|
|
1924
|
+
reason: 'not_connected' | 'no_reports' | 'unreadable';
|
|
1925
|
+
} | {
|
|
1926
|
+
available: true;
|
|
1927
|
+
/** Where they are kept: the hub's own until the account links Reports, then Reports'. */
|
|
1928
|
+
store: 'hub' | 'buddzee';
|
|
1929
|
+
truncated: boolean;
|
|
1930
|
+
period?: 'week' | 'month' | 'quarter' | null;
|
|
1931
|
+
/** The hub's own: whether figures could be read from Your numbers. */
|
|
1932
|
+
figures?: 'ok' | 'off' | 'no_workspace' | 'not_configured' | 'unreadable';
|
|
1933
|
+
kpis: BusinessKpi[];
|
|
1934
|
+
};
|
|
1536
1935
|
/** The business map, as businessMap() returns it. No email addresses. */
|
|
1537
1936
|
export interface BusinessMap {
|
|
1538
1937
|
version: 2;
|
|
@@ -1591,6 +1990,26 @@ export interface BusinessMap {
|
|
|
1591
1990
|
departmentsWithHelpers: number;
|
|
1592
1991
|
roles: number;
|
|
1593
1992
|
};
|
|
1993
|
+
/**
|
|
1994
|
+
* How far the business has got: the roles the owner is still responsible for (their own included) of
|
|
1995
|
+
* every role, and the processes written down and automated, each of every process.
|
|
1996
|
+
*/
|
|
1997
|
+
progress: {
|
|
1998
|
+
rolesYouHold: {
|
|
1999
|
+
held: number;
|
|
2000
|
+
of: number;
|
|
2001
|
+
};
|
|
2002
|
+
written: {
|
|
2003
|
+
done: number;
|
|
2004
|
+
of: number;
|
|
2005
|
+
};
|
|
2006
|
+
automated: {
|
|
2007
|
+
done: number;
|
|
2008
|
+
of: number;
|
|
2009
|
+
};
|
|
2010
|
+
};
|
|
2011
|
+
/** The one next step: a ready role to hand over first, else the most important gap; null when there is none. */
|
|
2012
|
+
nextStep: BusinessMapNextStep | null;
|
|
1594
2013
|
/** Sources that could not be read just now: a missing helper may simply not have been read. */
|
|
1595
2014
|
unavailable: string[];
|
|
1596
2015
|
}
|
|
@@ -1653,7 +2072,12 @@ export interface BusinessMapRoleDetail {
|
|
|
1653
2072
|
levelLabel: string;
|
|
1654
2073
|
exceptions: string | null;
|
|
1655
2074
|
}>;
|
|
2075
|
+
/** Each responsibility as a process, in the same order. */
|
|
2076
|
+
processes: BusinessMapProcess[];
|
|
2077
|
+
progress: BusinessMapRole['progress'];
|
|
2078
|
+
/** `id` is what a process's `doneBy.helperId` and a proposal's `doneByHelperId` name. */
|
|
1656
2079
|
helpers: Array<{
|
|
2080
|
+
id: number;
|
|
1657
2081
|
kind: BusinessMapHelper['kind'];
|
|
1658
2082
|
ref: string;
|
|
1659
2083
|
label: string;
|
|
@@ -1662,6 +2086,7 @@ export interface BusinessMapRoleDetail {
|
|
|
1662
2086
|
levelLabel: string | null;
|
|
1663
2087
|
exceptions: string | null;
|
|
1664
2088
|
instructionLine: string;
|
|
2089
|
+
look: BusinessMapRole['helpers'][number]['look'];
|
|
1665
2090
|
}>;
|
|
1666
2091
|
}
|
|
1667
2092
|
/**
|
|
@@ -1731,11 +2156,13 @@ export interface BusinessMapDivision {
|
|
|
1731
2156
|
helpers: Array<BusinessMapHelper & {
|
|
1732
2157
|
placedBy: string;
|
|
1733
2158
|
}>;
|
|
1734
|
-
/** The sub-departments. */
|
|
2159
|
+
/** The sub-departments, in the business's order: standardName and custom as on BusinessMapSubDepartment. */
|
|
1735
2160
|
departments: Array<{
|
|
1736
2161
|
no: number;
|
|
1737
2162
|
name: string;
|
|
1738
|
-
|
|
2163
|
+
standardName?: string | null;
|
|
2164
|
+
custom?: boolean;
|
|
2165
|
+
gloss: string | null;
|
|
1739
2166
|
runBy: {
|
|
1740
2167
|
name: string;
|
|
1741
2168
|
byDefault: boolean;
|
|
@@ -1930,6 +2357,19 @@ export interface WriteOptions {
|
|
|
1930
2357
|
/** Set a link by its key ('<id>'), or end it (null). */
|
|
1931
2358
|
links?: Record<string, string | null>;
|
|
1932
2359
|
}
|
|
2360
|
+
/** Which record in another system a record mirrors, for upsertByRef(). */
|
|
2361
|
+
export interface RecordRef {
|
|
2362
|
+
/** That system's name, lower case: letters, digits, `_`, `.` or `-`, at most 40 characters (`xero`, `shopify`). */
|
|
2363
|
+
system: string;
|
|
2364
|
+
/** The record's id in that system, 1 to 200 characters. */
|
|
2365
|
+
externalId: string;
|
|
2366
|
+
}
|
|
2367
|
+
/** What upsertByRef() did. */
|
|
2368
|
+
export interface UpsertByRefResult {
|
|
2369
|
+
id: string;
|
|
2370
|
+
/** True when the record was made; false when the one with that id changed. */
|
|
2371
|
+
created: boolean;
|
|
2372
|
+
}
|
|
1933
2373
|
/** The type of a saved query's or recipe's parameter. */
|
|
1934
2374
|
export type ParamType = 'text' | 'number' | 'date' | 'datetime' | 'boolean' | 'uuid' | 'text_list' | 'number_list';
|
|
1935
2375
|
/** One parameter of a saved query or recipe. */
|
|
@@ -2101,7 +2541,7 @@ export interface Schema {
|
|
|
2101
2541
|
max_limit: number;
|
|
2102
2542
|
statement_timeout_ms: number;
|
|
2103
2543
|
};
|
|
2104
|
-
/** With the account's token: the time zone dates are read in unless a query says otherwise. */
|
|
2544
|
+
/** With the account's token: the time zone dates are read in unless a query says otherwise (the business's own, Sydney if none is set). */
|
|
2105
2545
|
default_timezone?: string;
|
|
2106
2546
|
/** With an app key: whether it can only read or can also write. */
|
|
2107
2547
|
access?: 'read' | 'write';
|
|
@@ -2351,6 +2791,118 @@ export interface ContactTagsResult {
|
|
|
2351
2791
|
/** Tags taken off them. */
|
|
2352
2792
|
removed: number;
|
|
2353
2793
|
}
|
|
2794
|
+
/** One link pointing at a row, from related(). */
|
|
2795
|
+
export interface RelatedRows {
|
|
2796
|
+
/** The kind the link starts from. */
|
|
2797
|
+
kind: string;
|
|
2798
|
+
/** That kind's name as the owner wrote it, plural ("Jobs"): show this beside the label. */
|
|
2799
|
+
kind_label: string;
|
|
2800
|
+
/** The link's key on that kind (its rows carry <link>_id). A company's people come as kind contact, link company. */
|
|
2801
|
+
link: string;
|
|
2802
|
+
/** What the link is called from this side, as its maker named it ("has" when they did not). */
|
|
2803
|
+
label: string;
|
|
2804
|
+
/** True when this link could not be read just now: count and rows are empty, never zero. */
|
|
2805
|
+
unavailable?: boolean;
|
|
2806
|
+
/** Fields and sections of this kind your role cannot see, when any were left out. */
|
|
2807
|
+
not_shown_to_you?: NotShownToYou;
|
|
2808
|
+
/** How many rows point here, up to 10,000 (count_capped past it). */
|
|
2809
|
+
count: number;
|
|
2810
|
+
count_capped: boolean;
|
|
2811
|
+
/** The newest of them, only columns query() would show. */
|
|
2812
|
+
rows: Array<Record<string, unknown>>;
|
|
2813
|
+
/** Pass to query() with where { <link>_id: id } and after, for more. */
|
|
2814
|
+
next: string | null;
|
|
2815
|
+
}
|
|
2816
|
+
/** How a person asked to stop getting email, for contacts.unsubscribe(). */
|
|
2817
|
+
export type ContactStopHow = 'reply' | 'phone' | 'in_person' | 'in_writing' | 'other';
|
|
2818
|
+
/** What contacts.unsubscribe() recorded. */
|
|
2819
|
+
export interface ContactUnsubscribeResult {
|
|
2820
|
+
id: string;
|
|
2821
|
+
/** False when it was already recorded. */
|
|
2822
|
+
changed: boolean;
|
|
2823
|
+
/** Whether email reaches them now. */
|
|
2824
|
+
email_status: ContactEmailStatus;
|
|
2825
|
+
/** The list they left, or null for every email. */
|
|
2826
|
+
list: string | null;
|
|
2827
|
+
how: ContactStopHow;
|
|
2828
|
+
/** When they asked, ISO 8601. */
|
|
2829
|
+
asked_at: string;
|
|
2830
|
+
}
|
|
2831
|
+
/** What erasing a person would take, from contacts.erasurePreview(): counts only, never values. */
|
|
2832
|
+
export interface ContactErasureCounts {
|
|
2833
|
+
/** Their email addresses and phone numbers. */
|
|
2834
|
+
email_addresses: number;
|
|
2835
|
+
phone_numbers: number;
|
|
2836
|
+
/** Of their numbers, those someone else also holds: texts to them stop for that person too. */
|
|
2837
|
+
phone_numbers_shared: number;
|
|
2838
|
+
/** Details on their page with a value: name, company, phone, time zone and the owner's fields. */
|
|
2839
|
+
fields: number;
|
|
2840
|
+
tags: number;
|
|
2841
|
+
/** Email lists they are on. */
|
|
2842
|
+
lists: number;
|
|
2843
|
+
/** Their consent records with an IP address or browser: the records stay as proof, those details go. */
|
|
2844
|
+
consent_ip_details: number;
|
|
2845
|
+
/** Emails sent to them, and their opens and clicks. */
|
|
2846
|
+
emails_sent: number;
|
|
2847
|
+
opens_and_clicks: number;
|
|
2848
|
+
series_runs: number;
|
|
2849
|
+
/** Calls with them, and calls from their numbers that named nobody (a shared line's among them). */
|
|
2850
|
+
calls: number;
|
|
2851
|
+
calls_shared_number: number;
|
|
2852
|
+
/** What the agent remembered about them (0 or 1). */
|
|
2853
|
+
call_memory: number;
|
|
2854
|
+
/** Bookings: the answers they gave go, the times stay. */
|
|
2855
|
+
bookings: number;
|
|
2856
|
+
/** Support tickets that are theirs, and how each was found (a ticket can be found more than one way). */
|
|
2857
|
+
tickets: number;
|
|
2858
|
+
tickets_by_link: number;
|
|
2859
|
+
tickets_by_email: number;
|
|
2860
|
+
tickets_by_number: number;
|
|
2861
|
+
/** Someone else's tickets that carry their address or number: only that comes off. */
|
|
2862
|
+
tickets_of_someone_else: number;
|
|
2863
|
+
/** Tickets from a number someone else also holds: left alone. */
|
|
2864
|
+
tickets_shared_number: number;
|
|
2865
|
+
/** Their tickets that someone else raised: that person's own address, number and name stay. */
|
|
2866
|
+
tickets_customer_kept: number;
|
|
2867
|
+
/** Messages they wrote, their attachments, emails from them held as suspect, and stored raw copies. */
|
|
2868
|
+
messages: number;
|
|
2869
|
+
/** Customers' messages on their tickets that are someone else's, or that can't be told to be theirs: they stay. */
|
|
2870
|
+
messages_not_theirs: number;
|
|
2871
|
+
attachments: number;
|
|
2872
|
+
quarantined_emails: number;
|
|
2873
|
+
raw_emails: number;
|
|
2874
|
+
/** Stored emails also filed on someone else's record: kept for it. */
|
|
2875
|
+
raw_emails_shared: number;
|
|
2876
|
+
/** Other records linked to them, by kind; the links end and the records keep their own fields. */
|
|
2877
|
+
linked_records: Array<{
|
|
2878
|
+
kind: string;
|
|
2879
|
+
label: string;
|
|
2880
|
+
records: number;
|
|
2881
|
+
required: number;
|
|
2882
|
+
}>;
|
|
2883
|
+
/** Of those, records that must have a person and will need a new one before their next change. */
|
|
2884
|
+
linked_required: number;
|
|
2885
|
+
/** Their sign-in to the account's apps, and sign-in links sent to them. */
|
|
2886
|
+
app_sign_ins: number;
|
|
2887
|
+
/** Other sign-in addresses linked to them, blocked with theirs. */
|
|
2888
|
+
app_addresses_blocked: number;
|
|
2889
|
+
sign_in_links: number;
|
|
2890
|
+
/** Their rows in past imports. */
|
|
2891
|
+
import_rows: number;
|
|
2892
|
+
}
|
|
2893
|
+
/** What contacts.erasurePreview() answers. Nothing has been erased. */
|
|
2894
|
+
export interface ContactErasurePreview {
|
|
2895
|
+
/** The person's id, and whether they were removed from Contacts. Never their name or address: the Owner sees who it is in the hub. */
|
|
2896
|
+
contact: {
|
|
2897
|
+
id: string;
|
|
2898
|
+
removed: boolean;
|
|
2899
|
+
};
|
|
2900
|
+
counts: ContactErasureCounts;
|
|
2901
|
+
/** Where an Owner finishes it in the hub, signed in as themselves. Null when it can't be finished there on this account yet: pass on `note`. */
|
|
2902
|
+
finishInHub: string | null;
|
|
2903
|
+
/** What happens next, in a sentence to pass on. */
|
|
2904
|
+
note: string;
|
|
2905
|
+
}
|
|
2354
2906
|
/** The kinds of contact field contacts.createField() makes. */
|
|
2355
2907
|
export type ContactFieldType = 'text' | 'long_text' | 'number' | 'money' | 'date' | 'yes_no' | 'choice' | 'choices';
|
|
2356
2908
|
/** What contacts.createField() takes. */
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* Docs: https://hub.awesomate.ai/docs/sdk/
|
|
27
27
|
*/
|
|
28
28
|
/** This package's version, sent to the hub with every server call. */
|
|
29
|
-
export const VERSION = '0.
|
|
29
|
+
export const VERSION = '0.51.0';
|
|
30
30
|
const DEFAULT_BASE = 'https://hub.awesomate.ai';
|
|
31
31
|
/** Every record and contact id is a UUID; anything else can name no row. */
|
|
32
32
|
const RECORD_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -62,6 +62,8 @@ export class AwesomateError extends Error {
|
|
|
62
62
|
* being moved). Wait at least that long, then try once more; retrying at once only meets the same answer.
|
|
63
63
|
*/
|
|
64
64
|
retryAfter;
|
|
65
|
+
/** With serverCode unknown_role (`tasks.give({ role })` naming a role not on the business map): the map's roles, by key and name. */
|
|
66
|
+
roles;
|
|
65
67
|
constructor(
|
|
66
68
|
/** Why it failed. */
|
|
67
69
|
code, message,
|
|
@@ -94,6 +96,8 @@ export class AwesomateError extends Error {
|
|
|
94
96
|
this.requiredPlan = details.requiredPlan;
|
|
95
97
|
if (details.retryAfter !== undefined)
|
|
96
98
|
this.retryAfter = details.retryAfter;
|
|
99
|
+
if (details.roles !== undefined)
|
|
100
|
+
this.roles = details.roles;
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
103
|
/** Every code the hub uses for "the account has switched this off in its privacy settings". */
|
|
@@ -153,6 +157,12 @@ function refusal(status, json) {
|
|
|
153
157
|
?? (Array.isArray(json.requiredPlans) ? nonEmpty(json.requiredPlans[0]) : undefined);
|
|
154
158
|
if (required)
|
|
155
159
|
details.requiredPlan = required;
|
|
160
|
+
if (Array.isArray(json.roles)) {
|
|
161
|
+
details.roles = json.roles
|
|
162
|
+
.filter((r) => Boolean(r) && typeof r === 'object')
|
|
163
|
+
.map((r) => ({ slug: String(r.slug ?? ''), title: String(r.title ?? '') }))
|
|
164
|
+
.filter((r) => r.slug !== '');
|
|
165
|
+
}
|
|
156
166
|
return {
|
|
157
167
|
code: errorCode(status, serverCode, json),
|
|
158
168
|
message: (codeInError ? sentence : error ?? sentence) ?? `The hub answered ${status}.`,
|
|
@@ -414,6 +424,7 @@ export class AwesomateClient {
|
|
|
414
424
|
*
|
|
415
425
|
* @example
|
|
416
426
|
* await db.tasks.give({ title: 'Call Sam back about the leak', forEmail: 'jo@brightwater.example', dueAt: '2026-10-06T09:00:00+11:00' });
|
|
427
|
+
* await db.tasks.give({ title: 'Hot lead: Sam wants a quote today', forEmail: 'jo@brightwater.example', urgent: true });
|
|
417
428
|
*/
|
|
418
429
|
tasks = {
|
|
419
430
|
/** The board: waiting now, put off, with someone else, recently decided. `all` shows everyone's, not only yours. hosting:read. */
|
|
@@ -431,15 +442,32 @@ export class AwesomateClient {
|
|
|
431
442
|
* token may not see reads as not found (serverCode `gone`). hosting:read.
|
|
432
443
|
*/
|
|
433
444
|
decisionRecord: (taskId) => this.tasksCall('GET', `/api/my-tasks/decisions/${encodeURIComponent(String(taskId))}/record`),
|
|
434
|
-
/**
|
|
445
|
+
/**
|
|
446
|
+
* Give a task. The person gets it on their board, an email when they are not the one giving it,
|
|
447
|
+
* and a card in any chat they linked, within their quiet hours and daily limit (`urgent` goes
|
|
448
|
+
* straight away). `urgent` in the result says whether it went as urgent: a person's sixth urgent
|
|
449
|
+
* task in a day goes as an ordinary one, and `note` says so. hosting:manage.
|
|
450
|
+
*/
|
|
435
451
|
give: async (task) => {
|
|
436
452
|
const r = await this.tasksCall('POST', '/api/my-tasks/tasks', task);
|
|
437
|
-
return { key: r.key, id: r.id, holder: r.holder, emailed: r.emailed };
|
|
453
|
+
return { key: r.key, id: r.id, holder: r.holder, emailed: r.emailed, urgent: r.urgent === true, ...(r.role ? { role: r.role } : {}), ...(r.note ? { note: r.note } : {}) };
|
|
438
454
|
},
|
|
439
|
-
/**
|
|
455
|
+
/**
|
|
456
|
+
* Change a given task: whoever wrote it, or the owner. `urgent: false` takes urgent off; a task can
|
|
457
|
+
* only be marked urgent when it is given. hosting:manage.
|
|
458
|
+
*/
|
|
440
459
|
update: async (id, patch) => {
|
|
441
460
|
await this.tasksCall('PATCH', `/api/my-tasks/tasks/${encodeURIComponent(String(id))}`, patch);
|
|
442
461
|
},
|
|
462
|
+
/**
|
|
463
|
+
* Take a role's task (a card with `role.mayTake`): it becomes the owner's, and everyone else in
|
|
464
|
+
* the role sees who took it. Only someone in the role can take it, so this works for the owner
|
|
465
|
+
* only when they are in that role (serverCode `not_in_role` otherwise). Someone who got there
|
|
466
|
+
* first answers `taken`, with their name in the message. hosting:manage.
|
|
467
|
+
*/
|
|
468
|
+
take: async (id) => {
|
|
469
|
+
await this.tasksCall('POST', `/api/my-tasks/tasks/${encodeURIComponent(String(id))}/take`);
|
|
470
|
+
},
|
|
443
471
|
/** Mark a given task done: the person who has it, whoever wrote it, or the owner. hosting:manage. */
|
|
444
472
|
done: async (id) => {
|
|
445
473
|
await this.tasksCall('POST', `/api/my-tasks/tasks/${encodeURIComponent(String(id))}/done`);
|
|
@@ -786,6 +814,37 @@ export class AwesomateClient {
|
|
|
786
814
|
addTags: async (id, tags) => this.contactsWrite('POST', `/${contactIdOf(id)}/tags`, { add: tags }),
|
|
787
815
|
/** Take tags off a person, up to 20 a call. Answers how many they had. */
|
|
788
816
|
removeTags: async (id, tags) => this.contactsWrite('POST', `/${contactIdOf(id)}/tags`, { remove: tags }),
|
|
817
|
+
/**
|
|
818
|
+
* Record that the person asked to stop getting email, by reply, phone, in person or in writing
|
|
819
|
+
* (`how`), at the time they asked (`askedAt`, default now, at most 30 days back). With no `list`
|
|
820
|
+
* it stops every email, booking confirmations and other service emails included; with a list's
|
|
821
|
+
* key, that list only. Recorded as the person's own withdrawal, so a later import never puts
|
|
822
|
+
* them back. Answers `changed: false` when it was already recorded. The law gives 5 business
|
|
823
|
+
* days from when they asked. A person with no email address is refused (validation).
|
|
824
|
+
*/
|
|
825
|
+
unsubscribe: async (id, options) => {
|
|
826
|
+
const askedAt = options.askedAt instanceof Date ? options.askedAt.toISOString() : options.askedAt;
|
|
827
|
+
return this.contactsWrite('POST', `/${contactIdOf(id)}/unsubscribe`, {
|
|
828
|
+
how: options.how, ...(options.list !== undefined ? { list: options.list } : {}), ...(askedAt !== undefined ? { asked_at: askedAt } : {}),
|
|
829
|
+
});
|
|
830
|
+
},
|
|
831
|
+
/**
|
|
832
|
+
* Prepare an erasure, for when someone asks for their details to be deleted. Answers what
|
|
833
|
+
* erasing the person would take (`counts`) and `finishInHub`, the hub link where an Owner of the
|
|
834
|
+
* business finishes it, signed in as themselves, by typing the person's email address. Nothing
|
|
835
|
+
* is erased here: no token can erase anyone, because an erasure can't be undone. Only an Owner's
|
|
836
|
+
* token may prepare one (403 `owner_only`). Null when there is no such person.
|
|
837
|
+
*/
|
|
838
|
+
erasurePreview: async (id) => {
|
|
839
|
+
if (this.appKey)
|
|
840
|
+
throw contactsNeedAccount();
|
|
841
|
+
if (!RECORD_ID.test(String(id)))
|
|
842
|
+
return null;
|
|
843
|
+
const r = await nullIfMissing(this.request('GET', `/api/my-crm/v1/contacts/${encodeURIComponent(String(id))}/erasure`));
|
|
844
|
+
if (!r)
|
|
845
|
+
return null;
|
|
846
|
+
return { contact: r.contact, counts: r.counts, finishInHub: r.finish_in_hub, note: r.note };
|
|
847
|
+
},
|
|
789
848
|
/**
|
|
790
849
|
* Add a contact field. The hub makes its key from the label with a random part and answers it:
|
|
791
850
|
* use that key. Nothing here changes a field that exists. `ai_may_read` decides, once and now,
|
|
@@ -1010,6 +1069,22 @@ export class AwesomateClient {
|
|
|
1010
1069
|
throw err;
|
|
1011
1070
|
}
|
|
1012
1071
|
}
|
|
1072
|
+
/**
|
|
1073
|
+
* What points at one row: for each link from another kind (a job's customer, a memo's job), how
|
|
1074
|
+
* many rows point here and the newest of them (`limit`, default 20, at most 100), read as query()
|
|
1075
|
+
* reads that kind. Null when there is no such row. The account's token, crm:read.
|
|
1076
|
+
*
|
|
1077
|
+
* @example
|
|
1078
|
+
* const related = await db.related('contact', contactId);
|
|
1079
|
+
* for (const r of related ?? []) console.log(r.kind, r.link, r.count);
|
|
1080
|
+
*/
|
|
1081
|
+
async related(kind, id, options = {}) {
|
|
1082
|
+
if (!RECORD_ID.test(String(id)))
|
|
1083
|
+
return null;
|
|
1084
|
+
const qs = options.limit ? `?limit=${options.limit}` : '';
|
|
1085
|
+
const r = await nullIfMissing(this.request('GET', `/api/my-crm/v1/rows/${encodeURIComponent(kind)}/${encodeURIComponent(String(id))}/related${qs}`));
|
|
1086
|
+
return r ? r.related : null;
|
|
1087
|
+
}
|
|
1013
1088
|
/** The app kinds this account has defined. The account's token, crm:read, every plan; never an app key. */
|
|
1014
1089
|
async kinds() {
|
|
1015
1090
|
return (await this.request('GET', '/api/my-crm/v1/kinds')).kinds;
|
|
@@ -1087,6 +1162,25 @@ export class AwesomateClient {
|
|
|
1087
1162
|
async archive(kind, id) {
|
|
1088
1163
|
await this.request('POST', '/api/my-crm/v1/call', { fn: 'archive_record', args: { kind, id } }, false);
|
|
1089
1164
|
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Create or change the record that mirrors one in another system, found by that system's name and
|
|
1167
|
+
* its id there (`ref.system`, lower case like `xero`; `ref.externalId`), so a sync run twice changes
|
|
1168
|
+
* the record instead of making a second one. The same checks as write(). A record with that id that
|
|
1169
|
+
* was archived is refused (`conflict`): a sync never undoes an archive or makes a second copy. Companies
|
|
1170
|
+
* are refused here: use companies.upsert(), which matches by ABN and name. The account's token only
|
|
1171
|
+
* (never an app key), crm:write, Support Plus and above.
|
|
1172
|
+
*
|
|
1173
|
+
* @example
|
|
1174
|
+
* const { id, created } = await db.upsertByRef('job', { system: 'servicem8', externalId: 'JOB-0042' }, { title: 'Possum in the roof' }, { links: { customer: contactId } });
|
|
1175
|
+
*/
|
|
1176
|
+
async upsertByRef(kind, ref, data = {}, options = {}) {
|
|
1177
|
+
if (this.appKey)
|
|
1178
|
+
throw new AwesomateError('forbidden', "upsertByRef needs the account's token (amt_pat_...). An app key writes records with write().", 0);
|
|
1179
|
+
const r = await this.request('POST', `/api/my-crm/v1/records/${encodeURIComponent(kind)}/by-ref`, {
|
|
1180
|
+
system: ref.system, external_id: ref.externalId, data, links: options.links ?? {},
|
|
1181
|
+
}, false);
|
|
1182
|
+
return r.result;
|
|
1183
|
+
}
|
|
1090
1184
|
/** The saved queries on this account. crm:read, every plan: the account's token or an app key. */
|
|
1091
1185
|
async queries() {
|
|
1092
1186
|
return (await this.request('GET', '/api/my-crm/v1/queries')).queries;
|
|
@@ -1164,6 +1258,29 @@ export class AwesomateClient {
|
|
|
1164
1258
|
async businessMapRole(slug) {
|
|
1165
1259
|
return (await this.request('GET', `/api/my-business/v2/map/roles/${encodeURIComponent(slug)}`)).role;
|
|
1166
1260
|
}
|
|
1261
|
+
/**
|
|
1262
|
+
* The business's KPIs: each a number with a target and someone responsible for it, with where it
|
|
1263
|
+
* sits, who answers for it, its light against the target for the last complete period, the period
|
|
1264
|
+
* so far, a trend of up to 12 periods and where its figure comes from. A person's own key reads only the KPIs
|
|
1265
|
+
* they would see in the hub. `period` reads every KPI by the week, month or quarter (never finer than
|
|
1266
|
+
* its own period); left out, each by its own. hosting:read, every plan; `available` is false, with a
|
|
1267
|
+
* `reason`, where the account has no KPIs to read.
|
|
1268
|
+
*/
|
|
1269
|
+
async businessKpis(opts = {}) {
|
|
1270
|
+
return this.request('GET', `/api/my-business/v2/map/kpis${opts.period ? `?period=${opts.period}` : ''}`);
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Add figures for the business's KPIs from your own tool or script: totals per day, week or month,
|
|
1274
|
+
* into the business's own Your numbers, where a KPI reads them by name. Up to 100 a call; a figure
|
|
1275
|
+
* sent again for the same period replaces the one before. Each figure name belongs to the first
|
|
1276
|
+
* source that sends it (`serverCode: 'figure_owned'` for another). Totals only: a label that looks
|
|
1277
|
+
* like an email address, phone number or web address is refused. knowledge:write, Support Plus and
|
|
1278
|
+
* above (`feature_unavailable` below that), and Your numbers switched on for the business.
|
|
1279
|
+
*/
|
|
1280
|
+
async addFigures(input) {
|
|
1281
|
+
const r = await this.request('POST', '/api/my-business/v2/figures', input);
|
|
1282
|
+
return { added: r.added, source: r.source, tables: r.tables };
|
|
1283
|
+
}
|
|
1167
1284
|
/**
|
|
1168
1285
|
* The business map in its first shape, where a department is a `division`, a sub-department a
|
|
1169
1286
|
* `department` and a role a `job`. hosting:read, the business map on the account.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "Your own Awesomate data from Node and the browser: query contacts and app data with generated types, and sign your app's own users in",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|