@fayz-ai/core 0.9.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.
Files changed (218) hide show
  1. package/README.md +2 -2
  2. package/dist/access/index.js.map +1 -1
  3. package/dist/chunk-BEGXYHS4.js +566 -0
  4. package/dist/chunk-BEGXYHS4.js.map +1 -0
  5. package/dist/chunk-ED6NBH6U.js +348 -0
  6. package/dist/chunk-ED6NBH6U.js.map +1 -0
  7. package/dist/chunk-EWKX4VUM.js +429 -0
  8. package/dist/chunk-EWKX4VUM.js.map +1 -0
  9. package/dist/chunk-LARZWDHA.js +319 -0
  10. package/dist/chunk-LARZWDHA.js.map +1 -0
  11. package/dist/chunk-OXQGRJZT.js +125 -0
  12. package/dist/chunk-OXQGRJZT.js.map +1 -0
  13. package/dist/chunk-RRYFXUQX.js +1247 -0
  14. package/dist/chunk-RRYFXUQX.js.map +1 -0
  15. package/dist/{chunk-5RJVUC6J.js → chunk-TDI6F6PT.js} +373 -25
  16. package/dist/chunk-TDI6F6PT.js.map +1 -0
  17. package/dist/{chunk-V2MSAUHO.js → chunk-UVKH6RDX.js} +211 -335
  18. package/dist/chunk-UVKH6RDX.js.map +1 -0
  19. package/dist/chunk-V53GR4UT.js +289 -0
  20. package/dist/chunk-V53GR4UT.js.map +1 -0
  21. package/dist/connector-runtime/index.d.ts +15 -0
  22. package/dist/connector-runtime/index.d.ts.map +1 -0
  23. package/dist/connector-runtime/index.js +3 -0
  24. package/dist/connector-runtime/index.js.map +1 -0
  25. package/dist/data/archetype.d.ts.map +1 -1
  26. package/dist/data/backend-env.d.ts +38 -0
  27. package/dist/data/backend-env.d.ts.map +1 -0
  28. package/dist/data/bulk.d.ts +24 -0
  29. package/dist/data/bulk.d.ts.map +1 -1
  30. package/dist/data/cached.d.ts.map +1 -1
  31. package/dist/data/custom-fields.d.ts +5 -0
  32. package/dist/data/custom-fields.d.ts.map +1 -0
  33. package/dist/data/index.d.ts +2 -1
  34. package/dist/data/index.d.ts.map +1 -1
  35. package/dist/data/index.js +3 -1
  36. package/dist/data/mock.d.ts.map +1 -1
  37. package/dist/data/platform-api.d.ts.map +1 -1
  38. package/dist/data/resolve.d.ts.map +1 -1
  39. package/dist/data/supabase.d.ts.map +1 -1
  40. package/dist/data/types.d.ts +8 -0
  41. package/dist/data/types.d.ts.map +1 -1
  42. package/dist/entity/events.d.ts +14 -0
  43. package/dist/entity/events.d.ts.map +1 -0
  44. package/dist/events/envelope.d.ts +31 -0
  45. package/dist/events/envelope.d.ts.map +1 -0
  46. package/dist/events/index.d.ts +4 -0
  47. package/dist/events/index.d.ts.map +1 -1
  48. package/dist/events/log.d.ts +44 -0
  49. package/dist/events/log.d.ts.map +1 -0
  50. package/dist/events/types.d.ts +40 -0
  51. package/dist/events/types.d.ts.map +1 -0
  52. package/dist/fields/store.d.ts +45 -0
  53. package/dist/fields/store.d.ts.map +1 -0
  54. package/dist/i18n/index.d.ts +10 -0
  55. package/dist/i18n/index.d.ts.map +1 -1
  56. package/dist/i18n/index.js +1 -1
  57. package/dist/i18n/shell-translations.en.d.ts.map +1 -1
  58. package/dist/i18n/shell-translations.pt-br.d.ts.map +1 -1
  59. package/dist/index.d.ts +45 -21
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +543 -56
  62. package/dist/index.js.map +1 -1
  63. package/dist/integrations/events.d.ts +7 -0
  64. package/dist/integrations/events.d.ts.map +1 -0
  65. package/dist/integrations/index.d.ts +533 -29
  66. package/dist/integrations/index.d.ts.map +1 -1
  67. package/dist/integrations/index.js +3 -1
  68. package/dist/integrations/permissions.d.ts +132 -0
  69. package/dist/integrations/permissions.d.ts.map +1 -0
  70. package/dist/integrations/request.d.ts +170 -0
  71. package/dist/integrations/request.d.ts.map +1 -0
  72. package/dist/integrations/runtime-token.d.ts +33 -0
  73. package/dist/integrations/runtime-token.d.ts.map +1 -0
  74. package/dist/integrations/runtime.d.ts +398 -0
  75. package/dist/integrations/runtime.d.ts.map +1 -0
  76. package/dist/integrations/settings.d.ts +102 -0
  77. package/dist/integrations/settings.d.ts.map +1 -0
  78. package/dist/integrations/store.d.ts +145 -0
  79. package/dist/integrations/store.d.ts.map +1 -0
  80. package/dist/{address/index.d.ts → lib/address.d.ts} +1 -1
  81. package/dist/{address/index.d.ts.map → lib/address.d.ts.map} +1 -1
  82. package/dist/{phone/index.d.ts → lib/phone.d.ts} +1 -1
  83. package/dist/lib/phone.d.ts.map +1 -0
  84. package/dist/{seo/index.d.ts → lib/seo.d.ts} +18 -1
  85. package/dist/lib/seo.d.ts.map +1 -0
  86. package/dist/{tenant/index.d.ts → lib/tenant.d.ts} +1 -1
  87. package/dist/lib/tenant.d.ts.map +1 -0
  88. package/dist/manifest/index.d.ts +1 -1
  89. package/dist/manifest/index.d.ts.map +1 -1
  90. package/dist/messaging/index.d.ts +3 -0
  91. package/dist/messaging/index.d.ts.map +1 -0
  92. package/dist/messaging/registry.d.ts +35 -0
  93. package/dist/messaging/registry.d.ts.map +1 -0
  94. package/dist/messaging/types.d.ts +67 -0
  95. package/dist/messaging/types.d.ts.map +1 -0
  96. package/dist/plugin/index.js +3 -1
  97. package/dist/plugin/runtime.d.ts +17 -0
  98. package/dist/plugin/runtime.d.ts.map +1 -1
  99. package/dist/registry/block-catalog.d.ts +78 -0
  100. package/dist/registry/block-catalog.d.ts.map +1 -0
  101. package/dist/registry/block-constraints.d.ts +64 -0
  102. package/dist/registry/block-constraints.d.ts.map +1 -0
  103. package/dist/registry/block-schema.d.ts +69 -0
  104. package/dist/registry/block-schema.d.ts.map +1 -0
  105. package/dist/registry/blocks.d.ts +84 -0
  106. package/dist/registry/blocks.d.ts.map +1 -0
  107. package/dist/registry/entities.d.ts +179 -0
  108. package/dist/registry/entities.d.ts.map +1 -0
  109. package/dist/registry/extension-points.d.ts +117 -0
  110. package/dist/registry/extension-points.d.ts.map +1 -0
  111. package/dist/registry/handles.d.ts +41 -0
  112. package/dist/registry/handles.d.ts.map +1 -0
  113. package/dist/registry/index.d.ts +41 -41
  114. package/dist/registry/index.d.ts.map +1 -1
  115. package/dist/registry/loaders.d.ts +55 -0
  116. package/dist/registry/loaders.d.ts.map +1 -0
  117. package/dist/registry/registry-class.d.ts +157 -0
  118. package/dist/registry/registry-class.d.ts.map +1 -0
  119. package/dist/registry/schema-check.d.ts +14 -0
  120. package/dist/registry/schema-check.d.ts.map +1 -0
  121. package/dist/router/index.d.ts +78 -1
  122. package/dist/router/index.d.ts.map +1 -1
  123. package/dist/router/index.js +1 -1
  124. package/dist/{shell-translations.pt-br-2GWRQRRP.js → shell-translations.pt-br-BM5ZFSKJ.js} +72 -3
  125. package/dist/shell-translations.pt-br-BM5ZFSKJ.js.map +1 -0
  126. package/dist/telemetry/errors.d.ts +87 -0
  127. package/dist/telemetry/errors.d.ts.map +1 -0
  128. package/dist/testing/index.js +4 -1
  129. package/dist/{testing/index.d.ts → testing.d.ts} +5 -3
  130. package/dist/testing.d.ts.map +1 -0
  131. package/dist/types/analytics.d.ts +213 -0
  132. package/dist/types/analytics.d.ts.map +1 -0
  133. package/dist/types/crud.d.ts +37 -3
  134. package/dist/types/crud.d.ts.map +1 -1
  135. package/dist/types/plugins.d.ts +138 -1
  136. package/dist/types/plugins.d.ts.map +1 -1
  137. package/package.json +9 -17
  138. package/dist/blocks/index.d.ts +0 -25
  139. package/dist/blocks/index.d.ts.map +0 -1
  140. package/dist/chunk-5RJVUC6J.js.map +0 -1
  141. package/dist/chunk-L4TLMYGC.js +0 -42
  142. package/dist/chunk-L4TLMYGC.js.map +0 -1
  143. package/dist/chunk-V2MSAUHO.js.map +0 -1
  144. package/dist/chunk-X5THHG6T.js +0 -77
  145. package/dist/chunk-X5THHG6T.js.map +0 -1
  146. package/dist/chunk-Y2C2FBQP.js +0 -35
  147. package/dist/chunk-Y2C2FBQP.js.map +0 -1
  148. package/dist/chunk-YH25Y4FW.js +0 -311
  149. package/dist/chunk-YH25Y4FW.js.map +0 -1
  150. package/dist/phone/index.d.ts.map +0 -1
  151. package/dist/seo/index.d.ts.map +0 -1
  152. package/dist/shell-translations.pt-br-2GWRQRRP.js.map +0 -1
  153. package/dist/tenant/index.d.ts.map +0 -1
  154. package/dist/testing/index.d.ts.map +0 -1
  155. package/src/access/denial.ts +0 -33
  156. package/src/access/engine.test.ts +0 -48
  157. package/src/access/engine.ts +0 -136
  158. package/src/access/index.ts +0 -14
  159. package/src/access/limits.ts +0 -18
  160. package/src/address/index.ts +0 -188
  161. package/src/app/render.tsx +0 -69
  162. package/src/blocks/index.tsx +0 -68
  163. package/src/data/archetype.ts +0 -255
  164. package/src/data/bulk.ts +0 -35
  165. package/src/data/cached.ts +0 -55
  166. package/src/data/count.test.ts +0 -152
  167. package/src/data/count.ts +0 -131
  168. package/src/data/filters.test.ts +0 -70
  169. package/src/data/filters.ts +0 -90
  170. package/src/data/index.ts +0 -11
  171. package/src/data/mock.ts +0 -90
  172. package/src/data/platform-api.ts +0 -209
  173. package/src/data/refresh.ts +0 -115
  174. package/src/data/resolve.ts +0 -126
  175. package/src/data/supabase.ts +0 -230
  176. package/src/data/types.ts +0 -50
  177. package/src/entity/index.ts +0 -2
  178. package/src/entity/registry.ts +0 -49
  179. package/src/events/index.tsx +0 -82
  180. package/src/i18n/index.ts +0 -476
  181. package/src/i18n/shell-translations.en.ts +0 -875
  182. package/src/i18n/shell-translations.pt-br.ts +0 -873
  183. package/src/index.ts +0 -217
  184. package/src/integrations/index.ts +0 -237
  185. package/src/lib/cache.ts +0 -118
  186. package/src/lib/csv.ts +0 -54
  187. package/src/lib/format.ts +0 -58
  188. package/src/manifest/app-manifest.schema.json +0 -676
  189. package/src/manifest/index.ts +0 -518
  190. package/src/manifest/serialize.ts +0 -52
  191. package/src/phone/index.ts +0 -85
  192. package/src/plugin/createSafeDataProvider.ts +0 -30
  193. package/src/plugin/index.ts +0 -1
  194. package/src/plugin/runtime.ts +0 -331
  195. package/src/registry/index.ts +0 -163
  196. package/src/router/history.ts +0 -86
  197. package/src/router/index.ts +0 -29
  198. package/src/runtime/index.ts +0 -15
  199. package/src/runtime/oauth.ts +0 -219
  200. package/src/search/engine.ts +0 -559
  201. package/src/search/index.ts +0 -25
  202. package/src/search/text.ts +0 -206
  203. package/src/search/types.ts +0 -75
  204. package/src/seo/index.ts +0 -128
  205. package/src/tenant/index.ts +0 -38
  206. package/src/testing/index.ts +0 -116
  207. package/src/types/auth.ts +0 -41
  208. package/src/types/billing.ts +0 -39
  209. package/src/types/crud.ts +0 -184
  210. package/src/types/entities.ts +0 -142
  211. package/src/types/entitlements.ts +0 -45
  212. package/src/types/i18n.ts +0 -7
  213. package/src/types/index.ts +0 -11
  214. package/src/types/org.ts +0 -137
  215. package/src/types/payment.ts +0 -44
  216. package/src/types/permissions.ts +0 -32
  217. package/src/types/plugins.ts +0 -480
  218. package/src/types/theme.ts +0 -8
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether a subscription pattern covers an event key. One implementation on
3
+ * purpose: the ingress, the settings UI and the docs' examples all have to agree
4
+ * on what `blog.post.*` means, and a second matcher is a silent divergence.
5
+ */
6
+ export declare function eventKeyMatches(pattern: string, key: string): boolean;
7
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/integrations/events.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAKrE"}
@@ -1,7 +1,29 @@
1
1
  import type * as React from 'react';
2
+ import type { ConnectorPermission } from './permissions';
3
+ import type { RequestFailureMode } from './request';
4
+ import type { Completeness, Cursor, RateLimitBudget } from './runtime';
5
+ import type { ConnectorSetting, ConnectorSettingValue } from './settings';
6
+ export { permissionActions, isDataPermission, isEventPermission, grants, connectorPermissions, connectorEntities, connectorSubscribesTo, connectorSubscribes, permissionsWrite, hasSensitivePermission, sortedPermissions, groupedPermissions, connectorGrantScopes, } from './permissions';
7
+ export type { ConnectorPermission, ConnectorPermissionAction, ConnectorResourceKind, PermissionBearing, } from './permissions';
8
+ export { eventKeyMatches } from './events';
9
+ export { CONNECTOR_RUNTIME_TOKEN_HEADER, ConnectorRuntimeTokenUnavailableError, connectorRuntimeToken, getConnectorRuntimeTokenSource, setConnectorRuntimeTokenSource, } from './runtime-token';
10
+ export type { ConnectorRuntimeTokenRequest, ConnectorRuntimeTokenSource } from './runtime-token';
11
+ export { createConnectionStore, listConnections, connectionKey, connectionStatus, connectionSettings, connectionRuns, assertSettingsAllowed, ConnectionSettingsError, CONNECTIONS_TABLE, SYNC_RUNS_TABLE, } from './store';
12
+ export type { ConnectionStore, ConnectionStoreOptions, ConnectionSaveInput, ConnectionBackedStatus, ConnectionSettingsIO, ConnectionRunsIO, ListConnectionsOptions, } from './store';
13
+ export { connectorSettings, isSettingSet, missingRequiredSettings, settingsStatus, setupStatusDetail, } from './settings';
14
+ export type { ConnectorSetting, ConnectorSettingType, ConnectorSettingOption, ConnectorSettingValue, SettingsReadiness, } from './settings';
15
+ export { runRequest, runEffect, requestPlaneSpec, hasRequestPlane, buyerIdempotencyKey, createRpcEffectLedger, RequestBlockedError, RequestPlaneError, } from './request';
16
+ export type { RequestFailureMode, DegradeReason, RequestOutcome, RequestAttempt, ResolvedRequestPlane, EffectLedger, EffectClaim, EffectClaimInput, EffectOutcome, EffectStatus, } from './request';
17
+ export { ConnectorHttpError, RateLimitExceededError, parseRetryAfter, backoffDelay, classify, statusNeedsBody, fetchWithRetry, isExpiring, paginate, createRateLimiter, sliceWindow, advanceWindow, serializeCursor, reconcileMirror, cursorCompleteness, } from './runtime';
18
+ export type { Cursor, Completeness, Verdict, AttemptOutcome, ClassifyOptions, BackoffOptions, FetchWithRetryOptions, MinimalResponse, PageResult, PaginateOptions, PaginateResult, RateLimitBudget, RateLimiter, RateLimiterOptions, MirrorRecord, ReconcileInput, ReconcileResult, } from './runtime';
2
19
  /** How a connector authenticates to its provider. */
3
20
  export type IntegrationAuthKind = 'oauth' | 'api-key' | 'mtls';
4
- export type ConnectorPlane = 'agentic' | 'sync';
21
+ export declare const CONNECTOR_CATEGORIES: readonly ["database", "payments", "banking", "erp", "logistics", "marketplace", "ecommerce", "crm", "courses", "scheduling", "messaging", "analytics", "local", "ai", "automation"];
22
+ /** A shelf in the connector catalogue. See {@link CONNECTOR_CATEGORIES}. */
23
+ export type ConnectorCategory = (typeof CONNECTOR_CATEGORIES)[number];
24
+ /** Whether a string is a category the catalogue knows. */
25
+ export declare function isConnectorCategory(value: unknown): value is ConnectorCategory;
26
+ export type ConnectorPlane = 'agentic' | 'sync' | 'request';
5
27
  /** Which side reaches for the other, from this app's point of view. */
6
28
  export type ConnectorDirection = 'inbound' | 'outbound';
7
29
  /** A tool the assistant gains once a connector is resolved on the agentic plane. */
@@ -20,32 +42,84 @@ export interface ConnectorCapability {
20
42
  direction: SyncDirection;
21
43
  triggers: SyncTrigger[];
22
44
  }
23
- /** The state of a tenant's connection to a provider (one row in a *_integrations table). */
45
+ /**
46
+ * One row of `public.plg_connections` (migration 029) — a tenant's connection to
47
+ * ONE account at one provider. Two accounts are two rows, separated by
48
+ * `instanceKey`; two resources inside one account are two streams of one row.
49
+ *
50
+ * There is no credential field because the table has no credential column.
51
+ */
24
52
  export interface ConnectionConfig {
25
- /** Provider key, e.g. 'google', 'plugbank'. */
26
- provider: string;
27
- /** Whether the connection is active and should sync. */
53
+ id?: string;
54
+ tenantId?: string;
55
+ /** Connector id, e.g. 'google-calendar', 'plugbank'. */
56
+ connectorId: string;
57
+ /** Which account at the provider. `''` for the connectors that only ever have one. */
58
+ instanceKey: string;
59
+ displayName?: string | null;
60
+ /** The tenant's switch. */
28
61
  active: boolean;
29
- /** Opaque, provider-specific config (calendar id, account id, cursor, …). Never secrets. */
30
- settings?: Record<string, unknown>;
31
- /** Last successful sync, ISO timestamp. */
32
- lastSyncAt?: string;
62
+ /** Health, observed server-side not a mirror of `active`. */
63
+ status: ConnectionStatusValue;
64
+ statusDetail?: string | null;
65
+ /** Provider-specific config, restricted to the connector's declared field keys. Never secrets. */
66
+ settings: Record<string, unknown>;
67
+ /** The provider's own id for the account — how an inbound webhook finds the tenant. */
68
+ providerAccountKey?: string | null;
69
+ /** Resume state keyed BY STREAM: Google keeps a syncToken per calendar, not per connection. */
70
+ cursors: Record<string, Cursor>;
71
+ lastSyncAt?: string | null;
72
+ createdAt?: string;
73
+ updatedAt?: string;
33
74
  }
34
- /** Audit record of one sync execution (generalizes *_sync_log / *_sync_runs). */
75
+ /** Server-observed health of a connection (`plg_connections.status`). */
76
+ export type ConnectionStatusValue = 'pending' | 'connected' | 'error' | 'revoked';
77
+ /** One row of `public.plg_sync_runs` (migration 029) — one execution of the sync plane. */
35
78
  export interface SyncRun {
36
79
  id?: string;
37
- provider: string;
38
- direction: SyncDirection;
39
- trigger: SyncTrigger;
80
+ tenantId?: string;
81
+ /** Which connection ran. Without it two bank accounts share one history. */
82
+ connectionId: string;
83
+ connectorId: string;
84
+ direction: ConnectorDirection;
85
+ /** `trigger` is a reserved word in Postgres; the column is `trigger_kind`. */
86
+ triggerKind: SyncTrigger;
87
+ status: 'running' | 'success' | 'partial' | 'error';
88
+ /** Which resource inside the account this run touched. */
89
+ stream?: string | null;
90
+ fetched?: number;
91
+ written?: number;
92
+ /** Counters that are the connector's own: duplicates, discovered, period_from/to. */
93
+ stats?: Record<string, unknown>;
94
+ /** The cursor this run advanced to, serialised. */
95
+ cursor?: string | null;
96
+ /** Ties an outbound push to the inbound echo it will provoke. */
97
+ correlationId?: string | null;
98
+ /**
99
+ * What the run has to SAY, on any status (migration 031). `error` is what went
100
+ * WRONG; a successful run with something to report used to smuggle it through
101
+ * `stats.message`, which is the ad-hoc convention the generic table exists to
102
+ * prevent.
103
+ */
104
+ message?: string | null;
105
+ error?: string | null;
106
+ startedAt?: string;
107
+ finishedAt?: string | null;
108
+ }
109
+ /**
110
+ * What a connector's sync returns. Distinct from {@link SyncRun}: `completeness`
111
+ * is not a column, it is the verdict the engine needs BEFORE it decides whether
112
+ * records missing from this result may be cancelled locally.
113
+ */
114
+ export interface SyncResult {
40
115
  status: 'success' | 'partial' | 'error';
41
- /** Items pulled/pushed and how many were written. */
116
+ completeness: Completeness;
42
117
  fetched?: number;
43
118
  written?: number;
44
- /** Pagination/incremental cursor advanced by this run. */
45
- cursor?: string;
119
+ /** Advanced cursor, to be written back under its stream key. */
120
+ cursor?: Cursor;
121
+ stats?: Record<string, unknown>;
46
122
  error?: string;
47
- startedAt?: string;
48
- finishedAt?: string;
49
123
  }
50
124
  export interface TestConnectionResult {
51
125
  ok: boolean;
@@ -67,35 +141,194 @@ export interface Connector {
67
141
  capabilities: ConnectorCapability[];
68
142
  /** Validate the stored credentials/config without syncing. */
69
143
  testConnection?(config: ConnectionConfig): Promise<TestConnectionResult>;
70
- /** Run a sync for the given direction; returns the audit record. */
144
+ /** Run a sync for the given direction; the caller files the run server-side. */
71
145
  sync?(input: {
72
146
  config: ConnectionConfig;
73
147
  direction: SyncDirection;
74
148
  trigger: SyncTrigger;
75
- }): Promise<SyncRun>;
149
+ }): Promise<SyncResult>;
76
150
  }
77
- /** A credential input the unified setup form renders for an api-key/mtls connector. */
151
+ /**
152
+ * An input the connect step renders — **what authorizes the connection**, and
153
+ * nothing else.
154
+ *
155
+ * The rule, in one line: if the connection cannot be established without it, it
156
+ * is a field; if it changes how a live connection behaves, it is a
157
+ * {@link ConnectorSetting}. An API key is a field. The account identifier the
158
+ * key is scoped to is a field. Which payment methods the store accepts, or which
159
+ * postcode it ships from, is not — see ./settings.ts.
160
+ *
161
+ * `type: 'password'` is the marker the credential seam reads: a password field
162
+ * never reaches connector-author code and never reaches
163
+ * `plg_connections.settings`.
164
+ */
78
165
  export interface ConnectorField {
79
166
  key: string;
80
167
  label: string;
81
168
  type: 'text' | 'password';
82
169
  placeholder?: string;
170
+ /**
171
+ * Route this to the credential sink even though it is not masked.
172
+ *
173
+ * For the half of a credential PAIR that is not itself confidential — AppMax
174
+ * issues `client_id` alongside `client_secret`, and the id is useless to
175
+ * anyone without the secret. Masking it would only stop the merchant checking
176
+ * they pasted the right one; letting it fall through to the connector's own
177
+ * `saveConnection` would split one credential across two stores, which is
178
+ * how half of it ends up in a pool table.
179
+ */
180
+ secret?: boolean;
181
+ }
182
+ /**
183
+ * A door the merchant goes through AT THE PROVIDER before the connect step can
184
+ * be finished — and the reason the hub does not have to know which provider.
185
+ *
186
+ * Not every partner hands back a code on a redirect. AppMax issues the
187
+ * `client_id`/`client_secret` pair when the merchant INSTALLS our app inside
188
+ * their own AppMax admin ("chaves emitidas na instalação do app"), and only
189
+ * then shows them something to copy. An OAuth button there would be a button
190
+ * that lies: nothing comes back, and pressing it could never connect anything.
191
+ * What is true is a two-step gesture — go install it there, come back and paste
192
+ * what it showed you — so the gesture is declared and the panel renders it
193
+ * above {@link ConnectorDefinition.fields}.
194
+ *
195
+ * Declared and not hardcoded in the UI because the address is a fact about
196
+ * THIS app's registration at that provider, which the hub cannot know and a
197
+ * second connector with the same gesture will spell differently.
198
+ *
199
+ * An OAuth connector declares none: consent is the install.
200
+ */
201
+ export interface ConnectorProviderInstall {
202
+ /** Where the merchant installs this app at the provider. Opened in a new tab. */
203
+ url: string;
204
+ }
205
+ /**
206
+ * What the hub knows about who is connecting, handed to
207
+ * {@link ConnectorDefinition.startOAuth}.
208
+ *
209
+ * `tenantId` is a SELECTOR and never an assertion: the platform proves
210
+ * membership from the token it was called with and refuses anything outside it,
211
+ * so naming an organization here narrows which of the caller's own orgs the
212
+ * consent is for and can never widen it. Without it a merchant who belongs to
213
+ * two organizations cannot be told apart from one who belongs to neither.
214
+ */
215
+ export interface ConnectorConnectContext {
216
+ tenantId?: string;
217
+ }
218
+ /**
219
+ * An automation the connector owns rather than the tenant.
220
+ *
221
+ * "New sale → send it to Bling" is not a preference someone chose; it is what
222
+ * the integration IS. So it appears in the automations screen only while the
223
+ * connection is live, and the screen must not offer to delete it — a deleted
224
+ * row would leave the integration connected and silently half-wired, which
225
+ * reads as "Bling stopped working" weeks later. Disconnecting is the way out.
226
+ */
227
+ export interface ConnectorManagedAutomation {
228
+ /** Domain event that fires it. Must be covered by `subscribesTo`. */
229
+ eventKey: string;
230
+ /** What the tenant is told it does ("Send the sale to Bling"). */
231
+ label: string;
232
+ /** Whether the tenant may switch it off and stay connected. Default false. */
233
+ optional?: boolean;
234
+ }
235
+ /** One call site that invokes a connector, and what happens there. */
236
+ export interface ConnectorInvocation {
237
+ /**
238
+ * Stable call-site key, `<plugin>.<surface>.<verb>` —
239
+ * `shop.checkout.shipping_quote`. Not an event key: nothing publishes it, it
240
+ * names a place in the code, and it is what a support conversation and a trace
241
+ * will call the same call.
242
+ */
243
+ key: string;
244
+ /** What the tenant is told happens there ("O cliente pede as opções de frete"). */
245
+ label: string;
246
+ /**
247
+ * Which plane carries the call. Default `'request'` — the buyer is waiting.
248
+ * `'sync'` for the effects a request leads to (capture the payment, buy the
249
+ * label), which DO file a run.
250
+ */
251
+ plane?: Extract<ConnectorPlane, 'request' | 'sync'>;
252
+ /** Sync moments only: what fires it, in `plg_sync_runs.trigger_kind`'s words. */
253
+ trigger?: SyncTrigger;
254
+ /**
255
+ * Which declared resources this call reaches — `permissions[].resource` names.
256
+ *
257
+ * The half of "quando ele age" that was missing: the section said *when* a
258
+ * connector is called and never *what it gets at*. Naming the resource rather
259
+ * than restating the access is what keeps the two from disagreeing — a moment
260
+ * cannot reach something the connector did not ask for, and the contract check
261
+ * enforces exactly that.
262
+ */
263
+ touches?: string[];
264
+ }
265
+ /** The plane a moment runs on when it does not say. */
266
+ export declare function invocationPlane(moment: ConnectorInvocation): Extract<ConnectorPlane, 'request' | 'sync'>;
267
+ /**
268
+ * The two entries a first load has when the provider's catalogue is big enough
269
+ * that pulling it in line is not an option.
270
+ *
271
+ * Keeping them apart is forced by the budget, not by taste: at 3 req/s a
272
+ * ten-thousand-product catalogue is nearly an hour, and a connect screen that
273
+ * waits for it is a connect screen nobody finishes.
274
+ */
275
+ export interface ConnectorFirstLoad {
276
+ /** How many records the fast phase pulls before answering. */
277
+ sampleSize: number;
278
+ /** Pages the fast phase may spend. A sample that pages forever is a backfill. */
279
+ samplePages?: number;
280
+ /** Which stream the phases walk (`'products'`, `'orders'`). */
281
+ stream: string;
83
282
  }
84
283
  export interface ConnectorStatus {
85
284
  connected: boolean;
86
285
  detail?: string;
286
+ /**
287
+ * What is wrong with a live connection, in sentences a merchant can act on.
288
+ *
289
+ * `detail` is one line and is what a LIST row has room for; a connection can
290
+ * be unwell in more than one way at once (the watch expired AND the timezone
291
+ * drifted), and a connector that had more to say used to say it in its own
292
+ * panel — which put status on the settings tab and left `detail` repeating the
293
+ * first item. Declaring both is what lets the surface render the list once and
294
+ * fall back to `detail` when there is nothing to enumerate.
295
+ */
296
+ issues?: string[];
87
297
  /** Which plane the live connection is running on (when connected). */
88
298
  plane?: ConnectorPlane;
299
+ /**
300
+ * Connected, and unable to do its job until a required-to-operate setting is
301
+ * chosen — `plg_connections.status = 'pending'`.
302
+ *
303
+ * Not a third kind of "connected": the connection is real, the authorization
304
+ * happened, and nothing about it needs redoing. What is missing is
305
+ * configuration, which is why it is reported here rather than by pretending
306
+ * the connect step failed. See {@link settingsStatus}.
307
+ */
308
+ needsSetup?: boolean;
309
+ /** Which setting keys are missing. Keys only — never what the tenant typed. */
310
+ missingSettings?: string[];
89
311
  }
90
312
  /**
91
313
  * UI-facing connector descriptor. Built on the data-plane `Connector` concept
92
314
  * (`pluginId` → `hostPluginId`), plus the control-plane hooks the unified
93
315
  * Integrations hub calls. Lives in core so `PluginManifest.connectors` can type
94
- * it; the rendering hub lives in `@fayz-ai/saas`.
316
+ * it; the rendering hub lives in `@fayz-ai/admin`.
95
317
  */
96
318
  export interface ConnectorDefinition {
97
319
  /** Stable connector id, e.g. 'google-calendar', 'plugbank'. */
98
320
  id: string;
321
+ /**
322
+ * The platform catalogue slug this connector IS, when it differs from `id`.
323
+ *
324
+ * `id` names the implementation and `slug` names the provider, and they are
325
+ * only usually the same word: `plugbank` is the catalogue's `tecnospeed`.
326
+ * The tie matters twice — it is what lends
327
+ * an installed connector the catalogue's localized copy and brand mark, and
328
+ * what tells a slug a module declared in {@link PluginManifest.integrations}
329
+ * apart from one still to be built.
330
+ */
331
+ catalogSlug?: string;
99
332
  /** The plugin this connector extends, e.g. 'financial', 'agenda'. */
100
333
  hostPluginId: string;
101
334
  name: string;
@@ -111,33 +344,304 @@ export interface ConnectorDefinition {
111
344
  authKind: IntegrationAuthKind;
112
345
  /** Planes this connector can be honoured on. Default: `['sync']`. */
113
346
  planes?: ConnectorPlane[];
347
+ /**
348
+ * Request plane only, and required there: how long the buyer may wait before
349
+ * `onFailure` applies. No default — see {@link requestPlaneSpec}.
350
+ */
351
+ latencyBudgetMs?: number;
352
+ /**
353
+ * Request plane only, and required there. `'degrade'` serves a worse answer
354
+ * and the sale continues; `'block'` refuses the step and the buyer is told
355
+ * why. A field, not a decision re-taken in every screen that calls it.
356
+ */
357
+ onFailure?: RequestFailureMode;
114
358
  /** Default `'outbound'` — this app reaching a provider. */
115
359
  direction?: ConnectorDirection;
116
360
  /** What the assistant gains on the agentic plane — shown before connecting. */
117
361
  agentTools?: ConnectorAgentTool[];
118
- /** Canonical entities this connector touches ('booking', 'movement'). */
362
+ /**
363
+ * **What this connector needs access to, and why** — the one declaration the
364
+ * consent view, "quando ele age" and (eventually) the minted credential all
365
+ * read. See ./permissions.ts.
366
+ *
367
+ * It SUBSUMES {@link entities} and {@link subscribesTo}: declare permissions
368
+ * and both are derived ({@link connectorEntities}, {@link connectorSubscribesTo}).
369
+ * Declaring a permission and a contradicting legacy field fails the contract
370
+ * check rather than being merged — a connector that says it writes `booking`
371
+ * in one field and never mentions `booking` in the other has a bug, and
372
+ * picking a winner would hide it.
373
+ */
374
+ permissions?: ConnectorPermission[];
375
+ /**
376
+ * Canonical entities this connector touches ('booking', 'movement').
377
+ *
378
+ * Superseded by {@link permissions}, which says read or write rather than only
379
+ * the name. Still read for connectors built against an older core; when both
380
+ * are present they must name the same set. Read it through
381
+ * {@link connectorEntities}, never off the field.
382
+ */
119
383
  entities?: string[];
120
- /** Catalog category ('scheduling', 'payments', …) — matches the Fayz catalog. */
121
- category?: string;
384
+ /**
385
+ * The catalogue shelf, from the closed vocabulary in
386
+ * {@link CONNECTOR_CATEGORIES}. Typed rather than free-form because the badge
387
+ * that renders it is keyed by this exact string: an unlisted one renders no
388
+ * badge at all, which is invisible in review and invisible in the screenshot.
389
+ */
390
+ category?: ConnectorCategory;
391
+ /**
392
+ * The provider's call budget for ONE account, declared rather than discovered.
393
+ *
394
+ * The scheduler owns the clock ({@link createRateLimiter}); a `sleep` inside a
395
+ * connector's fetch helper cannot express a daily ceiling and cannot be shared
396
+ * between two streams pulling at the same time. Declaring it is also what
397
+ * makes "never one request per product" a checkable statement instead of a
398
+ * habit — see {@link firstLoad}.
399
+ */
400
+ rateLimit?: RateLimitBudget;
401
+ /**
402
+ * How the first load enters, when the catalogue is too large to fetch in line.
403
+ *
404
+ * Two phases, because they answer different questions: `sample` returns in
405
+ * seconds and is what a briefing or a generated storefront is designed
406
+ * against; `backfill` runs in the background against the budget and is what
407
+ * makes the mirror complete. Absent = the first load is just a sync.
408
+ */
409
+ firstLoad?: ConnectorFirstLoad;
122
410
  /** Provider documentation, linked from the connector's detail. */
123
411
  docsUrl?: string;
124
- /** Declarative credentials — the unified form renders these (api-key / mtls). */
412
+ /**
413
+ * What AUTHORIZES the connection — the connect step renders exactly these and
414
+ * nothing more (api-key / mtls). An OAuth connector declares none: consent is
415
+ * the whole form.
416
+ *
417
+ * A connector whose credential lives in the Fayz platform declares none
418
+ * either, and the connect step says so rather than drawing an empty grid.
419
+ */
125
420
  fields?: ConnectorField[];
421
+ /**
422
+ * The provider-side install the merchant must do first, when there is one.
423
+ * Rendered above `fields`. See {@link ConnectorProviderInstall}.
424
+ */
425
+ providerInstall?: ConnectorProviderInstall;
426
+ /**
427
+ * How the live connection BEHAVES — asked for only after it exists.
428
+ *
429
+ * The split is the point. Everything here changes with the season and none of
430
+ * it belongs in front of someone who has not connected yet; see ./settings.ts.
431
+ * Declaring a setting also allow-lists its key for
432
+ * `plg_connections.settings`, so a connector needs it in one place, not two.
433
+ */
434
+ settings?: ConnectorSetting[];
435
+ /** Current values for the settings form. Required whenever `settings` is declared. */
436
+ getSettings?(): Promise<Record<string, unknown>>;
437
+ /** Persist a settings patch — merged by key, never replacing the jsonb. */
438
+ saveSettings?(values: Record<string, ConnectorSettingValue>): Promise<void>;
439
+ /**
440
+ * The moments this connector is CALLED at — the request plane's answer to
441
+ * "acionado quando?". See {@link ConnectorInvocation}.
442
+ */
443
+ invokedAt?: ConnectorInvocation[];
444
+ /**
445
+ * Domain-event keys this connector reacts to — exact keys or `*`-suffixed
446
+ * prefixes (`agenda.booking_created`, `blog.post.*`). The ingress reads it to
447
+ * decide which facts are worth waking the connector for; without it every
448
+ * connector would have to be handed every event and filter it itself.
449
+ *
450
+ * Superseded by a `kind: 'event'` {@link permissions} entry carrying `listen`,
451
+ * which says the same thing plus why. Same agreement rule as {@link entities}.
452
+ * Read it through {@link connectorSubscribesTo}, never off the field.
453
+ */
454
+ subscribesTo?: string[];
455
+ /** Automations this connector owns. See {@link ConnectorManagedAutomation}. */
456
+ managedAutomations?: ConnectorManagedAutomation[];
126
457
  /** Current connection state for the status badge. */
127
458
  getStatus(): Promise<ConnectorStatus>;
459
+ /**
460
+ * The same answer as {@link getStatus}, derived from a `plg_connections` row a
461
+ * caller already holds.
462
+ *
463
+ * Declaring it is what lets a list of N connectors resolve in ONE batched read
464
+ * (`listConnections`) instead of N `getStatus()` round trips — the connectors
465
+ * screen used to issue one request per row. Pure by contract: it is handed a
466
+ * row, it must not fetch.
467
+ *
468
+ * Absent means "my truth is not in that table" (Stripe Connect derives from
469
+ * the provider), and the list falls back to calling `getStatus()`. Use
470
+ * {@link connectionStatus} to write both from one function.
471
+ */
472
+ statusFromConnection?(connection: ConnectionConfig | null): ConnectorStatus;
473
+ /** Which account at the provider `statusFromConnection` reads. Default `''`. */
474
+ instanceKey?: string;
128
475
  /** Validate credentials without persisting (api-key / mtls). */
129
476
  testConnection?(values: Record<string, string>): Promise<TestConnectionResult>;
130
477
  /** Persist the connection (api-key / mtls). */
131
478
  saveConnection?(values: Record<string, string>): Promise<void>;
132
- /** Begin an OAuth connect flow — returns the consent URL to redirect to. */
133
- startOAuth?(redirectTo?: string): Promise<string>;
479
+ /**
480
+ * Begin an OAuth connect flow — returns the consent URL to redirect to.
481
+ *
482
+ * `context` is optional so a connector written against an older core keeps
483
+ * compiling; the hub always passes it. See {@link ConnectorConnectContext}.
484
+ */
485
+ startOAuth?(redirectTo?: string, context?: ConnectorConnectContext): Promise<string>;
134
486
  /** Tear down the connection. */
135
487
  disconnect?(): Promise<void>;
488
+ /**
489
+ * What unplugging costs, when the answer is not obvious.
490
+ *
491
+ * A mirror that freezes is not a catalogue that is deleted, and a merchant
492
+ * who cannot tell the two apart never presses the button. Rendered beside
493
+ * Desconectar, which is the only place the question is ever asked.
494
+ */
495
+ disconnectNote?: string;
496
+ /**
497
+ * When this connector syncs, in the merchant's words.
498
+ *
499
+ * The first question anyone has after connecting, and one the screen could
500
+ * not answer: the cadence lives in `plg_connector_schedules`, the on-write
501
+ * wake in a database trigger, the manual run in a button — three places, none
502
+ * of them a sentence. Rendered on Visão geral.
503
+ */
504
+ howItSyncs?: string[];
136
505
  /** Move an existing connection between planes (only when `planes` has both). */
137
506
  setPlane?(plane: ConnectorPlane): Promise<void>;
138
- /** Optional connector-specific UI below the connect panel (import / sync / history). */
507
+ /**
508
+ * What this connection has DONE — newest first.
509
+ *
510
+ * The surface renders one history for every connector, so a connector
511
+ * declares where its runs are and nothing about how they look. Store-backed
512
+ * connectors get it from {@link connectionRuns}; a connector whose runs live
513
+ * in its own table maps them onto {@link SyncRun} here, which is the only
514
+ * shape the view knows.
515
+ *
516
+ * Absent means "I keep no history", and the surface offers no history tab —
517
+ * never an empty one, which would read as "nothing ever ran".
518
+ */
519
+ listRuns?(options?: {
520
+ limit?: number;
521
+ }): Promise<SyncRun[]>;
522
+ /**
523
+ * The connector's own actions that PRODUCE a run — sync now, import a
524
+ * statement, pull events from a date.
525
+ *
526
+ * Deliberately separate from {@link ExtraPanel}: an import is something
527
+ * somebody does once, and it was rendered beside a settings form, which is
528
+ * where the two got confused. Rendered above the history, because the history
529
+ * is where its effect shows up.
530
+ *
531
+ * `onRan` reloads that history — call it after the action lands.
532
+ */
533
+ RunActions?: React.ComponentType<{
534
+ onRan?: () => void;
535
+ }>;
536
+ /**
537
+ * The same thing as {@link RunActions}, DECLARED instead of drawn.
538
+ *
539
+ * What differs between two connectors is the sentence on the button and the
540
+ * call behind it. Spinner, toast, reloading the history, confirming a write at
541
+ * the provider — the surface owns all of it, or two integrations end up
542
+ * feeling like two products.
543
+ *
544
+ * Both seams render, so a connector can migrate one action at a time.
545
+ */
546
+ syncActions?: ConnectorSyncAction[];
547
+ /**
548
+ * Record by record: what reached the provider, what is queued, what was
549
+ * refused. The seam the automations screen reads — a managed automation could
550
+ * only show that the fact FIRED, never that anything arrived.
551
+ */
552
+ listDeliveries?(options?: {
553
+ eventKey?: string;
554
+ limit?: number;
555
+ }): Promise<ConnectorDelivery[]>;
556
+ /**
557
+ * The connector's own CONFIGURATION UI, rendered on the Settings tab.
558
+ *
559
+ * Configuration only: which Google calendar maps to which professional, which
560
+ * warehouse a stream belongs to. Status belongs in {@link ConnectorStatus},
561
+ * history in {@link listRuns}, and a one-off action in {@link RunActions} —
562
+ * this panel used to hold all four at once.
563
+ */
139
564
  ExtraPanel?: React.ComponentType;
140
565
  }
566
+ /**
567
+ * One RECORD's journey to the provider — "cadastrei aqui, foi?".
568
+ *
569
+ * A {@link SyncRun} says "12 of 20 filed", which is the number that does not
570
+ * help the person holding order 1042 in their hand.
571
+ */
572
+ export interface ConnectorDelivery {
573
+ /** The record, as the merchant would name it: "Pedido 1042", "Costela defumada". */
574
+ subject: string;
575
+ /** This app's id for it, when a screen wants to link back to the record. */
576
+ subjectId?: string;
577
+ /** `pending` is a real answer: queued, not yet sent — what the merchant sees
578
+ * in the fifteen minutes between a sale and the clock. */
579
+ status: 'delivered' | 'pending' | 'failed';
580
+ /** Why it is pending or failed, in the merchant's language. */
581
+ detail?: string;
582
+ /** The id or number it got at the provider. The one thing checkable on both screens. */
583
+ externalId?: string;
584
+ /** When it was delivered, or when the record was created if it was not. */
585
+ at?: string;
586
+ }
587
+ /** What a run actually did. `partial` and `error` are toasted as such. */
588
+ export interface ConnectorSyncOutcome {
589
+ message: string;
590
+ status?: 'success' | 'partial' | 'error';
591
+ }
592
+ /** One thing a merchant can make a connection DO. Declared rather than drawn —
593
+ * see {@link ConnectorDefinition.syncActions}. */
594
+ export interface ConnectorSyncAction {
595
+ /** Stable, for React keys and for telling two actions apart in a test. */
596
+ key: string;
597
+ /** The button. A verb, in the merchant's language: "Trazer catálogo do Bling". */
598
+ label: string;
599
+ /** Which way the data moves. Outbound is a write the merchant cannot undo
600
+ * from this screen, which is what `confirm` is for. */
601
+ direction: 'inbound' | 'outbound';
602
+ /** One line under the label, when the label alone cannot carry it. */
603
+ description?: string;
604
+ /**
605
+ * The action somebody came here to press — the one that is right on an
606
+ * ordinary day. At most one. The rest fold under "Outras ações": five equal
607
+ * buttons is a menu the reader has to grade themselves.
608
+ */
609
+ primary?: boolean;
610
+ /** Ask first. Only for what cannot be taken back. */
611
+ confirm?: {
612
+ title: string;
613
+ body: string;
614
+ cta: string;
615
+ };
616
+ /**
617
+ * Do it. What it returns becomes the toast — use the run's own sentence, so
618
+ * the merchant reads the same words here and in the history below.
619
+ *
620
+ * Return a {@link ConnectorSyncOutcome} when the run can partly fail: a push
621
+ * that filed 0 of 9 answers 200 with a sentence, and a surface that reads only
622
+ * "it did not throw" celebrates it. The verdict is already computed where the
623
+ * work happened; this is how it reaches the screen.
624
+ */
625
+ run(): Promise<string | ConnectorSyncOutcome | void>;
626
+ /**
627
+ * How many records are still waiting for this action.
628
+ *
629
+ * `0` means there is nothing left to send, and the surface says so — a check
630
+ * and a spent button, not a live control that would file nothing. A push whose
631
+ * queue is an absence can always answer this; a pull cannot know what changed
632
+ * at the provider, so it declares nothing and stays enabled.
633
+ */
634
+ pending?(): Promise<number | null> | number | null;
635
+ /** Whether to offer it at all. Hidden, not disabled: a greyed button reads as
636
+ * something the reader failed to do. Absent means always. */
637
+ available?(): Promise<boolean> | boolean;
638
+ /** A screen of its own, for an action that needs choices first. Replaces the
639
+ * row while open; call `onRan` when something actually happened. */
640
+ Component?: React.ComponentType<{
641
+ onClose(): void;
642
+ onRan?(): void;
643
+ }>;
644
+ }
141
645
  /** Planes a connector supports — the contract's default is the sync pipeline. */
142
646
  export declare function connectorPlanes(def: Pick<ConnectorDefinition, 'planes'>): ConnectorPlane[];
143
647
  /**