@llmnative/react 2.3.0 → 3.0.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 (61) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +20 -21
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +6768 -6811
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/modelIdentity-CIXNPtTA.mjs +624 -0
  7. package/dist/modelIdentity-CIXNPtTA.mjs.map +1 -0
  8. package/dist/modelIdentity-DX62i7g2.js +3 -0
  9. package/dist/modelIdentity-DX62i7g2.js.map +1 -0
  10. package/dist/server-B430eH0y.mjs +352 -0
  11. package/dist/server-B430eH0y.mjs.map +1 -0
  12. package/dist/server-CDheNgME.js +2 -0
  13. package/dist/server-CDheNgME.js.map +1 -0
  14. package/dist/server.js +1 -1
  15. package/dist/server.mjs +3 -3
  16. package/dist/types/src/App.d.ts +6 -4
  17. package/dist/types/src/I18n.d.ts +2 -0
  18. package/dist/types/src/components/widgets/grid-core/GridCore.d.ts +1 -1
  19. package/dist/types/src/components/widgets/grid-core/types.d.ts +2 -0
  20. package/dist/types/src/components/widgets/grid-core/useGridDBRecords.d.ts +6 -2
  21. package/dist/types/src/index.d.ts +21 -8
  22. package/dist/types/src/libs/index.d.ts +0 -1
  23. package/dist/types/src/providers/ProviderRegistryContext.d.ts +7 -5
  24. package/dist/types/src/providers/ai/server.d.ts +20 -0
  25. package/dist/types/src/providers/api/ApiProvider.d.ts +1 -1
  26. package/dist/types/src/providers/data/DataProvider.d.ts +29 -0
  27. package/dist/types/src/providers/data/firebase.d.ts +2 -2
  28. package/dist/types/src/providers/data/firestore.d.ts +2 -2
  29. package/dist/types/src/providers/data/query.d.ts +14 -0
  30. package/dist/types/src/providers/data/useDataSubscription.d.ts +20 -0
  31. package/dist/types/src/providers/email/EmailError.d.ts +27 -0
  32. package/dist/types/src/providers/email/EmailProviderContext.d.ts +13 -7
  33. package/dist/types/src/providers/email/EmailRead.d.ts +48 -0
  34. package/dist/types/src/providers/email/EmailSend.d.ts +54 -0
  35. package/dist/types/src/providers/email/brevo/BrevoEmailSender.d.ts +21 -0
  36. package/dist/types/src/providers/email/definitions.d.ts +4 -2
  37. package/dist/types/src/providers/email/gmail/GmailEmailReader.d.ts +37 -0
  38. package/dist/types/src/providers/email/gmail/GmailEmailSender.d.ts +21 -0
  39. package/dist/types/src/providers/email/gmail/browser.d.ts +10 -0
  40. package/dist/types/src/providers/email/gmail/gmailApi.d.ts +53 -0
  41. package/dist/types/src/providers/email/gmail/gmailOAuth.d.ts +25 -0
  42. package/dist/types/src/providers/email/imap/ImapEmailReader.d.ts +70 -0
  43. package/dist/types/src/providers/email/resend/ResendEmailSender.d.ts +20 -0
  44. package/dist/types/src/providers/manifest.d.ts +7 -5
  45. package/dist/vite.js +1 -1
  46. package/dist/vite.mjs +1 -1
  47. package/llms-full.txt +1690 -1625
  48. package/llms.txt +83 -82
  49. package/package.json +18 -1
  50. package/dist/modelIdentity-CGWliGDU.mjs +0 -183
  51. package/dist/modelIdentity-CGWliGDU.mjs.map +0 -1
  52. package/dist/modelIdentity-CgRMrC5H.js +0 -2
  53. package/dist/modelIdentity-CgRMrC5H.js.map +0 -1
  54. package/dist/server-CCbjPJEz.js +0 -2
  55. package/dist/server-CCbjPJEz.js.map +0 -1
  56. package/dist/server-CiWwr3Zg.mjs +0 -107
  57. package/dist/server-CiWwr3Zg.mjs.map +0 -1
  58. package/dist/types/src/libs/email.d.ts +0 -16
  59. package/dist/types/src/providers/email/EmailProvider.d.ts +0 -10
  60. package/dist/types/src/providers/email/google/GmailEmailProvider.d.ts +0 -7
  61. package/dist/types/src/providers/email/google/email.d.ts +0 -13
@@ -1,9 +1,13 @@
1
- import { type DatabaseOptions, type RecordProps } from "../../../providers/data/DataProvider";
1
+ import { type DatabaseOptions, type DataProviderError, type RecordProps } from "../../../providers/data/DataProvider";
2
2
  type UseGridDBRecordsArgs = {
3
3
  path?: string;
4
4
  where?: DatabaseOptions["where"];
5
5
  order?: DatabaseOptions["order"];
6
6
  fieldMap?: DatabaseOptions["fieldMap"];
7
7
  };
8
- declare function useGridDBRecords<TRecord extends RecordProps>({ path, where, order, fieldMap, }: UseGridDBRecordsArgs): TRecord[];
8
+ /** The records of a `Grid` with `path`, live, and why they did not arrive (CR-129). */
9
+ declare function useGridDBRecords<TRecord extends RecordProps>({ path, where, order, fieldMap, }: UseGridDBRecordsArgs): {
10
+ records: TRecord[];
11
+ error: DataProviderError | null;
12
+ };
9
13
  export default useGridDBRecords;
@@ -3,7 +3,7 @@ export { default as App, AppProvider } from './App';
3
3
  export { useMenu } from './App';
4
4
  export type { AppProps, AppProviderProps, AppProvidersConfig, MenuConfig } from './App';
5
5
  export type { AIConfig, FirebaseConfig } from './Config';
6
- export type { ServicesConfig, SupabaseProviderConfig, GoogleProviderConfig, MockProviderConfig, DataDriverName, StorageDriverName, AuthDriverName, EmailDriverName, AIDriverName, } from './providers/manifest';
6
+ export type { ServicesConfig, SupabaseProviderConfig, GoogleProviderConfig, MockProviderConfig, DataDriverName, StorageDriverName, AuthDriverName, EmailSendDriverName, AIDriverName, } from './providers/manifest';
7
7
  export type { ProxyConfig, GitHubAuthConfig } from './Config';
8
8
  export { Head, HeadProvider, DEFAULT_DOCUMENT_HEAD, DEFAULT_HEAD_APP_NAME, DEFAULT_LANGUAGE_HEAD, useAssetsHead, useDocumentHead, useHead, useHeadLinks, useLanguageHead, usePaginationHead, usePwaHead, useSchemaOrgHead, useSocialHead, } from './Head';
9
9
  export type { HeadController, AssetsHeadState, DocumentBaseHead, DocumentHeadState, DocumentHttpEquivMeta, HeadFontAsset, HeadLinkDescriptor, HeadLinksState, HeadMetaAttributes, HeadProviderProps, HeadScriptAsset, HeadStyleAsset, LanguageAlternateLink, LanguageHeadState, OpenGraphHeadState, PageMetadataState, PaginationHeadState, PwaIconLink, PwaHeadState, SchemaOrgHeadState, SchemaOrgJson, SocialHeadState, TwitterHeadState, } from './Head';
@@ -15,7 +15,11 @@ export type { AppThemeProviderConfig, BuiltInThemeId, CardTheme, ColorScale, Gal
15
15
  export { AuthButton, useAccessToken, getAccessToken } from './auth';
16
16
  export * from './components/auth';
17
17
  export { useGlobalVars, getGlobalVars, setGlobalVars, removeGlobalVars } from './Global';
18
- export type { DataProviderAdapter, FieldValue, RecordProps, RecordArray, DatabaseOptions, DBConfig, ReadOptions, WhereClause, OrderClause, Condition } from './providers/data/DataProvider';
18
+ export type { DataProviderAdapter, FieldValue, RecordProps, RecordArray, DatabaseOptions, DBConfig, ReadOptions, WhereClause, OrderClause, Condition, DataProviderErrorCode } from './providers/data/DataProvider';
19
+ export { DataProviderError } from './providers/data/DataProvider';
20
+ export { toDataProviderError } from './providers/data/query';
21
+ export { useDataSubscription } from './providers/data/useDataSubscription';
22
+ export type { DataSubscriptionOptions, DataSubscriptionState } from './providers/data/useDataSubscription';
19
23
  export type { OrderConfig, OrderDirection } from './libs/order';
20
24
  export { Order } from './libs/order';
21
25
  export { PromptUtils } from './libs/promptUtils';
@@ -67,9 +71,20 @@ export type { GitHubSessionProfile } from './providers/auth/github/GitHubAuthPro
67
71
  export type { CredentialsAdapter } from './providers/credentials/CredentialsProvider';
68
72
  export { useCredentialsProvider } from './providers/credentials/CredentialsProviderContext';
69
73
  export { GoogleServiceAccountProvider } from './providers/credentials/google/GoogleServiceAccountProvider';
70
- export type { EmailProviderAdapter, EmailSendParams } from './providers/email/EmailProvider';
71
- export type { EmailProviderId } from './providers/email/definitions';
72
- export { EMAIL_PROVIDER_DEFINITIONS } from './providers/email/definitions';
74
+ export type { EmailSendAdapter, EmailSendParams, EmailSendResult, EmailAddress, EmailRecipient } from './providers/email/EmailSend';
75
+ export type { EmailReadAdapter, EmailMessage, EmailReadStart, EmailReadBatch, EmailReadOptions } from './providers/email/EmailRead';
76
+ export { EmailProviderError } from './providers/email/EmailError';
77
+ export type { EmailProviderErrorCode } from './providers/email/EmailError';
78
+ export type { EmailSendProviderId, EmailReadProviderId } from './providers/email/definitions';
79
+ export { EMAIL_SEND_PROVIDER_DEFINITIONS, EMAIL_READ_PROVIDER_DEFINITIONS } from './providers/email/definitions';
80
+ export { ResendEmailSender } from './providers/email/resend/ResendEmailSender';
81
+ export type { ResendEmailSenderConfig } from './providers/email/resend/ResendEmailSender';
82
+ export { BrevoEmailSender } from './providers/email/brevo/BrevoEmailSender';
83
+ export type { BrevoEmailSenderConfig } from './providers/email/brevo/BrevoEmailSender';
84
+ export { GmailEmailSender } from './providers/email/gmail/GmailEmailSender';
85
+ export type { GmailEmailSenderConfig } from './providers/email/gmail/GmailEmailSender';
86
+ export { GMAIL_SCOPES } from './providers/email/gmail/gmailApi';
87
+ export type { GmailAuth } from './providers/email/gmail/gmailApi';
73
88
  export type { BuildManifest, BuildArtifacts, DeployOptions, DeployResult, Deployment, PublishProviderAdapter } from './providers/publish/PublishProvider';
74
89
  export type { PublishProviderId } from './providers/publish/definitions';
75
90
  export { PUBLISH_PROVIDER_DEFINITIONS } from './providers/publish/definitions';
@@ -82,15 +97,13 @@ export type { AppIconProviderConfig, IconController } from './providers/icon/Ico
82
97
  export { GoogleMapsProvider, useGoogleMapsConfig } from './providers/googleMaps/GoogleMapsProviderContext';
83
98
  export { loadGoogleMaps } from './providers/googleMaps/loadGoogleMaps';
84
99
  export type { GoogleMapsConfig } from './providers/googleMaps/loadGoogleMaps';
85
- export { useEmailProvider, EmailProvider } from './providers/email/EmailProviderContext';
86
- export { GmailEmailProvider } from './providers/email/google/GmailEmailProvider';
100
+ export { useEmailSendProvider, useEmailReadProvider, EmailSendProvider, EmailReadProvider } from './providers/email/EmailProviderContext';
87
101
  export type { AIRequestOptions, AIReasoningLevel, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIModelPricing, DiscoveredAIModel, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, CloudflareProviderOptions, ServerAIProviderConnection, ServerAIConnection, ModelIdentity, ModelIdentityEntry, ModelIdentityIndex, ResolvedModel, ModelOffer, ModelCost, } from './providers/ai';
88
102
  export { createAIProviderRegistry, getAIModelCatalog, formatAIModelRef, parseAIModelRef, isFreeAIModel, AI_PROVIDER_DEFINITIONS, AI_PROVIDER_DESCRIPTORS, OPENAI_COMPATIBLE_PROVIDER_DESCRIPTOR, CLOUDFLARE_PROVIDER_DESCRIPTOR, createCloudflareProviderDefinition, toProviderDescriptor, createServerCredentialAIRegistry, serverCredential, SERVER_CREDENTIAL_PREFIX, AI_PROVIDER_HOSTS, isAIProviderTarget, canonicalModelName, buildModelIdentityIndex, resolveModel, modelOffers, loadModelIdentityIndex } from './providers/ai';
89
103
  export type { ProviderDescriptor, ProviderCredentialField } from './providers/ProviderDescriptor';
90
104
  export { useAIProvider, useAIProviderRegistry, AIProvider } from './providers/ai/AIProviderContext';
91
105
  export { proxyFetch, useProxy, configureProxy, isProxyEnabled } from './providers/proxy';
92
106
  export { googleGetAccessToken } from './providers/auth/google/GoogleAuth';
93
- export { sendEmail } from './providers/email/google/email';
94
107
  export { getKeywordIdeas } from './providers/seo/google/keyword';
95
108
  export { getGoogleTrendsData, getGoogleTrendsRelated } from './providers/seo/google/trend';
96
109
  export { dropBox, useDropBoxConnect, DropBoxConnectButton } from './providers/storage/dropbox';
@@ -2,7 +2,6 @@ export { default as path } from './path';
2
2
  export * from './editorHeight';
3
3
  export * from './converter';
4
4
  export * from './sanitizer';
5
- export * from './email';
6
5
  export * from './fetch';
7
6
  export * from './csv';
8
7
  export * from './utils';
@@ -2,18 +2,20 @@ import React from 'react';
2
2
  import type { DataProviderAdapter } from './data/DataProvider';
3
3
  import type { StorageProviderAdapter } from './storage/StorageProvider';
4
4
  import type { AuthProviderAdapter } from './auth/AuthProvider';
5
- import type { EmailProviderAdapter } from './email/EmailProvider';
5
+ import type { EmailSendAdapter } from './email/EmailSend';
6
+ import type { EmailReadAdapter } from './email/EmailRead';
6
7
  import type { AIProviderAdapter } from './ai/AIProvider';
7
8
  import type { CredentialsAdapter } from './credentials/CredentialsProvider';
8
9
  export type ProviderAdapterMap = {
9
10
  data: DataProviderAdapter;
10
11
  storage: StorageProviderAdapter;
11
12
  auth: AuthProviderAdapter;
12
- email: EmailProviderAdapter;
13
+ emailSend: EmailSendAdapter;
14
+ emailRead: EmailReadAdapter;
13
15
  ai: AIProviderAdapter;
14
16
  credentials: CredentialsAdapter;
15
17
  };
16
- /** The 6 categories the framework ships out of the box. Any other string is a valid category too — see customCategories on <App>. */
18
+ /** The 7 categories the framework ships out of the box. Any other string is a valid category too — see customCategories on <App>. */
17
19
  export type ProviderService = keyof ProviderAdapterMap;
18
20
  export type ProviderRegistrySnapshot = Record<string, {
19
21
  registry: Record<string, unknown>;
@@ -21,7 +23,7 @@ export type ProviderRegistrySnapshot = Record<string, {
21
23
  }>;
22
24
  /**
23
25
  * Replaces a single named adapter in a provider registry at runtime, in ANY
24
- * category — one of the 6 built-in ones (typed) or an arbitrary custom one a
26
+ * category — one of the 7 built-in ones (typed) or an arbitrary custom one a
25
27
  * vertical registered (string). Calls the previous adapter's dispose() (if
26
28
  * defined) only when the instance changes, then propagates the new registry to every
27
29
  * useXProvider()/useProvider() consumer. If `category` didn't exist yet, it's
@@ -43,7 +45,7 @@ export declare const ProviderRegistryProvider: ({ registries, setProvider, child
43
45
  export declare const useSetProvider: () => SetProviderFn;
44
46
  /**
45
47
  * Generic read access to any provider category — built-in or custom. Prefer the
46
- * typed useDataProvider()/useStorageProvider()/... for the 6 built-ins; reach for
48
+ * typed useDataProvider()/useStorageProvider()/... for the 7 built-ins; reach for
47
49
  * this when consuming a category the framework doesn't know about (registered via
48
50
  * providers.customCategories or a runtime setProvider() call).
49
51
  */
@@ -33,3 +33,23 @@ export type ServerCredentialResolution = {
33
33
  * placeholder can never carry a key elsewhere. A request without placeholders passes unchanged.
34
34
  */
35
35
  export declare function resolveServerCredentials(request: ServerCredentialRequest, lookup: ServerCredentialLookup): Promise<ServerCredentialResolution>;
36
+ export { EmailProviderError } from '../email/EmailError';
37
+ export type { EmailProviderErrorCode } from '../email/EmailError';
38
+ export type { EmailSendAdapter, EmailSendParams, EmailSendResult, EmailAddress, EmailRecipient } from '../email/EmailSend';
39
+ export type { EmailReadAdapter, EmailMessage, EmailReadStart, EmailReadBatch, EmailReadOptions } from '../email/EmailRead';
40
+ export { EMAIL_SEND_PROVIDER_DEFINITIONS, EMAIL_READ_PROVIDER_DEFINITIONS } from '../email/definitions';
41
+ export type { EmailSendProviderId, EmailReadProviderId } from '../email/definitions';
42
+ export { ResendEmailSender } from '../email/resend/ResendEmailSender';
43
+ export type { ResendEmailSenderConfig } from '../email/resend/ResendEmailSender';
44
+ export { BrevoEmailSender } from '../email/brevo/BrevoEmailSender';
45
+ export type { BrevoEmailSenderConfig } from '../email/brevo/BrevoEmailSender';
46
+ export { GmailEmailSender } from '../email/gmail/GmailEmailSender';
47
+ export type { GmailEmailSenderConfig } from '../email/gmail/GmailEmailSender';
48
+ export { GmailEmailReader, decodeGmailPushNotification } from '../email/gmail/GmailEmailReader';
49
+ export type { GmailEmailReaderConfig } from '../email/gmail/GmailEmailReader';
50
+ export { createGmailOAuth } from '../email/gmail/gmailOAuth';
51
+ export type { GmailOAuth, GmailOAuthConfig } from '../email/gmail/gmailOAuth';
52
+ export { GMAIL_SCOPES } from '../email/gmail/gmailApi';
53
+ export type { GmailAuth } from '../email/gmail/gmailApi';
54
+ export { ImapEmailReader } from '../email/imap/ImapEmailReader';
55
+ export type { ImapEmailReaderConfig, ImapModules } from '../email/imap/ImapEmailReader';
@@ -15,7 +15,7 @@ import type { ProviderConfigurable } from '../ProviderConfiguration';
15
15
  * Registered/fixed fields always win over a matching key the caller passes — same
16
16
  * authoritative-merge rule as the tenant-session handshake.
17
17
  *
18
- * Other category adapters (an EmailProviderAdapter for Brevo, an AIProviderAdapter for a
18
+ * Other category adapters (an EmailSendAdapter for an internal mail API, an AIProviderAdapter for a
19
19
  * REST-only model) call an ApiProviderAdapter internally instead of fetch()/proxyFetch()
20
20
  * directly — a vendor adapter is just a few lines of normal code, no framework-provided bridge.
21
21
  *
@@ -28,6 +28,10 @@ export type Condition = {
28
28
  gte?: RangeValue;
29
29
  nin?: ListValue;
30
30
  in?: ListValue;
31
+ /** CR-129 — the field is a list that holds this value (Firestore `array-contains`, Supabase `contains`). */
32
+ contains?: ScalarValue;
33
+ /** CR-129 — the field is a list that holds at least one of these values (Firestore `array-contains-any`, Supabase `overlaps`). */
34
+ containsAny?: ListValue;
31
35
  };
32
36
  export type WhereClause = {
33
37
  [field: string]: Condition | OperatorValue;
@@ -35,9 +39,32 @@ export type WhereClause = {
35
39
  export type OrderClause = {
36
40
  [field: string]: "asc" | "desc";
37
41
  };
42
+ /**
43
+ * CR-129 — why a read failed, the same on every provider: the rules refused it (`permission-denied`), there
44
+ * is no session (`unauthenticated`), the query cannot run as written, e.g. a missing index or an operator the
45
+ * database refuses (`invalid-query`), the database cannot be reached (`unavailable`), or anything else.
46
+ */
47
+ export type DataProviderErrorCode = 'permission-denied' | 'unauthenticated' | 'invalid-query' | 'unavailable' | 'unknown';
48
+ /** CR-129 — a failed read, normalized from the error of the database (kept in `cause`). */
49
+ export declare class DataProviderError extends Error {
50
+ readonly code: DataProviderErrorCode;
51
+ readonly path?: string;
52
+ readonly cause?: unknown;
53
+ constructor(code: DataProviderErrorCode, message: string, options?: {
54
+ path?: string;
55
+ cause?: unknown;
56
+ });
57
+ }
38
58
  export interface DatabaseOptions {
39
59
  where?: WhereClause;
40
60
  order?: OrderClause;
61
+ /** CR-129 — at most this many records, after `where` and `order`. */
62
+ limit?: number;
63
+ /**
64
+ * CR-129 — called when the database refuses or loses the subscription. Without it the provider logs the
65
+ * error as before; with it the page can say why the data did not arrive.
66
+ */
67
+ onError?: (error: DataProviderError) => void;
41
68
  fieldMap?: Record<string, string>;
42
69
  onLoad?: (data: RecordObject) => RecordObject;
43
70
  }
@@ -47,6 +74,8 @@ export interface DBConfig extends DatabaseOptions {
47
74
  export interface ReadOptions {
48
75
  where?: WhereClause;
49
76
  order?: OrderClause;
77
+ /** CR-129 — at most this many records, after `where` and `order`. */
78
+ limit?: number;
50
79
  toArray?: boolean;
51
80
  exception?: boolean;
52
81
  }
@@ -10,13 +10,13 @@ export declare class FirebaseDataProvider implements DataProviderAdapter {
10
10
  getConfigurationState(): ProviderConfigurationState;
11
11
  isConfigured(): boolean;
12
12
  readShallow: (path: string, exception?: boolean) => Promise<string[]>;
13
- read: (path: string, { where, order, toArray, exception }?: ReadOptions) => Promise<any>;
13
+ read: (path: string, { where, order, limit, toArray, exception }?: ReadOptions) => Promise<any>;
14
14
  update: (path: string, data: object, exception?: boolean) => Promise<void>;
15
15
  set: (path: string, data: object, exception?: boolean) => Promise<void>;
16
16
  setChunks: (path: string, data: object, { chunkSize, purge, onProgress }?: SetChunksOptions) => Promise<void>;
17
17
  remove: (path: string, exception?: boolean) => Promise<void>;
18
18
  count: (path: string) => Promise<number>;
19
- subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void, { where, order, fieldMap, onLoad }?: DatabaseOptions) => (() => void);
19
+ subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void, options?: DatabaseOptions) => (() => void);
20
20
  }
21
21
  declare const _default: FirebaseDataProvider;
22
22
  export default _default;
@@ -23,7 +23,7 @@ export declare class FirestoreDataProvider implements DataProviderAdapter {
23
23
  dispose: () => Promise<void>;
24
24
  getConfigurationState(): ProviderConfigurationState;
25
25
  isConfigured(): boolean;
26
- read: (path: string, { where, order, toArray, exception }?: ReadOptions) => Promise<any>;
26
+ read: (path: string, { where, order, limit, toArray, exception }?: ReadOptions) => Promise<any>;
27
27
  set: (path: string, data: object, exception?: boolean) => Promise<void>;
28
28
  update: (path: string, data: object, exception?: boolean) => Promise<void>;
29
29
  remove: (path: string, exception?: boolean) => Promise<void>;
@@ -39,7 +39,7 @@ export declare class FirestoreDataProvider implements DataProviderAdapter {
39
39
  * Firestore inequality filters on a field require the first orderBy() to be
40
40
  * on that same field. Pass `order` accordingly to avoid SDK errors.
41
41
  */
42
- subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void, { where, order, fieldMap, onLoad }?: DatabaseOptions) => (() => void);
42
+ subscribe: <T extends RecordProps = RecordProps>(path: string | undefined, setRecords: (records: T[]) => void, options?: DatabaseOptions) => (() => void);
43
43
  /**
44
44
  * Returns the list of document IDs in a collection without loading document
45
45
  * data - the Firestore equivalent of RTDB's ?shallow=true REST endpoint.
@@ -0,0 +1,14 @@
1
+ import { DataProviderError, type Condition, type DatabaseOptions, type OperatorValue } from './DataProvider';
2
+ /** A `where` value as a `Condition`: a list is `in`, a scalar is `eq`. */
3
+ export declare function toCondition(raw: Condition | OperatorValue): Condition;
4
+ /** Whether `value` (the field of a record) satisfies a condition of `where`. Unknown operators never match. */
5
+ export declare function matchCondition(value: unknown, raw: Condition | OperatorValue): boolean;
6
+ /** The first `limit` items (all of them without a valid limit). */
7
+ export declare function applyLimit<T>(items: T[], limit?: number): T[];
8
+ /** Any error of a database as a `DataProviderError` (an existing one is returned as it is). */
9
+ export declare function toDataProviderError(error: unknown, path?: string): DataProviderError;
10
+ /**
11
+ * Tells the page that a subscription failed: `options.onError` when it is given, else the console as the
12
+ * providers did before CR-129. Returns the normalized error.
13
+ */
14
+ export declare function reportSubscribeError(options: Pick<DatabaseOptions, 'onError'> | undefined, error: unknown, path?: string): DataProviderError;
@@ -0,0 +1,20 @@
1
+ import type { DataProviderError, DatabaseOptions, RecordArray } from './DataProvider';
2
+ export type DataSubscriptionOptions = Pick<DatabaseOptions, 'where' | 'order' | 'limit' | 'fieldMap'> & {
3
+ /** Read nothing (a page still waiting for an id): `loading` false, no records. */
4
+ skip?: boolean;
5
+ /** The name of a provider registered in `providers` (the default one without it). */
6
+ provider?: string;
7
+ };
8
+ export type DataSubscriptionState = {
9
+ records: RecordArray;
10
+ loading: boolean;
11
+ /** Why the data did not arrive (rules, session, query, network), the same on every provider. */
12
+ error: DataProviderError | null;
13
+ };
14
+ /**
15
+ * CR-129 — the records at `path`, live, from the data provider: `{ records, loading, error }`. `loading` is
16
+ * true until the first answer; a subscription the database refuses gives `error` instead of a list that never
17
+ * arrives. `where`, `order` and `limit` are compared by value, so a new object with the same content does not
18
+ * subscribe again.
19
+ */
20
+ export declare function useDataSubscription(path: string | null | undefined, options?: DataSubscriptionOptions): DataSubscriptionState;
@@ -0,0 +1,27 @@
1
+ export type EmailProviderErrorCode =
2
+ /** The adapter misses a setting (key, sender, client, library). */
3
+ 'not-configured'
4
+ /** The message itself is not valid: no recipient, no body. */
5
+ | 'invalid-message'
6
+ /** The provider refused the credentials (401/403, revoked token). */
7
+ | 'unauthorized'
8
+ /** The provider refused the message (400/422: sender not verified, address not valid). */
9
+ | 'rejected' | 'rate-limited'
10
+ /** The provider or the network did not answer. */
11
+ | 'unavailable' | 'unknown';
12
+ export declare class EmailProviderError extends Error {
13
+ readonly code: EmailProviderErrorCode;
14
+ readonly provider: string;
15
+ readonly status?: number;
16
+ constructor(code: EmailProviderErrorCode, provider: string, message: string, options?: {
17
+ status?: number;
18
+ cause?: unknown;
19
+ });
20
+ }
21
+ /** The code of an HTTP status of a provider. */
22
+ export declare const emailErrorCode: (status: number) => EmailProviderErrorCode;
23
+ /**
24
+ * A JSON call to a provider: the answer, or an `EmailProviderError` with the status and the path only.
25
+ * A network failure is `unavailable`.
26
+ */
27
+ export declare function callEmailApi<T>(provider: string, http: typeof fetch, url: string, init: RequestInit): Promise<T>;
@@ -1,12 +1,18 @@
1
1
  import React from 'react';
2
- import type { EmailProviderAdapter } from './EmailProvider';
3
- type EmailProviderContextValue = {
4
- registry: Record<string, EmailProviderAdapter>;
2
+ import type { EmailSendAdapter } from './EmailSend';
3
+ import type { EmailReadAdapter } from './EmailRead';
4
+ type Registry<T> = {
5
+ registry: Record<string, T>;
5
6
  defaultKey: string;
6
7
  };
7
- declare const EmailProviderContext: React.Context<EmailProviderContextValue | null>;
8
- export declare const EmailProvider: ({ registry, defaultKey, children, }: EmailProviderContextValue & {
8
+ export declare const EmailSendProvider: ({ registry, defaultKey, children }: Registry<EmailSendAdapter> & {
9
9
  children: React.ReactNode;
10
10
  }) => React.JSX.Element;
11
- export declare const useEmailProvider: (name?: string) => EmailProviderAdapter | null;
12
- export default EmailProviderContext;
11
+ export declare const EmailReadProvider: ({ registry, defaultKey, children }: Registry<EmailReadAdapter> & {
12
+ children: React.ReactNode;
13
+ }) => React.JSX.Element;
14
+ /** The adapter that sends (the default one, or `name`), or `null` when none is registered. */
15
+ export declare const useEmailSendProvider: (name?: string) => EmailSendAdapter | null;
16
+ /** The adapter that reads (the default one, or `name`), or `null` when none is registered. */
17
+ export declare const useEmailReadProvider: (name?: string) => EmailReadAdapter | null;
18
+ export {};
@@ -0,0 +1,48 @@
1
+ import type { ProviderConfigurable } from '../ProviderConfiguration';
2
+ export interface EmailMessage {
3
+ /** The id of the message in its mailbox. */
4
+ id: string;
5
+ /** The conversation: Gmail's thread, the Message-ID of the first message elsewhere. */
6
+ threadId: string;
7
+ /** The headers as text (`Ada <ada@example.com>`). */
8
+ from: string;
9
+ to: string;
10
+ subject: string;
11
+ /** When it arrived, ISO 8601. */
12
+ date: string;
13
+ /** The plain text: the text part, else the HTML without tags. */
14
+ text: string;
15
+ /** `outbound` for a message the mailbox sent itself (Gmail's SENT). */
16
+ direction: 'inbound' | 'outbound';
17
+ /**
18
+ * Where to read on from once this message is handled: when the app stops at a message (its handler
19
+ * failed), it keeps the `cursor` of the last one handled and the next reading starts with the rest.
20
+ * With Gmail the next reading may give again the messages of the same history record handled before it.
21
+ */
22
+ cursor: string;
23
+ }
24
+ export interface EmailReadStart {
25
+ /** Where reading goes on from: opaque, the app keeps it as it is. */
26
+ cursor: string;
27
+ /** Gmail: when its push to Pub/Sub ends; call `start()` again before. */
28
+ expiresAt?: string;
29
+ }
30
+ export interface EmailReadBatch {
31
+ messages: EmailMessage[];
32
+ /** The cursor to read on from next time. */
33
+ cursor: string;
34
+ }
35
+ export interface EmailReadOptions {
36
+ /** At most this many messages (default 50): the returned cursor goes on from the last one. */
37
+ limit?: number;
38
+ }
39
+ export interface EmailReadAdapter extends ProviderConfigurable {
40
+ /** Reading starts now: the mails already in the mailbox stay out. */
41
+ start(): Promise<EmailReadStart>;
42
+ /**
43
+ * The new mails since `cursor`, oldest first, and the cursor after them. A cursor the mailbox no longer
44
+ * knows (Gmail's history expired, IMAP's UIDVALIDITY changed) starts again from now, reading nothing old.
45
+ */
46
+ read(cursor: string, options?: EmailReadOptions): Promise<EmailReadBatch>;
47
+ }
48
+ export declare const DEFAULT_EMAIL_READ_LIMIT = 50;
@@ -0,0 +1,54 @@
1
+ import type { ProviderConfigurable } from '../ProviderConfiguration';
2
+ /** An address, with the name shown to who reads it. */
3
+ export type EmailAddress = {
4
+ email: string;
5
+ name?: string;
6
+ };
7
+ /** An address as text (`ada@example.com`) or with its name. */
8
+ export type EmailRecipient = string | EmailAddress;
9
+ export interface EmailSendParams {
10
+ /** The sender; without it, the adapter's own `from`. */
11
+ from?: EmailRecipient;
12
+ to: EmailRecipient | EmailRecipient[];
13
+ cc?: EmailRecipient | EmailRecipient[];
14
+ bcc?: EmailRecipient | EmailRecipient[];
15
+ replyTo?: EmailRecipient;
16
+ subject: string;
17
+ /** The body as HTML, as text, or both (the reader's client picks). At least one. */
18
+ html?: string;
19
+ text?: string;
20
+ /** Gmail: the conversation the message joins. The other providers ignore it. */
21
+ threadId?: string;
22
+ }
23
+ export interface EmailSendResult {
24
+ /** The id the provider gave the message. */
25
+ id: string;
26
+ threadId?: string;
27
+ }
28
+ export interface EmailSendAdapter extends ProviderConfigurable {
29
+ send(params: EmailSendParams): Promise<EmailSendResult>;
30
+ }
31
+ /** An address as `{ email, name? }`. */
32
+ export declare const toEmailAddress: (recipient: EmailRecipient) => EmailAddress;
33
+ /** One or more addresses as a list, without the empty ones. */
34
+ export declare const toEmailAddresses: (recipients: EmailRecipient | EmailRecipient[] | undefined) => EmailAddress[];
35
+ /** An address as a header shows it: `Ada <ada@example.com>`, or the bare address. */
36
+ export declare const formatEmailAddress: ({ email, name }: EmailAddress) => string;
37
+ /**
38
+ * The message an adapter sends: sender and recipients as addresses, at least one recipient and one body.
39
+ * Throws `invalid-message` or (no sender, when the provider needs one) `not-configured`.
40
+ */
41
+ export declare function prepareEmail(provider: string, params: EmailSendParams, defaultFrom: EmailRecipient | undefined, { fromRequired }?: {
42
+ fromRequired?: boolean | undefined;
43
+ }): {
44
+ from: EmailAddress | undefined;
45
+ to: EmailAddress[];
46
+ cc: EmailAddress[];
47
+ bcc: EmailAddress[];
48
+ replyTo: EmailAddress | undefined;
49
+ subject: string;
50
+ html: string | undefined;
51
+ text: string | undefined;
52
+ threadId: string | undefined;
53
+ };
54
+ export type PreparedEmail = ReturnType<typeof prepareEmail>;
@@ -0,0 +1,21 @@
1
+ import { type ProviderConfigurationState } from '../../ProviderConfiguration';
2
+ import { type EmailRecipient, type EmailSendAdapter, type EmailSendParams, type EmailSendResult } from '../EmailSend';
3
+ export declare const BREVO_EMAIL_URL = "https://api.brevo.com/v3/smtp/email";
4
+ export type BrevoEmailSenderConfig = {
5
+ apiKey: string;
6
+ /** The default sender, a sender or domain verified in Brevo. */
7
+ from?: EmailRecipient;
8
+ /** The `fetch` to use (a proxy, a test). */
9
+ fetch?: typeof fetch;
10
+ };
11
+ /**
12
+ * Sends with Brevo's transactional API (CR-130). The key is a secret: use it on a server, not in a
13
+ * browser bundle.
14
+ */
15
+ export declare class BrevoEmailSender implements EmailSendAdapter {
16
+ private readonly config;
17
+ constructor(config: BrevoEmailSenderConfig);
18
+ getConfigurationState(): ProviderConfigurationState;
19
+ isConfigured(): boolean;
20
+ send(params: EmailSendParams): Promise<EmailSendResult>;
21
+ }
@@ -1,3 +1,5 @@
1
1
  import type { ProviderDescriptor } from '../ProviderDescriptor';
2
- export type EmailProviderId = 'resend' | 'sendgrid' | 'mailgun' | 'postmark' | 'ses' | 'smtp';
3
- export declare const EMAIL_PROVIDER_DEFINITIONS: ProviderDescriptor[];
2
+ export type EmailSendProviderId = 'resend' | 'brevo' | 'gmail' | 'sendgrid' | 'mailgun' | 'postmark' | 'ses' | 'smtp';
3
+ export type EmailReadProviderId = 'gmail' | 'imap';
4
+ export declare const EMAIL_SEND_PROVIDER_DEFINITIONS: ProviderDescriptor[];
5
+ export declare const EMAIL_READ_PROVIDER_DEFINITIONS: ProviderDescriptor[];
@@ -0,0 +1,37 @@
1
+ import type { ProviderConfigurationState } from '../../ProviderConfiguration';
2
+ import { type EmailReadAdapter, type EmailReadBatch, type EmailReadOptions, type EmailReadStart } from '../EmailRead';
3
+ import { type GmailAuth } from './gmailApi';
4
+ export type GmailEmailReaderConfig = {
5
+ auth: GmailAuth;
6
+ /**
7
+ * The Pub/Sub topic Gmail notifies (`projects/<project>/topics/<name>`, with `roles/pubsub.publisher` to
8
+ * `gmail-api-push@system.gserviceaccount.com`). Without it `start()` registers no push: the app reads by polling.
9
+ */
10
+ topic?: string;
11
+ /** The label read (default `INBOX`). */
12
+ labelId?: string;
13
+ fetch?: typeof fetch;
14
+ };
15
+ /**
16
+ * Reads a Gmail mailbox (CR-130) by its history: the cursor is a `historyId`. With a `topic`, `start()` also
17
+ * asks Gmail to notify the topic of every change (the push lasts 7 days: call `start()` again before
18
+ * `expiresAt`); a notification (`decodeGmailPushNotification`) tells the app when to `read()`.
19
+ * Scope `GMAIL_SCOPES.read`.
20
+ */
21
+ export declare class GmailEmailReader implements EmailReadAdapter {
22
+ private readonly config;
23
+ constructor(config: GmailEmailReaderConfig);
24
+ getConfigurationState(): ProviderConfigurationState;
25
+ isConfigured(): boolean;
26
+ private session;
27
+ start(): Promise<EmailReadStart>;
28
+ read(cursor: string, { limit }?: EmailReadOptions): Promise<EmailReadBatch>;
29
+ }
30
+ /**
31
+ * The notification Gmail publishes on the topic: the `data` of the Pub/Sub message (base64 JSON) as
32
+ * `{ emailAddress, historyId }`, or `null` when it is not one.
33
+ */
34
+ export declare function decodeGmailPushNotification(data: string | undefined | null): {
35
+ emailAddress: string;
36
+ historyId: string;
37
+ } | null;
@@ -0,0 +1,21 @@
1
+ import type { ProviderConfigurationState } from '../../ProviderConfiguration';
2
+ import { type EmailRecipient, type EmailSendAdapter, type EmailSendParams, type EmailSendResult } from '../EmailSend';
3
+ import { type GmailAuth } from './gmailApi';
4
+ export type GmailEmailSenderConfig = {
5
+ auth: GmailAuth;
6
+ /** The sender shown; without it Gmail uses the address of the account (an alias must be set in Gmail). */
7
+ from?: EmailRecipient;
8
+ fetch?: typeof fetch;
9
+ };
10
+ /**
11
+ * Sends from a Gmail mailbox (CR-130): with the browser's Google sign-in (`auth.accessToken`), or on a server
12
+ * with the app's OAuth client and the mailbox's refresh token (scope `GMAIL_SCOPES.send`). `threadId` keeps a
13
+ * reply in its conversation.
14
+ */
15
+ export declare class GmailEmailSender implements EmailSendAdapter {
16
+ protected readonly config: GmailEmailSenderConfig;
17
+ constructor(config: GmailEmailSenderConfig);
18
+ getConfigurationState(): ProviderConfigurationState;
19
+ isConfigured(): boolean;
20
+ send(params: EmailSendParams): Promise<EmailSendResult>;
21
+ }
@@ -0,0 +1,10 @@
1
+ import { type ProviderConfigurationState } from '../../ProviderConfiguration';
2
+ import { GmailEmailSender } from './GmailEmailSender';
3
+ /**
4
+ * The `gmail` driver of the `google` provider (CR-130): sends as the user signed in with Google in the
5
+ * browser, so it is configured when `google.oAuth2.clientId` is.
6
+ */
7
+ export declare class BrowserGmailEmailSender extends GmailEmailSender {
8
+ constructor();
9
+ getConfigurationState(): ProviderConfigurationState;
10
+ }
@@ -0,0 +1,53 @@
1
+ import { type ProviderConfigurationState } from '../../ProviderConfiguration';
2
+ import { type PreparedEmail } from '../EmailSend';
3
+ import type { EmailMessage } from '../EmailRead';
4
+ export declare const GMAIL_API = "https://gmail.googleapis.com/gmail/v1/users/me";
5
+ export declare const GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
6
+ /** The scopes of Gmail: read the mailbox, send from it. */
7
+ export declare const GMAIL_SCOPES: {
8
+ readonly read: "https://www.googleapis.com/auth/gmail.readonly";
9
+ readonly send: "https://www.googleapis.com/auth/gmail.send";
10
+ };
11
+ /**
12
+ * How a Gmail adapter gets its access token: a function (the browser's Google sign-in), or the OAuth client
13
+ * of the app and the refresh token of the mailbox (a server).
14
+ */
15
+ export type GmailAuth = {
16
+ accessToken: () => Promise<string>;
17
+ } | {
18
+ clientId: string;
19
+ clientSecret: string;
20
+ refreshToken: string;
21
+ };
22
+ export declare const PROVIDER = "Gmail";
23
+ /** Whether the auth has what it needs. */
24
+ export declare function gmailConfigurationState(name: string, auth: GmailAuth | undefined): ProviderConfigurationState;
25
+ /** A fresh access token: from the function, or exchanging the refresh token. */
26
+ export declare function gmailAccessToken(auth: GmailAuth, http: typeof fetch): Promise<string>;
27
+ export declare const base64Url: (text: string) => string;
28
+ export declare const fromBase64Url: (data: string) => string;
29
+ /** The raw message (RFC 2822) in base64url, as `messages.send` takes it. */
30
+ export declare function gmailRawMessage(mail: PreparedEmail): string;
31
+ type GmailPart = {
32
+ mimeType?: string;
33
+ body?: {
34
+ data?: string;
35
+ };
36
+ parts?: GmailPart[];
37
+ };
38
+ export type GmailApiMessage = {
39
+ id: string;
40
+ threadId?: string;
41
+ labelIds?: string[];
42
+ snippet?: string;
43
+ internalDate?: string;
44
+ payload?: GmailPart & {
45
+ headers?: {
46
+ name: string;
47
+ value: string;
48
+ }[];
49
+ };
50
+ };
51
+ /** A message of the API (`format=full`) as an `EmailMessage`, with the cursor after it. */
52
+ export declare function toEmailMessage(message: GmailApiMessage, cursor: string): EmailMessage;
53
+ export {};