clivly 0.9.6 → 0.9.7

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 (58) hide show
  1. package/README.md +15 -3
  2. package/core-auth-adapter.cjs +1 -1
  3. package/core-auth-adapter.mjs +1 -1
  4. package/core-drizzle.cjs +1 -1
  5. package/core-drizzle.d.cts +1 -1
  6. package/core-drizzle.d.mts +1 -1
  7. package/core-drizzle.mjs +1 -1
  8. package/core-entity-config.cjs +1 -1
  9. package/core-entity-config.mjs +1 -1
  10. package/core-mapping-form.cjs +1 -1
  11. package/core-mapping-form.mjs +1 -1
  12. package/core-mappings-config.cjs +1 -1
  13. package/core-mappings-config.mjs +1 -1
  14. package/core-sync-engine.cjs +1 -1
  15. package/core-sync-engine.mjs +1 -1
  16. package/core-view-compiler.cjs +1 -1
  17. package/core-view-compiler.mjs +1 -1
  18. package/core.cjs +4 -5
  19. package/core.mjs +4 -4
  20. package/{drizzle-CiK8MMEZ.d.mts → drizzle-BmDDgAIF.d.mts} +3 -1
  21. package/{drizzle-bfjVzYR6.cjs → drizzle-DcB7OfBp.cjs} +9 -1
  22. package/{drizzle-DEtRrqtc.d.cts → drizzle-ixVV4pPN.d.cts} +3 -1
  23. package/{drizzle-3kvhkwO7.mjs → drizzle-wbcuG-cy.mjs} +9 -1
  24. package/drizzle.cjs +56 -22
  25. package/drizzle.d.cts +9 -3
  26. package/drizzle.d.mts +9 -3
  27. package/drizzle.mjs +56 -22
  28. package/{entity-config-CusbTOJ1.mjs → entity-config-C8IIkrmX.mjs} +33 -4
  29. package/{entity-config-DE30_RpU.cjs → entity-config-CPM-Tp-d.cjs} +33 -4
  30. package/index.cjs +34 -3
  31. package/index.mjs +34 -3
  32. package/{internal-BQ47iN6f.cjs → internal-BLKMnIIZ.cjs} +1 -1
  33. package/{internal-ChufvXE6.mjs → internal-BpVh_J77.mjs} +1 -1
  34. package/internal-drizzle.cjs +1 -1
  35. package/internal-drizzle.d.cts +1 -1
  36. package/internal-drizzle.d.mts +1 -1
  37. package/internal-drizzle.mjs +1 -1
  38. package/internal-entity-config.cjs +1 -1
  39. package/internal-entity-config.mjs +1 -1
  40. package/internal-entity-heuristics.cjs +1 -1
  41. package/internal-entity-heuristics.mjs +1 -1
  42. package/internal-mappings-config.cjs +1 -1
  43. package/internal-mappings-config.mjs +1 -1
  44. package/internal.cjs +3 -3
  45. package/internal.mjs +3 -3
  46. package/{mappings-config-CjCmT-aU.cjs → mappings-config-CBwL3FVh.cjs} +1 -1
  47. package/{mappings-config-7qQ47p9K.mjs → mappings-config-DUKBe6OS.mjs} +1 -1
  48. package/{namespace-probe-Ckn9yJ6F.d.mts → namespace-probe-BQ4imnV7.d.mts} +41 -1
  49. package/{namespace-probe-DaTJINS-.d.cts → namespace-probe-DZIGdvlm.d.cts} +41 -1
  50. package/package.json +1 -1
  51. package/{sdk-w8Kv_XnW.cjs → sdk-BL9BCzyD.cjs} +324 -14
  52. package/{sdk-Dkq6ELkf.mjs → sdk-CubnsyD9.mjs} +324 -14
  53. package/sdk.cjs +2 -2
  54. package/sdk.d.cts +2 -2
  55. package/sdk.d.mts +2 -2
  56. package/sdk.mjs +2 -2
  57. package/vite.d.cts +1 -1
  58. package/vite.d.mts +1 -1
@@ -1,5 +1,6 @@
1
- import { o as customObjectDeclarations } from "./entity-config-CusbTOJ1.mjs";
2
- import { t as entitiesToMappings } from "./mappings-config-7qQ47p9K.mjs";
1
+ import { a as projectionSchema } from "./projection-hnPSgH6G.mjs";
2
+ import { b as primaryKeyColumns, m as validateProjection, o as customObjectDeclarations } from "./entity-config-C8IIkrmX.mjs";
3
+ import { t as entitiesToMappings } from "./mappings-config-DUKBe6OS.mjs";
3
4
  import { t as DRIZZLE_META } from "./drizzle-meta-D-5k3n0i.mjs";
4
5
  //#region ../sdk/src/deployment-identity.ts
5
6
  const MAX_DEPLOYMENT_ID_LENGTH = 128;
@@ -989,6 +990,240 @@ function describeSilentPush(target, body) {
989
990
  return `Clivly sync: pushed ${received} row(s) for ${objectType ? `"${source}" → "${objectType}"` : `"${source}"`} and none were stored — no active mapping in this workspace targets it, so the rows were dropped. Map it in Integrations → Mapping, then sync again.`;
990
991
  }
991
992
  //#endregion
993
+ //#region ../sdk/src/remote-projections.ts
994
+ const SYNC_CUSTOM_PATH$1 = "/clivly/sdk/sync/custom";
995
+ const MISSING_INTROSPECTOR = "this app cannot run dashboard-authored derived objects yet — add `introspector: drizzleIntrospector(db)` to clivly.config.ts";
996
+ /**
997
+ * Turn definitions fetched from the cloud into runnable sync sources.
998
+ *
999
+ * Revalidates every projection locally against the schema THIS app discovered,
1000
+ * never against the cloud's stored copy. Two reasons, and both matter:
1001
+ *
1002
+ * 1. Security. `checkTablesExist`/`checkRefs` bound every table and column ref
1003
+ * to the schema passed in, so validating against the locally-discovered
1004
+ * schema makes the blast radius exactly the namespace the developer handed
1005
+ * to `discoverFromDrizzle`. Trusting the cloud's verdict instead would let a
1006
+ * compromised cloud read any table in the database.
1007
+ * 2. Truth. The stored copy can be stale. A column dropped in the host app
1008
+ * becomes a readable quarantine here instead of a raw Postgres error out of
1009
+ * `sql.raw` at execution time.
1010
+ */
1011
+ function resolveRemoteProjections(args) {
1012
+ const { entries, introspector, schema } = args;
1013
+ return entries.map((entry) => resolveOne(entry, schema, introspector));
1014
+ }
1015
+ /**
1016
+ * The base table's PK, resolved from the schema THIS app discovered — never
1017
+ * from the cloud's copy.
1018
+ *
1019
+ * `validateProjection` proved its uniqueness case against this exact source
1020
+ * (`primaryKeyColumns` over the locally-discovered schema, see
1021
+ * `projection-validate.ts`). Compiling a *different* column — the cloud's
1022
+ * `basePkColumn`, which can go stale the moment a host renames a PK and the
1023
+ * `updatedAt`-only ETag never invalidates — would defeat that proof and
1024
+ * revive the raw-Postgres-error failure mode local revalidation exists to
1025
+ * prevent. Only relevant when the identity is `base_pk` with no explicit
1026
+ * column; every other identity kind ignores `basePkColumn` entirely.
1027
+ */
1028
+ function resolveLocalBasePk(projection, schema) {
1029
+ if (projection.identity.kind !== "base_pk" || projection.identity.column) return;
1030
+ const baseTable = schema.find((t) => t.name === projection.baseTable);
1031
+ if (!baseTable) return;
1032
+ return primaryKeyColumns(baseTable)[0];
1033
+ }
1034
+ function resolveOne(entry, schema, introspector) {
1035
+ const parsed = projectionSchema.safeParse(entry.projection);
1036
+ if (!parsed.success) return {
1037
+ id: entry.id,
1038
+ status: "invalid",
1039
+ reason: `projection did not parse: ${parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
1040
+ };
1041
+ const projection = parsed.data;
1042
+ const errors = validateProjection(projection, schema, entry.entityKey);
1043
+ if (errors.length > 0) return {
1044
+ id: entry.id,
1045
+ status: "invalid",
1046
+ reason: errors.map((e) => `${e.path}: ${e.message}`).join("; ")
1047
+ };
1048
+ if (!introspector?.projectionSource) return {
1049
+ id: entry.id,
1050
+ status: "skipped",
1051
+ reason: MISSING_INTROSPECTOR
1052
+ };
1053
+ try {
1054
+ const basePkColumn = resolveLocalBasePk(projection, schema) ?? entry.basePkColumn;
1055
+ const source = introspector.projectionSource(projection, {
1056
+ objectType: entry.objectType,
1057
+ ...basePkColumn ? { basePkColumn } : {}
1058
+ });
1059
+ return {
1060
+ id: entry.id,
1061
+ status: "ok",
1062
+ source
1063
+ };
1064
+ } catch (error) {
1065
+ return {
1066
+ id: entry.id,
1067
+ status: "failed",
1068
+ reason: error instanceof Error ? error.message : String(error)
1069
+ };
1070
+ }
1071
+ }
1072
+ const PROJECTIONS_PATH = "/clivly/sdk/projections";
1073
+ const PROJECTIONS_REPORT_PATH = "/clivly/sdk/projections/report";
1074
+ const MAX_REASON = 2e3;
1075
+ /**
1076
+ * Merge what resolution decided with what the push actually did.
1077
+ *
1078
+ * A `status: "ok"` outcome means the projection *resolved*, not that its rows
1079
+ * landed. If the push then failed, the object did not sync and must not be
1080
+ * reported as healthy — so the push result wins for those.
1081
+ */
1082
+ function buildRemoteProjectionReport(args) {
1083
+ return {
1084
+ ...args.runId ? { runId: args.runId } : {},
1085
+ results: args.outcomes.map((outcome) => {
1086
+ if (outcome.status !== "ok") return {
1087
+ id: outcome.id,
1088
+ status: outcome.status,
1089
+ reason: outcome.reason.slice(0, MAX_REASON)
1090
+ };
1091
+ const result = args.pushed.get(outcome.source.entity);
1092
+ if (result?.ok) return {
1093
+ id: outcome.id,
1094
+ status: "ok",
1095
+ rows: result.count
1096
+ };
1097
+ return {
1098
+ id: outcome.id,
1099
+ status: "failed",
1100
+ reason: (result?.reason ?? "the push to Clivly failed; rows were read but not stored").slice(0, MAX_REASON)
1101
+ };
1102
+ })
1103
+ };
1104
+ }
1105
+ function createRemoteProjectionFetcher(args) {
1106
+ let etag = null;
1107
+ let cached = [];
1108
+ return { async fetch() {
1109
+ try {
1110
+ const response = await args.fetcher(`${args.apiUrl}${PROJECTIONS_PATH}`, { headers: {
1111
+ authorization: `Bearer ${args.apiKey}`,
1112
+ ...etag ? { "if-none-match": etag } : {}
1113
+ } });
1114
+ if (response.status === 304) return cached;
1115
+ if (!response.ok) return [];
1116
+ const body = await response.json();
1117
+ etag = body.etag ?? null;
1118
+ cached = body.projections ?? [];
1119
+ return cached;
1120
+ } catch {
1121
+ return [];
1122
+ }
1123
+ } };
1124
+ }
1125
+ const REMOTE_PAGE_SIZE = 500;
1126
+ /**
1127
+ * Page one source to exhaustion, keyset-paging on identity alone (the id
1128
+ * field, no timestamp). Split out of `pushRemoteProjections` so that
1129
+ * function's own cognitive complexity stays under the lint threshold — this
1130
+ * is the piece that can throw (a `fetchPage` execution error), kept separate
1131
+ * from push-failure handling below.
1132
+ */
1133
+ async function fetchAllPages(source, pageSize) {
1134
+ const idField = source.idField ?? "id";
1135
+ const all = [];
1136
+ let since = null;
1137
+ for (;;) {
1138
+ const rows = await source.fetchPage({
1139
+ since,
1140
+ limit: pageSize
1141
+ });
1142
+ if (rows.length === 0) break;
1143
+ all.push(...rows);
1144
+ const last = rows.at(-1);
1145
+ const nextId = String(last?.[idField]);
1146
+ if (since && nextId === since.id) break;
1147
+ since = { id: nextId };
1148
+ if (rows.length < pageSize) break;
1149
+ }
1150
+ return all;
1151
+ }
1152
+ /**
1153
+ * Page a remote projection by identity and push one `full` batch.
1154
+ *
1155
+ * `full` rather than `delta` because only a full push lets the server archive
1156
+ * rows that dropped out when a join or filter stopped matching — a delta cannot
1157
+ * express absence. And identity rather than a timestamp because a
1158
+ * dashboard-authored projection has no watermark column, while validation has
1159
+ * already proven the identity unique.
1160
+ *
1161
+ * `pageSize` defaults to `REMOTE_PAGE_SIZE` and exists so a test can force a
1162
+ * short page without either mutating the exported constant or constructing a
1163
+ * fixture hundreds of rows deep.
1164
+ *
1165
+ * Returns one entry per source, keyed by `source.entity`. `count` and `ok`
1166
+ * are independent: `count` is how many rows were pushed (0 for a projection
1167
+ * that legitimately matches nothing this run), `ok` is whether the push
1168
+ * itself succeeded. A caller that folds failures into a report must branch
1169
+ * on `ok`, never on `count === 0` — a correctly-working, legitimately-empty
1170
+ * projection has `ok: true, count: 0` and is not a failure.
1171
+ *
1172
+ * Each source's paging-and-push is wrapped individually: a projection can
1173
+ * validate cleanly and still fail at execution — permission denied, a type
1174
+ * error, a column dropped between validation and this run — and `fetchPage`
1175
+ * throwing is the realistic shape of that. Quarantine that one source as
1176
+ * `{ count: 0, ok: false, reason }` and keep going. The design's promise is
1177
+ * one bad object never takes down the others or the run's report; letting a
1178
+ * throw here escape the loop would break that promise for every source
1179
+ * queued after the failing one.
1180
+ *
1181
+ * Paging and pushing are caught separately, on purpose: `reason` is set only
1182
+ * when paging itself threw (no rows were ever read), so the reported cause
1183
+ * names execution — not the push, which is what actually failed when
1184
+ * `args.push` returns `false`. Conflating the two sent an author whose
1185
+ * projection can't even run to look at their push credentials instead of
1186
+ * their SQL.
1187
+ */
1188
+ async function pushRemoteProjections(args) {
1189
+ const pageSize = args.pageSize ?? REMOTE_PAGE_SIZE;
1190
+ const pushed = /* @__PURE__ */ new Map();
1191
+ for (const source of args.sources) {
1192
+ let all;
1193
+ try {
1194
+ all = await fetchAllPages(source, pageSize);
1195
+ } catch (error) {
1196
+ const message = error instanceof Error ? error.message : String(error);
1197
+ pushed.set(source.entity, {
1198
+ count: 0,
1199
+ ok: false,
1200
+ reason: `the projection failed to execute: ${message}`.slice(0, MAX_REASON)
1201
+ });
1202
+ continue;
1203
+ }
1204
+ try {
1205
+ const ok = await args.push(SYNC_CUSTOM_PATH$1, {
1206
+ source: source.entity,
1207
+ rows: all,
1208
+ mode: "full",
1209
+ fetched: all.length,
1210
+ cursor: null,
1211
+ objectType: source.objectType
1212
+ });
1213
+ pushed.set(source.entity, {
1214
+ count: all.length,
1215
+ ok
1216
+ });
1217
+ } catch {
1218
+ pushed.set(source.entity, {
1219
+ count: 0,
1220
+ ok: false
1221
+ });
1222
+ }
1223
+ }
1224
+ return pushed;
1225
+ }
1226
+ //#endregion
992
1227
  //#region ../sdk/src/self-check.ts
993
1228
  function selfCheck(input) {
994
1229
  const issues = [];
@@ -1337,12 +1572,25 @@ function resolveContactEntity(config) {
1337
1572
  }
1338
1573
  function collectSchemaMeta(config) {
1339
1574
  const byTable = /* @__PURE__ */ new Map();
1340
- for (const table of config.schema ?? []) if (table.columnsMeta) byTable.set(table.name, table.columnsMeta);
1575
+ const merge = (name, meta) => {
1576
+ const existing = byTable.get(name);
1577
+ byTable.set(name, {
1578
+ columnsMeta: meta.columnsMeta ?? existing?.columnsMeta,
1579
+ uniqueConstraints: meta.uniqueConstraints ?? existing?.uniqueConstraints
1580
+ });
1581
+ };
1582
+ for (const table of config.schema ?? []) if (table.columnsMeta || table.uniqueConstraints) merge(table.name, {
1583
+ columnsMeta: table.columnsMeta,
1584
+ uniqueConstraints: table.uniqueConstraints
1585
+ });
1341
1586
  const sources = [];
1342
1587
  if (config.source) sources.push(config.source.contacts, config.source.companies, config.source.deals, ...config.source.custom ?? []);
1343
1588
  for (const source of sources) {
1344
1589
  const meta = source?.[DRIZZLE_META];
1345
- if (meta?.tableName && meta.columnsMeta) byTable.set(meta.tableName, meta.columnsMeta);
1590
+ if (meta?.tableName && (meta.columnsMeta || meta.uniqueConstraints)) merge(meta.tableName, {
1591
+ columnsMeta: meta.columnsMeta,
1592
+ uniqueConstraints: meta.uniqueConstraints
1593
+ });
1346
1594
  }
1347
1595
  return byTable;
1348
1596
  }
@@ -1357,12 +1605,13 @@ function buildSchema(config) {
1357
1605
  if (config.contactEntity && !byName.has(config.contactEntity)) byName.set(config.contactEntity, new Set(config.contactFields ?? []));
1358
1606
  const metaByTable = collectSchemaMeta(config);
1359
1607
  return [...byName].map(([name, columns]) => {
1360
- const columnsMeta = metaByTable.get(name);
1361
- if (columnsMeta) for (const col of columnsMeta) columns.add(col.name);
1608
+ const meta = metaByTable.get(name);
1609
+ for (const col of meta?.columnsMeta ?? []) columns.add(col.name);
1362
1610
  return {
1363
1611
  name,
1364
1612
  columns: [...columns],
1365
- ...columnsMeta ? { columnsMeta } : {}
1613
+ ...meta?.columnsMeta ? { columnsMeta: meta.columnsMeta } : {},
1614
+ ...meta?.uniqueConstraints ? { uniqueConstraints: meta.uniqueConstraints } : {}
1366
1615
  };
1367
1616
  });
1368
1617
  }
@@ -1578,9 +1827,15 @@ function createClivlySDK(config) {
1578
1827
  const cursorStore = config.cursorStore ?? createMemoryCursorStore();
1579
1828
  const fetcher = createFetcher(config.retry);
1580
1829
  let warnedUnsignedTrigger = false;
1830
+ const remoteProjections = createRemoteProjectionFetcher({
1831
+ apiKey: config.apiKey,
1832
+ apiUrl,
1833
+ fetcher
1834
+ });
1581
1835
  let observedUrl;
1582
1836
  let lastPushFailure = null;
1583
1837
  let lastPush = { failed: false };
1838
+ let lastRemoteOutcomes = [];
1584
1839
  const warnedSilentTargets = /* @__PURE__ */ new Set();
1585
1840
  const warnIfSilent = async (target, response) => {
1586
1841
  if (typeof response.json !== "function") return;
@@ -1652,18 +1907,58 @@ function createClivlySDK(config) {
1652
1907
  for (const customSource of customSources ?? []) if (!await syncOne(customSource, SYNC_CUSTOM_PATH, mode, customSource.objectType, runId)) failed.push(customSource.entity);
1653
1908
  return failed;
1654
1909
  };
1910
+ const syncRemoteSources = async (sources, runId) => {
1911
+ const pushed = await pushRemoteProjections({
1912
+ push: createPush(runId),
1913
+ sources
1914
+ });
1915
+ const failed = [];
1916
+ for (const [entity, result] of pushed) if (!result.ok) failed.push(entity);
1917
+ return {
1918
+ failed,
1919
+ pushed
1920
+ };
1921
+ };
1922
+ const reportRemoteOutcomes = async (outcomes, pushed, runId) => {
1923
+ if (outcomes.length === 0) return;
1924
+ try {
1925
+ const report = buildRemoteProjectionReport({
1926
+ outcomes,
1927
+ pushed,
1928
+ runId
1929
+ });
1930
+ await fetcher(`${apiUrl}${PROJECTIONS_REPORT_PATH}`, {
1931
+ method: "POST",
1932
+ headers: {
1933
+ authorization: `Bearer ${config.apiKey}`,
1934
+ "content-type": "application/json"
1935
+ },
1936
+ body: JSON.stringify(report)
1937
+ });
1938
+ } catch {}
1939
+ };
1655
1940
  const runSync = async (options) => {
1656
- if (!config.source) return;
1941
+ const remoteOutcomes = resolveRemoteProjections({
1942
+ entries: await remoteProjections.fetch(),
1943
+ introspector: config.introspector,
1944
+ schema: buildSchema(config)
1945
+ });
1946
+ lastRemoteOutcomes = remoteOutcomes;
1947
+ const remoteSources = remoteOutcomes.filter((o) => o.status === "ok").map((o) => o.source);
1948
+ if (!config.source && remoteSources.length === 0 && remoteOutcomes.length === 0) return;
1657
1949
  lastPushFailure = null;
1658
1950
  const mode = options?.mode ?? "delta";
1659
1951
  const runId = options?.runId;
1660
1952
  const failed = [];
1661
- if (config.source.companies) {
1953
+ if (config.source?.companies) {
1662
1954
  if (!await syncOne(config.source.companies, SYNC_COMPANIES_PATH, mode, void 0, runId)) failed.push(config.source.companies.entity);
1663
1955
  }
1664
- if (!await syncOne(config.source.contacts, SYNC_CONTACTS_PATH, mode, void 0, runId)) failed.push(config.source.contacts.entity);
1665
- if (config.source.deals && !await syncOne(config.source.deals, SYNC_DEALS_PATH, mode, void 0, runId)) failed.push(config.source.deals.entity);
1666
- failed.push(...await syncCustomSources(config.source.custom, mode, runId));
1956
+ if (config.source?.contacts && !await syncOne(config.source.contacts, SYNC_CONTACTS_PATH, mode, void 0, runId)) failed.push(config.source.contacts.entity);
1957
+ if (config.source?.deals && !await syncOne(config.source.deals, SYNC_DEALS_PATH, mode, void 0, runId)) failed.push(config.source.deals.entity);
1958
+ failed.push(...await syncCustomSources(config.source?.custom, mode, runId));
1959
+ const remote = await syncRemoteSources(remoteSources, runId);
1960
+ failed.push(...remote.failed);
1961
+ await reportRemoteOutcomes(lastRemoteOutcomes, remote.pushed, runId);
1667
1962
  if (failed.length > 0) {
1668
1963
  const message = describePushFailure(failed);
1669
1964
  lastPush = {
@@ -1689,6 +1984,20 @@ function createClivlySDK(config) {
1689
1984
  observedUrl
1690
1985
  })
1691
1986
  });
1987
+ const describeRemoteProjections = () => {
1988
+ const counts = {
1989
+ failed: 0,
1990
+ invalid: 0,
1991
+ ok: 0,
1992
+ skipped: 0
1993
+ };
1994
+ for (const outcome of lastRemoteOutcomes) counts[outcome.status] += 1;
1995
+ return {
1996
+ capable: Boolean(config.introspector?.projectionSource),
1997
+ ran: lastRemoteOutcomes.length > 0,
1998
+ ...counts
1999
+ };
2000
+ };
1692
2001
  const sendHeartbeat = () => {
1693
2002
  const triggerUrl = describeSyncTrigger().resolved;
1694
2003
  return fetcher(`${apiUrl}/clivly/sdk/heartbeat`, {
@@ -1887,7 +2196,7 @@ function createClivlySDK(config) {
1887
2196
  });
1888
2197
  const runScheduled = async (options) => {
1889
2198
  await heartbeat();
1890
- if (config.source) await runSync(options);
2199
+ if (config.source || config.introspector) await runSync(options);
1891
2200
  };
1892
2201
  const triggerRequestAllowed = async (req, rawBody) => {
1893
2202
  const secret = config.syncTrigger?.secret;
@@ -1981,7 +2290,7 @@ function createClivlySDK(config) {
1981
2290
  presenceClient = null;
1982
2291
  console.warn("Clivly presence socket unavailable; using HTTP heartbeat", error);
1983
2292
  }
1984
- if (!timers.sync && config.source) {
2293
+ if (!timers.sync && (config.source || config.introspector)) {
1985
2294
  timers.sync = setInterval(() => {
1986
2295
  runSync().catch(() => {});
1987
2296
  }, syncIntervalMs);
@@ -2015,6 +2324,7 @@ function createClivlySDK(config) {
2015
2324
  ping,
2016
2325
  doctor,
2017
2326
  describeSyncTrigger,
2327
+ describeRemoteProjections,
2018
2328
  runScheduled,
2019
2329
  createClivlyHandler,
2020
2330
  sync: runSync,
package/sdk.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_entity_config = require("./entity-config-DE30_RpU.cjs");
3
- const require_sdk = require("./sdk-w8Kv_XnW.cjs");
2
+ const require_entity_config = require("./entity-config-CPM-Tp-d.cjs");
3
+ const require_sdk = require("./sdk-BL9BCzyD.cjs");
4
4
  exports.ClivlyAuthError = require_sdk.ClivlyAuthError;
5
5
  exports.ClivlyError = require_sdk.ClivlyError;
6
6
  exports.ClivlyNetworkError = require_sdk.ClivlyNetworkError;
package/sdk.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { C as defineClivlyConfig, S as customObjectDeclarations, a as ClivlyEntitiesConfig, f as CustomObjectDeclaration, k as validateEntitiesConfig, l as ConfigValidationError, m as DiscoveredSchemaTable, u as ConfigValidationResult } from "./entity-config-B2RA53nw.cjs";
2
- import { a as ClivlyConnectResult, c as ClivlyUser, d as DiscoveredTable, f as DoctorCheck, g as EnsuredObjectTypeResult, h as EnsuredMappingResult, i as ClivlyConnectReason, l as CreateChatSessionHandlerOptions, m as EnsureSchemaResult, n as ChatSessionRequestBody, o as ClivlySDK, p as DoctorReport, r as ChatWidgetVisitor, s as ClivlySDKConfig, u as CursorStore, v as SyncTriggerDescription } from "./namespace-probe-DaTJINS-.cjs";
2
+ import { _ as RemoteProjectionsDescription, a as ClivlyConnectResult, c as ClivlyUser, d as DiscoveredTable, f as DoctorCheck, g as EnsuredObjectTypeResult, h as EnsuredMappingResult, i as ClivlyConnectReason, l as CreateChatSessionHandlerOptions, m as EnsureSchemaResult, n as ChatSessionRequestBody, o as ClivlySDK, p as DoctorReport, r as ChatWidgetVisitor, s as ClivlySDKConfig, u as CursorStore, y as SyncTriggerDescription } from "./namespace-probe-DZIGdvlm.cjs";
3
3
  //#region ../sdk/src/trigger-url.d.ts
4
4
  declare function isPlaceholderUrl(value: string): boolean;
5
5
  //#endregion
@@ -36,4 +36,4 @@ declare class ClivlyNetworkError extends ClivlyError {}
36
36
  */
37
37
  declare function createClivlySDK(config: ClivlySDKConfig): ClivlySDK;
38
38
  //#endregion
39
- export { type ChatSessionRequestBody, type ChatWidgetVisitor, ClivlyAuthError, type ClivlyConnectReason, type ClivlyConnectResult, type ClivlyEntitiesConfig, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, type ClivlySDK, type ClivlySDKConfig, type ClivlyUser, type ConfigValidationError, type ConfigValidationResult, type CreateChatSessionHandlerOptions, type CursorStore, type CustomObjectDeclaration, type DiscoveredSchemaTable, type DiscoveredTable, type DoctorCheck, type DoctorReport, type EnsureSchemaResult, type EnsuredMappingResult, type EnsuredObjectTypeResult, type SyncTriggerDescription, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
39
+ export { type ChatSessionRequestBody, type ChatWidgetVisitor, ClivlyAuthError, type ClivlyConnectReason, type ClivlyConnectResult, type ClivlyEntitiesConfig, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, type ClivlySDK, type ClivlySDKConfig, type ClivlyUser, type ConfigValidationError, type ConfigValidationResult, type CreateChatSessionHandlerOptions, type CursorStore, type CustomObjectDeclaration, type DiscoveredSchemaTable, type DiscoveredTable, type DoctorCheck, type DoctorReport, type EnsureSchemaResult, type EnsuredMappingResult, type EnsuredObjectTypeResult, type RemoteProjectionsDescription, type SyncTriggerDescription, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
package/sdk.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { C as defineClivlyConfig, S as customObjectDeclarations, a as ClivlyEntitiesConfig, f as CustomObjectDeclaration, k as validateEntitiesConfig, l as ConfigValidationError, m as DiscoveredSchemaTable, u as ConfigValidationResult } from "./entity-config-B2RA53nw.mjs";
2
- import { a as ClivlyConnectResult, c as ClivlyUser, d as DiscoveredTable, f as DoctorCheck, g as EnsuredObjectTypeResult, h as EnsuredMappingResult, i as ClivlyConnectReason, l as CreateChatSessionHandlerOptions, m as EnsureSchemaResult, n as ChatSessionRequestBody, o as ClivlySDK, p as DoctorReport, r as ChatWidgetVisitor, s as ClivlySDKConfig, u as CursorStore, v as SyncTriggerDescription } from "./namespace-probe-Ckn9yJ6F.mjs";
2
+ import { _ as RemoteProjectionsDescription, a as ClivlyConnectResult, c as ClivlyUser, d as DiscoveredTable, f as DoctorCheck, g as EnsuredObjectTypeResult, h as EnsuredMappingResult, i as ClivlyConnectReason, l as CreateChatSessionHandlerOptions, m as EnsureSchemaResult, n as ChatSessionRequestBody, o as ClivlySDK, p as DoctorReport, r as ChatWidgetVisitor, s as ClivlySDKConfig, u as CursorStore, y as SyncTriggerDescription } from "./namespace-probe-BQ4imnV7.mjs";
3
3
  //#region ../sdk/src/trigger-url.d.ts
4
4
  declare function isPlaceholderUrl(value: string): boolean;
5
5
  //#endregion
@@ -36,4 +36,4 @@ declare class ClivlyNetworkError extends ClivlyError {}
36
36
  */
37
37
  declare function createClivlySDK(config: ClivlySDKConfig): ClivlySDK;
38
38
  //#endregion
39
- export { type ChatSessionRequestBody, type ChatWidgetVisitor, ClivlyAuthError, type ClivlyConnectReason, type ClivlyConnectResult, type ClivlyEntitiesConfig, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, type ClivlySDK, type ClivlySDKConfig, type ClivlyUser, type ConfigValidationError, type ConfigValidationResult, type CreateChatSessionHandlerOptions, type CursorStore, type CustomObjectDeclaration, type DiscoveredSchemaTable, type DiscoveredTable, type DoctorCheck, type DoctorReport, type EnsureSchemaResult, type EnsuredMappingResult, type EnsuredObjectTypeResult, type SyncTriggerDescription, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
39
+ export { type ChatSessionRequestBody, type ChatWidgetVisitor, ClivlyAuthError, type ClivlyConnectReason, type ClivlyConnectResult, type ClivlyEntitiesConfig, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, type ClivlySDK, type ClivlySDKConfig, type ClivlyUser, type ConfigValidationError, type ConfigValidationResult, type CreateChatSessionHandlerOptions, type CursorStore, type CustomObjectDeclaration, type DiscoveredSchemaTable, type DiscoveredTable, type DoctorCheck, type DoctorReport, type EnsureSchemaResult, type EnsuredMappingResult, type EnsuredObjectTypeResult, type RemoteProjectionsDescription, type SyncTriggerDescription, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
package/sdk.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { o as customObjectDeclarations, p as validateEntitiesConfig, s as defineClivlyConfig } from "./entity-config-CusbTOJ1.mjs";
2
- import { a as ClivlyRateLimitError, i as ClivlyNetworkError, n as ClivlyAuthError, o as createChatSessionHandler, r as ClivlyError, s as isPlaceholderUrl, t as createClivlySDK } from "./sdk-Dkq6ELkf.mjs";
1
+ import { o as customObjectDeclarations, p as validateEntitiesConfig, s as defineClivlyConfig } from "./entity-config-C8IIkrmX.mjs";
2
+ import { a as ClivlyRateLimitError, i as ClivlyNetworkError, n as ClivlyAuthError, o as createChatSessionHandler, r as ClivlyError, s as isPlaceholderUrl, t as createClivlySDK } from "./sdk-CubnsyD9.mjs";
3
3
  export { ClivlyAuthError, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
package/vite.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { o as ClivlySDK } from "./namespace-probe-DaTJINS-.cjs";
1
+ import { o as ClivlySDK } from "./namespace-probe-DZIGdvlm.cjs";
2
2
  import { Plugin } from "vite";
3
3
  //#region ../sdk/src/vite.d.ts
4
4
  interface ClivlyViteOptions {
package/vite.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { o as ClivlySDK } from "./namespace-probe-Ckn9yJ6F.mjs";
1
+ import { o as ClivlySDK } from "./namespace-probe-BQ4imnV7.mjs";
2
2
  import { Plugin } from "vite";
3
3
  //#region ../sdk/src/vite.d.ts
4
4
  interface ClivlyViteOptions {