@awesomate/sdk 0.81.2 → 0.81.4

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 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.81.2";
29
+ export declare const VERSION = "0.81.4";
30
30
  /** Augmented by the generated awesomate.d.ts, so each kind's rows are typed. */
31
31
  export interface Kinds {
32
32
  }
@@ -1490,11 +1490,18 @@ export declare class AwesomateClient {
1490
1490
  topics: {
1491
1491
  /** Every topic, in the centre's order. */
1492
1492
  list: () => Promise<HelpTopic[]>;
1493
- /** Add a topic; its slug is made from the name unless given. */
1493
+ /** Add a topic; its slug is made from the name unless given. `icon` is one of HELP_ICON_NAMES. */
1494
1494
  create: (input: {
1495
1495
  name: string;
1496
1496
  slug?: string;
1497
1497
  description?: string | null;
1498
+ icon?: HelpIconName | null;
1499
+ }) => Promise<HelpTopic>;
1500
+ /** Rename a topic, or change its description or icon (one of HELP_ICON_NAMES, or null for the default). Its slug is changed in the hub. */
1501
+ update: (id: string, patch: {
1502
+ name?: string;
1503
+ description?: string | null;
1504
+ icon?: HelpIconName | null;
1498
1505
  }) => Promise<HelpTopic>;
1499
1506
  };
1500
1507
  articles: {
@@ -4305,7 +4312,7 @@ export interface ContactFindResult {
4305
4312
  zone: string | null;
4306
4313
  }
4307
4314
  /** The groups contacts.activity() can keep, as its `types` option takes them. */
4308
- export type ContactActivityGroup = 'contact' | 'lists' | 'forms' | 'events' | 'emails' | 'series' | 'bookings' | 'conversations';
4315
+ export type ContactActivityGroup = 'contact' | 'lists' | 'forms' | 'events' | 'emails' | 'series' | 'bookings' | 'conversations' | 'changes';
4309
4316
  /** One thing that happened with a person, from contacts.activity(). */
4310
4317
  export interface ContactActivityRow {
4311
4318
  /** What happened: contact_added, list_joined, tag_added, email, service_email, series_came_off, booking_completed, ticket, call and so on. */
@@ -5370,9 +5377,15 @@ export interface HelpTopic {
5370
5377
  name: string;
5371
5378
  slug: string;
5372
5379
  description: string | null;
5380
+ /** Its icon's name, one of HELP_ICON_NAMES, or null for the default. */
5381
+ icon: HelpIconName | null;
5373
5382
  position: number;
5374
5383
  updatedAt: string;
5375
5384
  }
5385
+ /** The icons a help topic may use, by name (the help pages draw each one inline). */
5386
+ export declare const HELP_ICON_NAMES: readonly ["rocket", "settings", "account", "billing", "receipt", "website", "email", "chat", "automation", "ai", "knowledge", "learn", "help", "security", "lock", "troubleshoot", "cloud", "data", "code", "phone", "calendar", "people", "marketing", "shop", "reports", "integrations", "document", "star"];
5387
+ /** One of HELP_ICON_NAMES. */
5388
+ export type HelpIconName = (typeof HELP_ICON_NAMES)[number];
5376
5389
  /** The help centre, from help.centre(). */
5377
5390
  export interface HelpCentreView {
5378
5391
  centre: {
@@ -5389,6 +5402,10 @@ export interface HelpCentreView {
5389
5402
  /** The audiences an article may name (`all`, or plans on Awesomate's own centre). */
5390
5403
  segments: string[];
5391
5404
  topics: HelpTopic[];
5405
+ /** The public help API's address for this centre (createHelpClient). */
5406
+ publicApi: string | null;
5407
+ /** Whether the new design is on for this centre: the public help API answers only then. */
5408
+ v2: boolean;
5392
5409
  }
5393
5410
  /** What creating or changing an article takes. */
5394
5411
  export interface HelpArticleInput {
@@ -6332,4 +6349,199 @@ export declare class AwesomateBookingsClient {
6332
6349
  * ```
6333
6350
  */
6334
6351
  export declare function createBookingsClient(options: BookingsClientOptions): AwesomateBookingsClient;
6352
+ /** Options for createHelpClient(). */
6353
+ export interface HelpClientOptions {
6354
+ /** The help centre's handle (awesomate), or its own address once that is switched on (help.yourbusiness.com.au). */
6355
+ centre: string;
6356
+ /** Default https://hub.awesomate.ai. */
6357
+ baseUrl?: string;
6358
+ /** Your own fetch. Default: the global one. */
6359
+ fetch?: typeof fetch;
6360
+ }
6361
+ /** A help centre's topic, from the public help API: only topics with something published in them. */
6362
+ export interface PublicHelpTopic {
6363
+ id: string;
6364
+ slug: string;
6365
+ name: string;
6366
+ description: string | null;
6367
+ icon: HelpIconName | null;
6368
+ /** The icon as inline SVG, drawn in `currentColor`: no third-party request. */
6369
+ iconSvg: string;
6370
+ articleCount: number;
6371
+ }
6372
+ /** A published article in a list, from the public help API. */
6373
+ export interface PublicHelpArticleSummary {
6374
+ id: string;
6375
+ slug: string;
6376
+ title: string;
6377
+ summary: string | null;
6378
+ topicId: string | null;
6379
+ updatedAt: string | null;
6380
+ /** The article's page on the help centre. */
6381
+ url: string;
6382
+ }
6383
+ /** One published article, from help.article(). */
6384
+ export interface PublicHelpArticle extends PublicHelpArticleSummary {
6385
+ markdown: string;
6386
+ /** The article as safe HTML: no scripts, only https images and the help pages' own players. */
6387
+ html: string;
6388
+ /** Its headings, for a contents list (`text` is already HTML-safe). */
6389
+ headings: Array<{
6390
+ depth: number;
6391
+ id: string;
6392
+ text: string;
6393
+ }>;
6394
+ firstPublishedAt: string | null;
6395
+ topic: {
6396
+ id: string;
6397
+ slug: string;
6398
+ name: string;
6399
+ } | null;
6400
+ }
6401
+ /** The help centre, from help.centre(). */
6402
+ export interface PublicHelpCentre {
6403
+ handle: string;
6404
+ title: string;
6405
+ /** Where its own pages are. */
6406
+ url: string;
6407
+ /** The business's website, for "Go to website". */
6408
+ website: string | null;
6409
+ privacyUrl: string | null;
6410
+ brand: {
6411
+ name: string;
6412
+ logo: {
6413
+ src: string;
6414
+ alt: string;
6415
+ } | null;
6416
+ colours: Record<string, string>;
6417
+ fontStack: string;
6418
+ };
6419
+ topics: PublicHelpTopic[];
6420
+ /** What the centre offers: answers (ask), messages (contact) and, with messages, questions about the business's services. */
6421
+ features: {
6422
+ ask: boolean;
6423
+ contact: boolean;
6424
+ enquiries: boolean;
6425
+ };
6426
+ }
6427
+ /** An answer from help.ask(). */
6428
+ export interface PublicHelpAnswer {
6429
+ /** answered; none (the articles do not say); unavailable (try the articles, or later). An empty or too long question is refused with `validation`. */
6430
+ status: 'answered' | 'none' | 'unavailable';
6431
+ /** The answer as markdown, with [n] markers for its citations. Null unless answered. */
6432
+ answer: string | null;
6433
+ html: string | null;
6434
+ citations: Array<{
6435
+ n: number;
6436
+ title: string;
6437
+ url: string | null;
6438
+ }>;
6439
+ /** Carry it into help.contact.start({ attempt }) so the team sees this answer with the message. */
6440
+ feedbackToken: string | null;
6441
+ }
6442
+ /** Where a message to the team is up to, from help.contact. */
6443
+ export type PublicHelpContactStep = {
6444
+ step: 'form';
6445
+ problems: Array<{
6446
+ field: 'name' | 'email' | 'question' | 'kind';
6447
+ message: string;
6448
+ }>;
6449
+ message?: string;
6450
+ code?: string;
6451
+ } | {
6452
+ step: 'code';
6453
+ flow: string;
6454
+ email: string;
6455
+ message: string;
6456
+ code?: string;
6457
+ } | {
6458
+ step: 'done';
6459
+ email: string;
6460
+ deskAddress: string | null;
6461
+ };
6462
+ /**
6463
+ * The help client, from createHelpClient(): a business's published help centre for pages it builds
6464
+ * itself, for visitors who are not signed in. Reading needs no key and works from any website.
6465
+ * Asking, rating and messages work only from the centre's own address and the websites its owner
6466
+ * listed, in the visitor's browser: limits are per visitor address, so a server relaying for many
6467
+ * people shares one allowance.
6468
+ */
6469
+ export declare class AwesomateHelpClient {
6470
+ private readonly base;
6471
+ private readonly doFetch;
6472
+ constructor(opts: HelpClientOptions);
6473
+ private request;
6474
+ /** The centre: its title, address, brand, website, topics and what it offers. */
6475
+ centre(): Promise<PublicHelpCentre>;
6476
+ /** Topics with something published in them, each with its icon and count. */
6477
+ topics(): Promise<PublicHelpTopic[]>;
6478
+ /** Published articles, 20 a page unless told otherwise (at most 50), optionally in one topic (by its slug). */
6479
+ articles(options?: {
6480
+ topic?: string;
6481
+ page?: number;
6482
+ perPage?: number;
6483
+ }): Promise<{
6484
+ articles: PublicHelpArticleSummary[];
6485
+ page: number;
6486
+ perPage: number;
6487
+ total: number;
6488
+ }>;
6489
+ /** One published article with its HTML, markdown and headings, or null when there is none by that slug. */
6490
+ article(slug: string): Promise<PublicHelpArticle | null>;
6491
+ /** The six most read articles, the owner's pinned ones first. */
6492
+ popular(): Promise<PublicHelpArticleSummary[]>;
6493
+ /** Articles matching a search (spelling slips and close words included). The words are never kept. */
6494
+ search(q: string): Promise<PublicHelpArticleSummary[]>;
6495
+ /**
6496
+ * The notice to show beside an ask box, and its token. Pass the token to ask() once you have shown
6497
+ * the notice: only then can a question the articles do not answer reach the owner's Questions inbox.
6498
+ */
6499
+ askNotice(): Promise<{
6500
+ notice: string | null;
6501
+ noticeToken: string | null;
6502
+ }>;
6503
+ /**
6504
+ * Ask the centre's assistant (one of the business's Knowledge answers; the same question again within
6505
+ * a day costs nothing). From the centre's own address and the owner's listed websites only.
6506
+ */
6507
+ ask(question: string, options?: {
6508
+ noticeToken?: string | null;
6509
+ }): Promise<PublicHelpAnswer>;
6510
+ /** "Was this helpful?" on an article. Counted once a day per visitor. */
6511
+ helpful(slug: string, yes: boolean): Promise<void>;
6512
+ /**
6513
+ * A message to the business's team. start() checks the form and emails the visitor a 6-digit code;
6514
+ * confirm() takes the code and sends the message, as a ticket with the assistant's answer beside it
6515
+ * when `attempt` carried one. Problems and a wrong code come back as steps, not errors.
6516
+ */
6517
+ readonly contact: {
6518
+ /** Check the form and send the code. `kind: 'enquiry'` only where features.enquiries is on. */
6519
+ start: (input: {
6520
+ name: string;
6521
+ email: string;
6522
+ question: string;
6523
+ kind?: "help" | "enquiry";
6524
+ attempt?: string | null;
6525
+ }) => Promise<PublicHelpContactStep>;
6526
+ /** The code from the email: the message is sent (`done`), or the code page again with why. */
6527
+ confirm: (flow: string, code: string) => Promise<PublicHelpContactStep>;
6528
+ /** Send a new code for the same message. */
6529
+ resend: (flow: string) => Promise<PublicHelpContactStep>;
6530
+ };
6531
+ }
6532
+ /**
6533
+ * The client for help pages a business builds itself, for visitors who are not signed in. Reading
6534
+ * works from anywhere with no key; asking, rating and messages from the centre's own address and the
6535
+ * websites its owner lists. The help centre must have the new design on.
6536
+ *
6537
+ * @example
6538
+ * ```ts
6539
+ * import { createHelpClient } from '@awesomate/sdk';
6540
+ *
6541
+ * const help = createHelpClient({ centre: 'awesomate' });
6542
+ * const { topics } = await help.centre();
6543
+ * const found = await help.search('reset my password');
6544
+ * ```
6545
+ */
6546
+ export declare function createHelpClient(options: HelpClientOptions): AwesomateHelpClient;
6335
6547
  export {};
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.81.2';
29
+ export const VERSION = '0.81.4';
30
30
  const DEFAULT_BASE = 'https://hub.awesomate.ai';
31
31
  /** The one check for a platform `watch_url` (mirrored in the hub's awesomate-knowledge.ts and its MCP). */
32
32
  const WATCH_URL = /^https:\/\/[^\s"'<>]+$/i;
@@ -1128,13 +1128,15 @@ export class AwesomateClient {
1128
1128
  /** The centre, its public address, the segments an article may name, and its topics. */
1129
1129
  centre: async () => {
1130
1130
  const r = await this.helpRequest('GET', '/?articles=0');
1131
- return { centre: r.centre, publicUrl: r.publicUrl, segments: r.segments, topics: r.topics };
1131
+ return { centre: r.centre, publicUrl: r.publicUrl, segments: r.segments, topics: r.topics, publicApi: r.publicApi ?? null, v2: r.v2 === true };
1132
1132
  },
1133
1133
  topics: {
1134
1134
  /** Every topic, in the centre's order. */
1135
1135
  list: async () => (await this.helpRequest('GET', '/?articles=0')).topics,
1136
- /** Add a topic; its slug is made from the name unless given. */
1136
+ /** Add a topic; its slug is made from the name unless given. `icon` is one of HELP_ICON_NAMES. */
1137
1137
  create: async (input) => (await this.helpRequest('POST', '/topics', input)).topic,
1138
+ /** Rename a topic, or change its description or icon (one of HELP_ICON_NAMES, or null for the default). Its slug is changed in the hub. */
1139
+ update: async (id, patch) => (await this.helpRequest('PATCH', `/topics/${encodeURIComponent(String(id))}`, patch)).topic,
1138
1140
  },
1139
1141
  articles: {
1140
1142
  /** Articles without their bodies, optionally in one status or matching words in the title. */
@@ -2187,6 +2189,12 @@ function briefFromWire(r) {
2187
2189
  const { session_id, job_id, ...rest } = r;
2188
2190
  return { ...rest, ...(session_id ? { sessionId: session_id } : {}), ...(job_id ? { jobId: job_id } : {}) };
2189
2191
  }
2192
+ /** The icons a help topic may use, by name (the help pages draw each one inline). */
2193
+ export const HELP_ICON_NAMES = [
2194
+ 'rocket', 'settings', 'account', 'billing', 'receipt', 'website', 'email', 'chat', 'automation', 'ai', 'knowledge', 'learn', 'help',
2195
+ 'security', 'lock', 'troubleshoot', 'cloud', 'data', 'code', 'phone', 'calendar', 'people', 'marketing', 'shop', 'reports',
2196
+ 'integrations', 'document', 'star',
2197
+ ];
2190
2198
  function memoryStorage() {
2191
2199
  const m = new Map();
2192
2200
  return { getItem: (k) => m.get(k) ?? null, setItem: (k, v) => { m.set(k, v); }, removeItem: (k) => { m.delete(k); } };
@@ -3441,3 +3449,131 @@ export class AwesomateBookingsClient {
3441
3449
  export function createBookingsClient(options) {
3442
3450
  return new AwesomateBookingsClient(options);
3443
3451
  }
3452
+ /**
3453
+ * The help client, from createHelpClient(): a business's published help centre for pages it builds
3454
+ * itself, for visitors who are not signed in. Reading needs no key and works from any website.
3455
+ * Asking, rating and messages work only from the centre's own address and the websites its owner
3456
+ * listed, in the visitor's browser: limits are per visitor address, so a server relaying for many
3457
+ * people shares one allowance.
3458
+ */
3459
+ export class AwesomateHelpClient {
3460
+ base;
3461
+ doFetch;
3462
+ constructor(opts) {
3463
+ const centre = String(opts?.centre ?? '').trim().toLowerCase();
3464
+ if (!/^[a-z0-9][a-z0-9.-]{0,252}$/.test(centre))
3465
+ throw new Error('createHelpClient needs the help centre\'s handle, or its own address (help.yourbusiness.com.au).');
3466
+ this.base = `${(opts.baseUrl ?? DEFAULT_BASE).replace(/\/+$/, '')}/api/public/help/v1/${encodeURIComponent(centre)}`;
3467
+ const f = opts.fetch ?? globalThis.fetch?.bind(globalThis);
3468
+ if (!f)
3469
+ throw new Error('No fetch available.');
3470
+ this.doFetch = f;
3471
+ }
3472
+ async request(method, path, body, steps = false) {
3473
+ let res;
3474
+ try {
3475
+ res = await this.doFetch(`${this.base}${path}`, {
3476
+ method,
3477
+ headers: body === undefined ? {} : { 'content-type': 'application/json' },
3478
+ body: body === undefined ? undefined : JSON.stringify(body),
3479
+ });
3480
+ }
3481
+ catch (err) {
3482
+ throw new AwesomateError('unavailable', `The hub could not be reached: ${err.message}`, 0);
3483
+ }
3484
+ const data = (await res.json().catch(() => ({})));
3485
+ // A message's own steps (the form's problems, a wrong code) are answers, not failures.
3486
+ if (!res.ok && !(steps && typeof data.step === 'string')) {
3487
+ const err = hubError(res, data);
3488
+ throw new AwesomateError(err.code, err.message, err.status, err.field, err.serverCode, err.message, err);
3489
+ }
3490
+ return data;
3491
+ }
3492
+ /** The centre: its title, address, brand, website, topics and what it offers. */
3493
+ centre() {
3494
+ return this.request('GET', '/centre');
3495
+ }
3496
+ /** Topics with something published in them, each with its icon and count. */
3497
+ async topics() {
3498
+ return (await this.request('GET', '/topics')).topics;
3499
+ }
3500
+ /** Published articles, 20 a page unless told otherwise (at most 50), optionally in one topic (by its slug). */
3501
+ articles(options = {}) {
3502
+ const q = new URLSearchParams();
3503
+ if (options.topic)
3504
+ q.set('topic', options.topic);
3505
+ if (options.page)
3506
+ q.set('page', String(options.page));
3507
+ if (options.perPage)
3508
+ q.set('per_page', String(options.perPage));
3509
+ const qs = q.toString();
3510
+ return this.request('GET', `/articles${qs ? `?${qs}` : ''}`);
3511
+ }
3512
+ /** One published article with its HTML, markdown and headings, or null when there is none by that slug. */
3513
+ async article(slug) {
3514
+ try {
3515
+ return await this.request('GET', `/articles/${encodeURIComponent(slug)}`);
3516
+ }
3517
+ catch (err) {
3518
+ if (err instanceof AwesomateError && err.code === 'not_found')
3519
+ return null;
3520
+ throw err;
3521
+ }
3522
+ }
3523
+ /** The six most read articles, the owner's pinned ones first. */
3524
+ async popular() {
3525
+ return (await this.request('GET', '/popular')).articles;
3526
+ }
3527
+ /** Articles matching a search (spelling slips and close words included). The words are never kept. */
3528
+ async search(q) {
3529
+ return (await this.request('GET', `/search?q=${encodeURIComponent(q)}`)).articles;
3530
+ }
3531
+ /**
3532
+ * The notice to show beside an ask box, and its token. Pass the token to ask() once you have shown
3533
+ * the notice: only then can a question the articles do not answer reach the owner's Questions inbox.
3534
+ */
3535
+ askNotice() {
3536
+ return this.request('GET', '/ask/notice');
3537
+ }
3538
+ /**
3539
+ * Ask the centre's assistant (one of the business's Knowledge answers; the same question again within
3540
+ * a day costs nothing). From the centre's own address and the owner's listed websites only.
3541
+ */
3542
+ ask(question, options = {}) {
3543
+ return this.request('POST', '/ask', { question, ...(options.noticeToken ? { noticeToken: options.noticeToken } : {}) });
3544
+ }
3545
+ /** "Was this helpful?" on an article. Counted once a day per visitor. */
3546
+ async helpful(slug, yes) {
3547
+ await this.request('POST', `/articles/${encodeURIComponent(slug)}/helpful`, { answer: yes ? 'yes' : 'no' });
3548
+ }
3549
+ /**
3550
+ * A message to the business's team. start() checks the form and emails the visitor a 6-digit code;
3551
+ * confirm() takes the code and sends the message, as a ticket with the assistant's answer beside it
3552
+ * when `attempt` carried one. Problems and a wrong code come back as steps, not errors.
3553
+ */
3554
+ contact = {
3555
+ /** Check the form and send the code. `kind: 'enquiry'` only where features.enquiries is on. */
3556
+ start: (input) => this.request('POST', '/contact/start', input, true),
3557
+ /** The code from the email: the message is sent (`done`), or the code page again with why. */
3558
+ confirm: (flow, code) => this.request('POST', '/contact/confirm', { flow, code }, true),
3559
+ /** Send a new code for the same message. */
3560
+ resend: (flow) => this.request('POST', '/contact/confirm', { flow, resend: true }, true),
3561
+ };
3562
+ }
3563
+ /**
3564
+ * The client for help pages a business builds itself, for visitors who are not signed in. Reading
3565
+ * works from anywhere with no key; asking, rating and messages from the centre's own address and the
3566
+ * websites its owner lists. The help centre must have the new design on.
3567
+ *
3568
+ * @example
3569
+ * ```ts
3570
+ * import { createHelpClient } from '@awesomate/sdk';
3571
+ *
3572
+ * const help = createHelpClient({ centre: 'awesomate' });
3573
+ * const { topics } = await help.centre();
3574
+ * const found = await help.search('reset my password');
3575
+ * ```
3576
+ */
3577
+ export function createHelpClient(options) {
3578
+ return new AwesomateHelpClient(options);
3579
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/sdk",
3
- "version": "0.81.2",
3
+ "version": "0.81.4",
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",