@fayz-ai/plugin-conversations 0.10.0 → 0.11.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/README.md +3 -1
- package/dist/data/channels.d.ts +70 -0
- package/dist/data/channels.d.ts.map +1 -0
- package/dist/data/payment-preflight.d.ts +42 -0
- package/dist/data/payment-preflight.d.ts.map +1 -0
- package/dist/data/tables.d.ts +1 -0
- package/dist/data/tables.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1152 -28
- package/dist/index.js.map +1 -1
- package/dist/integrations/tyxter/connectorDef.d.ts +14 -0
- package/dist/integrations/tyxter/connectorDef.d.ts.map +1 -0
- package/dist/integrations/tyxter/data.d.ts +70 -0
- package/dist/integrations/tyxter/data.d.ts.map +1 -0
- package/dist/migrations/index.d.ts +7 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
Customers reach out everywhere — a WhatsApp here, an Instagram DM there, an email, a text. Replying across five tabs is how businesses drop conversations. `plugin-conversations` is the GoHighLevel-style unified inbox for the Fayz engine: every channel collapses into one threaded view, so a salon, a restaurant, or an agency answers everyone from a single place.
|
|
11
11
|
|
|
12
|
-
This is foundational today. The plugin ships a complete inbox UI and a data-provider seam: it runs on a rich mock out of the box, and reads/writes the `conversations` + `conversation_messages` tables (tenant-scoped) when a Supabase client is registered.
|
|
12
|
+
This is foundational today. The plugin ships a complete inbox UI and a data-provider seam: it runs on a rich mock out of the box, and reads/writes the `conversations` + `conversation_messages` tables (tenant-scoped) when a Supabase client is registered. WhatsApp is the first real channel, through the **Tyxter** connector; Instagram, email and SMS still arrive out-of-band.
|
|
13
13
|
|
|
14
14
|
## What's inside
|
|
15
15
|
- A full-bleed `/conversations` inbox view backed by a Zustand store
|
|
16
16
|
- A `ConversationsProvider` seam: mock provider, or a Supabase provider (tenant-scoped via the active org) when a client is registered
|
|
17
|
+
- The **Tyxter** connector (`messaging` shelf): WhatsApp on a number the platform already owns — no key to paste — with an optional dedicated number per tenant
|
|
18
|
+
- `plg_conversations_channels`: which number a message leaves by (product fallback vs tenant dedicated), read by members, written only by the service role
|
|
17
19
|
- Domain events: `conversations.message.received`, `conversations.message.sent`
|
|
18
20
|
- AI tools: `listConversations` (filter by `sms` / `whatsapp` / `instagram` / `email` / `webchat`) and `sendMessage`
|
|
19
21
|
- Configurable navigation and full i18n
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Channel } from '../types';
|
|
2
|
+
/** Whose number it is. `fallback` is the product's, shared by every tenant. */
|
|
3
|
+
export type MessagingChannelKind = 'fallback' | 'dedicated';
|
|
4
|
+
/** The provider's own lifecycle, kept verbatim. Only `active` may carry a send. */
|
|
5
|
+
export type MessagingChannelStatus = 'requested' | 'provisioning' | 'provisioned' | 'verifying' | 'active' | 'failed' | 'released' | 'disconnected';
|
|
6
|
+
export interface MessagingChannelAccount {
|
|
7
|
+
id: string;
|
|
8
|
+
/** `null` on the product fallback row — it belongs to the software, not a tenant. */
|
|
9
|
+
tenantId: string | null;
|
|
10
|
+
channel: Channel;
|
|
11
|
+
provider: string;
|
|
12
|
+
providerNumberId: string;
|
|
13
|
+
phoneE164: string | null;
|
|
14
|
+
kind: MessagingChannelKind;
|
|
15
|
+
status: MessagingChannelStatus;
|
|
16
|
+
displayName: string | null;
|
|
17
|
+
metadata: Record<string, unknown>;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ListMessagingChannelsOptions {
|
|
22
|
+
/** Narrow to one provider ('tyxter'). Omitted: every provider in the pool. */
|
|
23
|
+
provider?: string;
|
|
24
|
+
/** Narrow to one channel ('whatsapp'). */
|
|
25
|
+
channel?: Channel;
|
|
26
|
+
/** Supabase client override; defaults to the globally registered one. */
|
|
27
|
+
supabaseClient?: unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Every number this tenant can send by — its own, plus the product fallback.
|
|
31
|
+
*
|
|
32
|
+
* No tenant filter is applied, and that is deliberate: RLS already returns the
|
|
33
|
+
* tenant's rows and the fallback row, and the fallback has no tenant to filter
|
|
34
|
+
* on. Filtering here would hide exactly the row the panel most needs to show.
|
|
35
|
+
*/
|
|
36
|
+
export declare function listMessagingChannels(options?: ListMessagingChannelsOptions): Promise<MessagingChannelAccount[]>;
|
|
37
|
+
/**
|
|
38
|
+
* The happy path, in order. Observed live against the provider's sandbox on
|
|
39
|
+
* 2026-08-24: a provision answered `requested` and the number then walked
|
|
40
|
+
* `provisioned` → `verifying` → `active` in about a second. `provisioning` is in
|
|
41
|
+
* the provider's enum and was not seen at 150ms polling — kept here because the
|
|
42
|
+
* enum has it and a step missing from a timeline reads as a step that failed.
|
|
43
|
+
*/
|
|
44
|
+
export declare const CHANNEL_CLAIM_TIMELINE: MessagingChannelStatus[];
|
|
45
|
+
/**
|
|
46
|
+
* The states in which the tenant already has a claim and must not start another.
|
|
47
|
+
*
|
|
48
|
+
* Mirrors `LIVE_CHANNEL_STATUSES` in functions/_shared/tyxter-runtime.js, which
|
|
49
|
+
* is where the edge function enforces it. Two copies because an edge function
|
|
50
|
+
* may not import from src/ — the vitest suite asserts they agree, so a change to
|
|
51
|
+
* one that is not made to the other fails a test rather than letting the panel
|
|
52
|
+
* offer a button the server will refuse.
|
|
53
|
+
*/
|
|
54
|
+
export declare const LIVE_CHANNEL_STATUSES: MessagingChannelStatus[];
|
|
55
|
+
/** Terminal, and not a reason to stop the tenant trying again. */
|
|
56
|
+
export declare function isDeadChannelStatus(status: MessagingChannelStatus): boolean;
|
|
57
|
+
/** On its way, but not carrying messages yet — the state the panel polls in. */
|
|
58
|
+
export declare function isPendingChannelStatus(status: MessagingChannelStatus): boolean;
|
|
59
|
+
/** The tenant's own number, live or on its way. Null when they have none. */
|
|
60
|
+
export declare function findDedicatedChannel(channels: MessagingChannelAccount[], tenantId?: string | null): MessagingChannelAccount | null;
|
|
61
|
+
/** The product's shared number, which every tenant sends by until it has its own. */
|
|
62
|
+
export declare function findFallbackChannel(channels: MessagingChannelAccount[]): MessagingChannelAccount | null;
|
|
63
|
+
/**
|
|
64
|
+
* Can this tenant ask for a number right now?
|
|
65
|
+
*
|
|
66
|
+
* The same rule the edge function answers 409 on, asked before the round trip
|
|
67
|
+
* so the button is disabled rather than the click refused.
|
|
68
|
+
*/
|
|
69
|
+
export declare function canClaimDedicated(channels: MessagingChannelAccount[], tenantId?: string | null): boolean;
|
|
70
|
+
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/data/channels.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAEvC,+EAA+E;AAC/E,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,WAAW,CAAA;AAE3D,mFAAmF;AACnF,MAAM,MAAM,sBAAsB,GAC9B,WAAW,GACX,cAAc,GACd,aAAa,GACb,WAAW,GACX,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,cAAc,CAAA;AAElB,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAA;IACV,qFAAqF;IACrF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,EAAE,oBAAoB,CAAA;IAC1B,MAAM,EAAE,sBAAsB,CAAA;IAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAqBD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,4BAAiC,GACzC,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAoBpC;AAUD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,sBAAsB,EAM1D,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,EAMzD,CAAA;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAE3E;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAE9E;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,uBAAuB,EAAE,EACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,uBAAuB,GAAG,IAAI,CAMhC;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,uBAAuB,EAAE,GAClC,uBAAuB,GAAG,IAAI,CAEhC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,uBAAuB,EAAE,EACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAET"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** The edge function that holds both questions. */
|
|
2
|
+
export declare const PAYMENT_PREFLIGHT_FUNCTION = "tyxter-payment-preflight";
|
|
3
|
+
/**
|
|
4
|
+
* Which rail is actually behind the payments channel.
|
|
5
|
+
*
|
|
6
|
+
* The distinction that matters and is easy to collapse: `sandbox_default` is
|
|
7
|
+
* READY — charges open, settle and fire webhooks — but the money is not real,
|
|
8
|
+
* and the transparent-Pix provider options are refused. A green badge over it
|
|
9
|
+
* is how a salon finds out on the day of its first real charge, so the panel
|
|
10
|
+
* says "sandbox" beside the tick instead.
|
|
11
|
+
*/
|
|
12
|
+
export type PaymentActiveMode = 'sandbox_default' | 'iniciador' | 'abacate_pay';
|
|
13
|
+
export interface PaymentReadiness {
|
|
14
|
+
/** The provider's own verdict. True for the sandbox fixture too — see `sandbox`. */
|
|
15
|
+
ready: boolean;
|
|
16
|
+
status: string;
|
|
17
|
+
mode: PaymentActiveMode | null;
|
|
18
|
+
/** `mode === 'sandbox_default'`: ready, but not with real money. */
|
|
19
|
+
sandbox: boolean;
|
|
20
|
+
environment: string | null;
|
|
21
|
+
/** Why not, when the provider says why. */
|
|
22
|
+
reason: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** The browser handoff where the merchant enters credentials this app never sees. */
|
|
25
|
+
export interface PaymentSetupSession {
|
|
26
|
+
setupUrl: string | null;
|
|
27
|
+
requestId: string | null;
|
|
28
|
+
expiresAt: string | null;
|
|
29
|
+
environment: string | null;
|
|
30
|
+
}
|
|
31
|
+
export declare function readPaymentReadiness(tenantId?: string): Promise<PaymentReadiness>;
|
|
32
|
+
export declare function openPaymentSetupSession(tenantId?: string): Promise<PaymentSetupSession>;
|
|
33
|
+
/**
|
|
34
|
+
* Is the `pay` action safe to offer in a message template?
|
|
35
|
+
*
|
|
36
|
+
* The sandbox fixture counts, deliberately: a build being dogfooded on sandbox
|
|
37
|
+
* credentials must be able to exercise the whole flow, and the panel is where
|
|
38
|
+
* the "sandbox" qualifier is shown. What is refused is a channel with nothing
|
|
39
|
+
* selected behind it, where a Pix button would produce a charge that never opens.
|
|
40
|
+
*/
|
|
41
|
+
export declare function canOfferPayment(readiness: PaymentReadiness | null): boolean;
|
|
42
|
+
//# sourceMappingURL=payment-preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-preflight.d.ts","sourceRoot":"","sources":["../../src/data/payment-preflight.ts"],"names":[],"mappings":"AAWA,mDAAmD;AACnD,eAAO,MAAM,0BAA0B,6BAA6B,CAAA;AAEpE;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG,WAAW,GAAG,aAAa,CAAA;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,oFAAoF;IACpF,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAC9B,oEAAoE;IACpE,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,2CAA2C;IAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,qFAAqF;AACrF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAqCD,wBAAsB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGvF;AAED,wBAAsB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAE7F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAG3E"}
|
package/dist/data/tables.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../src/data/tables.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,CAAC
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../src/data/tables.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,CAAC;;;;CAIJ,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -27,4 +27,7 @@ export type { ConversationsProvider } from './data/types';
|
|
|
27
27
|
export type { Conversation, Message, Channel, CreateConversationInput } from './types';
|
|
28
28
|
export { createMockConversationsProvider, type MockConversationsConfig } from './data/mock';
|
|
29
29
|
export { createSupabaseConversationsProvider, type SupabaseConversationsConfig, } from './data/supabase';
|
|
30
|
+
export { readPaymentReadiness, openPaymentSetupSession, canOfferPayment, PAYMENT_PREFLIGHT_FUNCTION, type PaymentReadiness, type PaymentActiveMode, type PaymentSetupSession, } from './data/payment-preflight';
|
|
31
|
+
export { listMessagingChannels, type MessagingChannelAccount, type MessagingChannelKind, type MessagingChannelStatus, type ListMessagingChannelsOptions, } from './data/channels';
|
|
32
|
+
export { tyxterConnectorDef, TYXTER_CONNECTOR_ID, TYXTER_LATENCY_BUDGET_MS, } from './integrations/tyxter/connectorDef';
|
|
30
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAEvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGlD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAEvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGlD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AA8BzD,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,qBAAqB,CAAA;IAEpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,aAAa,CAAC,EAAE,YAAY,CAAA;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAA;CAC7B;AA2BD,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,cAAc,CAoP9F;AAED,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AACtF,OAAO,EAAE,+BAA+B,EAAE,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAC3F,OAAO,EACL,mCAAmC,EACnC,KAAK,2BAA2B,GACjC,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,EACf,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,qBAAqB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,GAClC,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,oCAAoC,CAAA"}
|