clivly 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +60 -6
  2. package/core-entity-config.cjs +1 -1
  3. package/core-entity-config.mjs +1 -1
  4. package/core-mappings-config.cjs +1 -1
  5. package/core-mappings-config.mjs +1 -1
  6. package/core-sync-engine.cjs +1 -1
  7. package/core-sync-engine.mjs +1 -1
  8. package/core-view-compiler.cjs +1 -1
  9. package/core-view-compiler.mjs +1 -1
  10. package/core.cjs +11 -6
  11. package/core.d.cts +3 -2
  12. package/core.d.mts +3 -2
  13. package/core.mjs +8 -7
  14. package/drizzle.cjs +74 -9
  15. package/drizzle.d.cts +83 -7
  16. package/drizzle.d.mts +83 -7
  17. package/drizzle.mjs +74 -10
  18. package/{entity-config-DtBsl2MQ.cjs → entity-config-7sGCk_nw.cjs} +1 -1
  19. package/{entity-config-kUHri9yA.mjs → entity-config-B74SPOUZ.mjs} +1 -1
  20. package/index.cjs +141 -29
  21. package/index.d.cts +2 -1
  22. package/index.d.mts +2 -1
  23. package/index.mjs +141 -30
  24. package/integration-state-BK-riZnm.d.cts +130 -0
  25. package/integration-state-BK-riZnm.d.mts +130 -0
  26. package/{internal-Df-PtOH_.mjs → internal-CykXpEGk.mjs} +2 -2
  27. package/{internal-CwnEG6Wl.cjs → internal-DqduZU3l.cjs} +2 -2
  28. package/internal-entity-config.cjs +1 -1
  29. package/internal-entity-config.mjs +1 -1
  30. package/internal-entity-heuristics.cjs +1 -1
  31. package/internal-entity-heuristics.mjs +1 -1
  32. package/internal-mappings-config.cjs +1 -1
  33. package/internal-mappings-config.mjs +1 -1
  34. package/{internal-CDY8g9Ic.d.mts → internal-o2M7FGlR.d.mts} +29 -1
  35. package/internal-sync-engine.cjs +1 -1
  36. package/internal-sync-engine.mjs +1 -1
  37. package/internal-view-compiler.cjs +1 -1
  38. package/internal-view-compiler.mjs +1 -1
  39. package/{internal-Da_dlcQ_.d.cts → internal-wCXSELDN.d.cts} +29 -1
  40. package/internal.cjs +11 -6
  41. package/internal.d.cts +3 -2
  42. package/internal.d.mts +3 -2
  43. package/internal.mjs +8 -7
  44. package/{mappings-config-B0RqFLxu.cjs → mappings-config-CLyEg0sf.cjs} +1 -1
  45. package/{mappings-config-B1b1HVBg.mjs → mappings-config-DQS_s4dg.mjs} +1 -1
  46. package/{namespace-probe-C6aHjedO.d.cts → namespace-probe-BoGI18dQ.d.cts} +15 -0
  47. package/{namespace-probe-Dj-0Q3Hb.d.mts → namespace-probe-Cn7voAd0.d.mts} +15 -0
  48. package/package.json +1 -1
  49. package/{projection-D7xmQP4S.mjs → projection-CSGJbZlZ.mjs} +25 -4
  50. package/{projection-C5244vGa.cjs → projection-Dz6_i1-w.cjs} +25 -4
  51. package/projection-sql-BgnfiGqF.mjs +65 -0
  52. package/projection-sql-Cl1qIn8m.cjs +94 -0
  53. package/{sdk-D4Wp_uxb.cjs → sdk-CM1UO-I7.cjs} +59 -15
  54. package/{sdk-DXV8M_Io.mjs → sdk-DYBDR939.mjs} +54 -16
  55. package/sdk.cjs +3 -2
  56. package/sdk.d.cts +5 -2
  57. package/sdk.d.mts +5 -2
  58. package/sdk.mjs +3 -3
  59. package/{sync-engine-abE94g6X.cjs → sync-engine-C4A5jgA4.cjs} +1 -1
  60. package/{sync-engine-SuxSzbZ4.mjs → sync-engine-Dt5QQSKO.mjs} +1 -1
  61. package/{view-compiler-Blu4OXJ7.cjs → view-compiler-B5nDal14.cjs} +21 -74
  62. package/{view-compiler-CQx8TRrW.mjs → view-compiler-CSYwEWf5.mjs} +2 -55
  63. package/vite.d.cts +1 -1
  64. package/vite.d.mts +1 -1
@@ -1,5 +1,5 @@
1
- const require_entity_config = require("./entity-config-DtBsl2MQ.cjs");
2
- const require_mappings_config = require("./mappings-config-B0RqFLxu.cjs");
1
+ const require_entity_config = require("./entity-config-7sGCk_nw.cjs");
2
+ const require_mappings_config = require("./mappings-config-CLyEg0sf.cjs");
3
3
  const require_drizzle_meta = require("./drizzle-meta-Bb1JWYqf.cjs");
4
4
  //#region ../sdk/src/deployment-identity.ts
5
5
  const MAX_DEPLOYMENT_ID_LENGTH = 128;
@@ -123,11 +123,16 @@ function checkConceptCoverage(config) {
123
123
  }
124
124
  //#endregion
125
125
  //#region ../sdk/src/custom-slug.ts
126
+ const SLUG_PATTERN = /^[a-z][a-z0-9_-]*$/;
126
127
  const NON_ALNUM = /[^a-z0-9]+/g;
127
128
  const EDGE_HYPHENS = /(^-|-$)/g;
128
129
  function slugify(value) {
129
130
  return value.toLowerCase().trim().replace(NON_ALNUM, "-").replace(EDGE_HYPHENS, "");
130
131
  }
132
+ function suggestionFor(declared) {
133
+ const candidate = slugify(declared);
134
+ return candidate !== declared && SLUG_PATTERN.test(candidate) ? ` Did you mean "${candidate}"?` : "";
135
+ }
131
136
  function checkCustomObjectSlugs(config) {
132
137
  const custom = config.source?.custom ?? [];
133
138
  const declared = config.entities ? require_entity_config.customObjectDeclarations(config.entities) : [];
@@ -141,12 +146,11 @@ function checkCustomObjectSlugs(config) {
141
146
  const seen = /* @__PURE__ */ new Map();
142
147
  for (const source of custom) {
143
148
  const declared = source.objectType;
144
- const canonical = slugify(declared);
145
- if (canonical === "") problems.push(`"${source.entity}" has an empty objectType.`);
146
- else if (canonical !== declared) problems.push(`"${declared}" is not a slug — the dashboard would store it as "${canonical}".`);
147
- const prior = seen.get(canonical);
148
- if (prior && canonical !== "") problems.push(`duplicate slug "${canonical}" declared by "${prior}" and "${source.entity}".`);
149
- else seen.set(canonical, source.entity);
149
+ if (declared === "") problems.push(`"${source.entity}" has an empty objectType.`);
150
+ else if (!SLUG_PATTERN.test(declared)) problems.push(`"${declared}" is not a valid object type slug — use lowercase letters, digits, "-" or "_", starting with a letter.${suggestionFor(declared)}`);
151
+ const prior = seen.get(declared);
152
+ if (prior && declared !== "") problems.push(`duplicate slug "${declared}" declared by "${prior}" and "${source.entity}".`);
153
+ else seen.set(declared, source.entity);
150
154
  }
151
155
  if (problems.length > 0) return {
152
156
  name: "Custom object slugs",
@@ -253,10 +257,20 @@ async function runMappingDryRun(config, entityKey) {
253
257
  detail: `"${resolved.source.entity}" is empty — nothing to map yet.`
254
258
  };
255
259
  const missing = Object.entries(fields).filter(([, column]) => !(column in row)).map(([field, column]) => `${field} → ${column}`);
260
+ if (missing.length === 0) return {
261
+ name,
262
+ ok: true,
263
+ detail: `Mapped ${Object.keys(fields).length} field(s) from a real "${resolved.source.entity}" row.`
264
+ };
265
+ if (config.entities?.entities?.[entityKey]?.projection !== void 0 && missing.length === Object.keys(fields).length) return {
266
+ name,
267
+ ok: false,
268
+ detail: `Row from "${resolved.source.entity}" carries none of the projection's columns (${missing.join(", ")}) — the source performs no joins, so the projection is declared but never executed. Build it with \`fromDrizzleProjection\` from \`clivly/drizzle\`, which runs the joins and returns rows keyed by ref token.`
269
+ };
256
270
  return {
257
271
  name,
258
- ok: missing.length === 0,
259
- detail: missing.length === 0 ? `Mapped ${Object.keys(fields).length} field(s) from a real "${resolved.source.entity}" row.` : `Row from "${resolved.source.entity}" is missing mapped column(s): ${missing.join(", ")}.`
272
+ ok: false,
273
+ detail: `Row from "${resolved.source.entity}" is missing mapped column(s): ${missing.join(", ")}.`
260
274
  };
261
275
  }
262
276
  //#endregion
@@ -465,9 +479,27 @@ async function mappingDryRunChecks(config) {
465
479
  return checks;
466
480
  }
467
481
  /**
482
+ * Why a source has no `DRIZZLE_META`, without asserting more than we know.
483
+ *
484
+ * There are two ways to get here and they are indistinguishable at runtime: the
485
+ * source really was hand-written, or it came from `fromDrizzle` and a spread
486
+ * stripped the metadata, which is non-enumerable. The second is easy to fall
487
+ * into precisely where `objectType` is present — `source.custom` is typed
488
+ * `Array<SyncSource & { objectType: string }>`, so attaching that property with
489
+ * `{ ...fromDrizzle(...), objectType }` used to be the only way to satisfy it.
490
+ *
491
+ * Flatly calling such a source "hand-written" sent developers looking for one
492
+ * that does not exist. Where `objectType` is present, name the likelier cause
493
+ * and the fix instead of guessing wrong with confidence.
494
+ */
495
+ function missingMetaDetail(source) {
496
+ const skipped = "column check skipped";
497
+ if (source.objectType === void 0) return `"${source.entity}" is a hand-written source — ${skipped}.`;
498
+ return `"${source.entity}" has no drizzle metadata — ${skipped}. If it came from \`fromDrizzle\`, a spread such as \`{ ...fromDrizzle(...), objectType }\` dropped it; pass \`objectType\` to \`fromDrizzle\` instead.`;
499
+ }
500
+ /**
468
501
  * Confirm each drizzle source actually has the cursor and id columns the sync
469
- * pages on. Hand-written sources have no column metadata, so they are skipped
470
- * rather than failed.
502
+ * pages on. Sources with no column metadata are skipped rather than failed.
471
503
  */
472
504
  function cursorColumnChecks(sources) {
473
505
  const checks = [];
@@ -478,7 +510,7 @@ function cursorColumnChecks(sources) {
478
510
  name: `Cursor/id columns exist (${source.entity})`,
479
511
  ok: false,
480
512
  skipped: true,
481
- detail: `"${source.entity}" is a hand-written source — column check skipped.`
513
+ detail: missingMetaDetail(source)
482
514
  });
483
515
  continue;
484
516
  }
@@ -1117,11 +1149,16 @@ function observedTriggerUrl(req) {
1117
1149
  return new URL(`${proto}://${host}${requestUrl.pathname}`).toString();
1118
1150
  } catch {}
1119
1151
  }
1152
+ const PLACEHOLDER_BRACKETS = /[<>]/;
1153
+ function isPlaceholderUrl(value) {
1154
+ return PLACEHOLDER_BRACKETS.test(value);
1155
+ }
1120
1156
  /**
1121
1157
  * Decide which trigger URL to report, in precedence order:
1122
1158
  *
1123
1159
  * 1. `configuredUrl` — an explicit `syncTrigger.url`. Someone typed this on
1124
- * purpose, so it beats anything inferred.
1160
+ * purpose, so it beats anything inferred. An unedited placeholder is not
1161
+ * "on purpose" and is skipped.
1125
1162
  * 2. platform env origin + `configuredPath` — available at boot, before any
1126
1163
  * request has arrived. Needs the path because platform variables only give
1127
1164
  * an origin.
@@ -1131,7 +1168,7 @@ function observedTriggerUrl(req) {
1131
1168
  * doesn't need to know about it.
1132
1169
  */
1133
1170
  function resolveTriggerUrl(args) {
1134
- if (args.configuredUrl) return args.configuredUrl;
1171
+ if (args.configuredUrl && !isPlaceholderUrl(args.configuredUrl)) return args.configuredUrl;
1135
1172
  const origin = originFromPlatformEnv(args.env);
1136
1173
  if (origin && args.configuredPath) return `${origin}${args.configuredPath.startsWith("/") ? args.configuredPath : `/${args.configuredPath}`}`;
1137
1174
  return args.observedUrl;
@@ -1789,6 +1826,7 @@ function createClivlySDK(config) {
1789
1826
  reason: "ok",
1790
1827
  retryable: false,
1791
1828
  org: body?.org,
1829
+ workspace: body?.workspace ?? null,
1792
1830
  ..."appLastSeenAt" in body ? { appLastSeenAt: body.appLastSeenAt ?? null } : {}
1793
1831
  };
1794
1832
  }
@@ -1996,3 +2034,9 @@ Object.defineProperty(exports, "createClivlySDK", {
1996
2034
  return createClivlySDK;
1997
2035
  }
1998
2036
  });
2037
+ Object.defineProperty(exports, "isPlaceholderUrl", {
2038
+ enumerable: true,
2039
+ get: function() {
2040
+ return isPlaceholderUrl;
2041
+ }
2042
+ });
@@ -1,5 +1,5 @@
1
- import { o as customObjectDeclarations } from "./entity-config-kUHri9yA.mjs";
2
- import { t as entitiesToMappings } from "./mappings-config-B1b1HVBg.mjs";
1
+ import { o as customObjectDeclarations } from "./entity-config-B74SPOUZ.mjs";
2
+ import { t as entitiesToMappings } from "./mappings-config-DQS_s4dg.mjs";
3
3
  import { t as DRIZZLE_META } from "./drizzle-meta-D-5k3n0i.mjs";
4
4
  //#region ../sdk/src/deployment-identity.ts
5
5
  const MAX_DEPLOYMENT_ID_LENGTH = 128;
@@ -123,11 +123,16 @@ function checkConceptCoverage(config) {
123
123
  }
124
124
  //#endregion
125
125
  //#region ../sdk/src/custom-slug.ts
126
+ const SLUG_PATTERN = /^[a-z][a-z0-9_-]*$/;
126
127
  const NON_ALNUM = /[^a-z0-9]+/g;
127
128
  const EDGE_HYPHENS = /(^-|-$)/g;
128
129
  function slugify(value) {
129
130
  return value.toLowerCase().trim().replace(NON_ALNUM, "-").replace(EDGE_HYPHENS, "");
130
131
  }
132
+ function suggestionFor(declared) {
133
+ const candidate = slugify(declared);
134
+ return candidate !== declared && SLUG_PATTERN.test(candidate) ? ` Did you mean "${candidate}"?` : "";
135
+ }
131
136
  function checkCustomObjectSlugs(config) {
132
137
  const custom = config.source?.custom ?? [];
133
138
  const declared = config.entities ? customObjectDeclarations(config.entities) : [];
@@ -141,12 +146,11 @@ function checkCustomObjectSlugs(config) {
141
146
  const seen = /* @__PURE__ */ new Map();
142
147
  for (const source of custom) {
143
148
  const declared = source.objectType;
144
- const canonical = slugify(declared);
145
- if (canonical === "") problems.push(`"${source.entity}" has an empty objectType.`);
146
- else if (canonical !== declared) problems.push(`"${declared}" is not a slug — the dashboard would store it as "${canonical}".`);
147
- const prior = seen.get(canonical);
148
- if (prior && canonical !== "") problems.push(`duplicate slug "${canonical}" declared by "${prior}" and "${source.entity}".`);
149
- else seen.set(canonical, source.entity);
149
+ if (declared === "") problems.push(`"${source.entity}" has an empty objectType.`);
150
+ else if (!SLUG_PATTERN.test(declared)) problems.push(`"${declared}" is not a valid object type slug — use lowercase letters, digits, "-" or "_", starting with a letter.${suggestionFor(declared)}`);
151
+ const prior = seen.get(declared);
152
+ if (prior && declared !== "") problems.push(`duplicate slug "${declared}" declared by "${prior}" and "${source.entity}".`);
153
+ else seen.set(declared, source.entity);
150
154
  }
151
155
  if (problems.length > 0) return {
152
156
  name: "Custom object slugs",
@@ -253,10 +257,20 @@ async function runMappingDryRun(config, entityKey) {
253
257
  detail: `"${resolved.source.entity}" is empty — nothing to map yet.`
254
258
  };
255
259
  const missing = Object.entries(fields).filter(([, column]) => !(column in row)).map(([field, column]) => `${field} → ${column}`);
260
+ if (missing.length === 0) return {
261
+ name,
262
+ ok: true,
263
+ detail: `Mapped ${Object.keys(fields).length} field(s) from a real "${resolved.source.entity}" row.`
264
+ };
265
+ if (config.entities?.entities?.[entityKey]?.projection !== void 0 && missing.length === Object.keys(fields).length) return {
266
+ name,
267
+ ok: false,
268
+ detail: `Row from "${resolved.source.entity}" carries none of the projection's columns (${missing.join(", ")}) — the source performs no joins, so the projection is declared but never executed. Build it with \`fromDrizzleProjection\` from \`clivly/drizzle\`, which runs the joins and returns rows keyed by ref token.`
269
+ };
256
270
  return {
257
271
  name,
258
- ok: missing.length === 0,
259
- detail: missing.length === 0 ? `Mapped ${Object.keys(fields).length} field(s) from a real "${resolved.source.entity}" row.` : `Row from "${resolved.source.entity}" is missing mapped column(s): ${missing.join(", ")}.`
272
+ ok: false,
273
+ detail: `Row from "${resolved.source.entity}" is missing mapped column(s): ${missing.join(", ")}.`
260
274
  };
261
275
  }
262
276
  //#endregion
@@ -465,9 +479,27 @@ async function mappingDryRunChecks(config) {
465
479
  return checks;
466
480
  }
467
481
  /**
482
+ * Why a source has no `DRIZZLE_META`, without asserting more than we know.
483
+ *
484
+ * There are two ways to get here and they are indistinguishable at runtime: the
485
+ * source really was hand-written, or it came from `fromDrizzle` and a spread
486
+ * stripped the metadata, which is non-enumerable. The second is easy to fall
487
+ * into precisely where `objectType` is present — `source.custom` is typed
488
+ * `Array<SyncSource & { objectType: string }>`, so attaching that property with
489
+ * `{ ...fromDrizzle(...), objectType }` used to be the only way to satisfy it.
490
+ *
491
+ * Flatly calling such a source "hand-written" sent developers looking for one
492
+ * that does not exist. Where `objectType` is present, name the likelier cause
493
+ * and the fix instead of guessing wrong with confidence.
494
+ */
495
+ function missingMetaDetail(source) {
496
+ const skipped = "column check skipped";
497
+ if (source.objectType === void 0) return `"${source.entity}" is a hand-written source — ${skipped}.`;
498
+ return `"${source.entity}" has no drizzle metadata — ${skipped}. If it came from \`fromDrizzle\`, a spread such as \`{ ...fromDrizzle(...), objectType }\` dropped it; pass \`objectType\` to \`fromDrizzle\` instead.`;
499
+ }
500
+ /**
468
501
  * Confirm each drizzle source actually has the cursor and id columns the sync
469
- * pages on. Hand-written sources have no column metadata, so they are skipped
470
- * rather than failed.
502
+ * pages on. Sources with no column metadata are skipped rather than failed.
471
503
  */
472
504
  function cursorColumnChecks(sources) {
473
505
  const checks = [];
@@ -478,7 +510,7 @@ function cursorColumnChecks(sources) {
478
510
  name: `Cursor/id columns exist (${source.entity})`,
479
511
  ok: false,
480
512
  skipped: true,
481
- detail: `"${source.entity}" is a hand-written source — column check skipped.`
513
+ detail: missingMetaDetail(source)
482
514
  });
483
515
  continue;
484
516
  }
@@ -1117,11 +1149,16 @@ function observedTriggerUrl(req) {
1117
1149
  return new URL(`${proto}://${host}${requestUrl.pathname}`).toString();
1118
1150
  } catch {}
1119
1151
  }
1152
+ const PLACEHOLDER_BRACKETS = /[<>]/;
1153
+ function isPlaceholderUrl(value) {
1154
+ return PLACEHOLDER_BRACKETS.test(value);
1155
+ }
1120
1156
  /**
1121
1157
  * Decide which trigger URL to report, in precedence order:
1122
1158
  *
1123
1159
  * 1. `configuredUrl` — an explicit `syncTrigger.url`. Someone typed this on
1124
- * purpose, so it beats anything inferred.
1160
+ * purpose, so it beats anything inferred. An unedited placeholder is not
1161
+ * "on purpose" and is skipped.
1125
1162
  * 2. platform env origin + `configuredPath` — available at boot, before any
1126
1163
  * request has arrived. Needs the path because platform variables only give
1127
1164
  * an origin.
@@ -1131,7 +1168,7 @@ function observedTriggerUrl(req) {
1131
1168
  * doesn't need to know about it.
1132
1169
  */
1133
1170
  function resolveTriggerUrl(args) {
1134
- if (args.configuredUrl) return args.configuredUrl;
1171
+ if (args.configuredUrl && !isPlaceholderUrl(args.configuredUrl)) return args.configuredUrl;
1135
1172
  const origin = originFromPlatformEnv(args.env);
1136
1173
  if (origin && args.configuredPath) return `${origin}${args.configuredPath.startsWith("/") ? args.configuredPath : `/${args.configuredPath}`}`;
1137
1174
  return args.observedUrl;
@@ -1789,6 +1826,7 @@ function createClivlySDK(config) {
1789
1826
  reason: "ok",
1790
1827
  retryable: false,
1791
1828
  org: body?.org,
1829
+ workspace: body?.workspace ?? null,
1792
1830
  ..."appLastSeenAt" in body ? { appLastSeenAt: body.appLastSeenAt ?? null } : {}
1793
1831
  };
1794
1832
  }
@@ -1960,4 +1998,4 @@ function createClivlySDK(config) {
1960
1998
  };
1961
1999
  }
1962
2000
  //#endregion
1963
- export { ClivlyRateLimitError as a, ClivlyNetworkError as i, ClivlyAuthError as n, createChatSessionHandler as o, ClivlyError as r, createClivlySDK as t };
2001
+ export { ClivlyRateLimitError as a, ClivlyNetworkError as i, ClivlyAuthError as n, createChatSessionHandler as o, ClivlyError as r, isPlaceholderUrl as s, createClivlySDK as t };
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-DtBsl2MQ.cjs");
3
- const require_sdk = require("./sdk-D4Wp_uxb.cjs");
2
+ const require_entity_config = require("./entity-config-7sGCk_nw.cjs");
3
+ const require_sdk = require("./sdk-CM1UO-I7.cjs");
4
4
  exports.ClivlyAuthError = require_sdk.ClivlyAuthError;
5
5
  exports.ClivlyError = require_sdk.ClivlyError;
6
6
  exports.ClivlyNetworkError = require_sdk.ClivlyNetworkError;
@@ -9,4 +9,5 @@ exports.createChatSessionHandler = require_sdk.createChatSessionHandler;
9
9
  exports.createClivlySDK = require_sdk.createClivlySDK;
10
10
  exports.customObjectDeclarations = require_entity_config.customObjectDeclarations;
11
11
  exports.defineClivlyConfig = require_entity_config.defineClivlyConfig;
12
+ exports.isPlaceholderUrl = require_sdk.isPlaceholderUrl;
12
13
  exports.validateEntitiesConfig = require_entity_config.validateEntitiesConfig;
package/sdk.d.cts CHANGED
@@ -1,5 +1,8 @@
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 } from "./namespace-probe-C6aHjedO.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 } from "./namespace-probe-BoGI18dQ.cjs";
3
+ //#region ../sdk/src/trigger-url.d.ts
4
+ declare function isPlaceholderUrl(value: string): boolean;
5
+ //#endregion
3
6
  //#region ../sdk/src/chat-session.d.ts
4
7
  declare function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl, fetchImpl, resolveUser }: CreateChatSessionHandlerOptions): (request: Request) => Promise<Response>;
5
8
  //#endregion
@@ -33,4 +36,4 @@ declare class ClivlyNetworkError extends ClivlyError {}
33
36
  */
34
37
  declare function createClivlySDK(config: ClivlySDKConfig): ClivlySDK;
35
38
  //#endregion
36
- 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, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, 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, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
package/sdk.d.mts CHANGED
@@ -1,5 +1,8 @@
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 } from "./namespace-probe-Dj-0Q3Hb.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 } from "./namespace-probe-Cn7voAd0.mjs";
3
+ //#region ../sdk/src/trigger-url.d.ts
4
+ declare function isPlaceholderUrl(value: string): boolean;
5
+ //#endregion
3
6
  //#region ../sdk/src/chat-session.d.ts
4
7
  declare function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl, fetchImpl, resolveUser }: CreateChatSessionHandlerOptions): (request: Request) => Promise<Response>;
5
8
  //#endregion
@@ -33,4 +36,4 @@ declare class ClivlyNetworkError extends ClivlyError {}
33
36
  */
34
37
  declare function createClivlySDK(config: ClivlySDKConfig): ClivlySDK;
35
38
  //#endregion
36
- 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, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, 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, 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-kUHri9yA.mjs";
2
- import { a as ClivlyRateLimitError, i as ClivlyNetworkError, n as ClivlyAuthError, o as createChatSessionHandler, r as ClivlyError, t as createClivlySDK } from "./sdk-DXV8M_Io.mjs";
3
- export { ClivlyAuthError, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, validateEntitiesConfig };
1
+ import { o as customObjectDeclarations, p as validateEntitiesConfig, s as defineClivlyConfig } from "./entity-config-B74SPOUZ.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-DYBDR939.mjs";
3
+ export { ClivlyAuthError, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
@@ -1,4 +1,4 @@
1
- const require_view_compiler = require("./view-compiler-Blu4OXJ7.cjs");
1
+ const require_view_compiler = require("./view-compiler-B5nDal14.cjs");
2
2
  //#region ../core/src/sync-engine.ts
3
3
  /**
4
4
  * Diff a view's rows against the current mirror population for one entity.
@@ -1,4 +1,4 @@
1
- import { r as compileEntityViews } from "./view-compiler-CQx8TRrW.mjs";
1
+ import { r as compileEntityViews } from "./view-compiler-CSYwEWf5.mjs";
2
2
  //#region ../core/src/sync-engine.ts
3
3
  /**
4
4
  * Diff a view's rows against the current mirror population for one entity.
@@ -1,58 +1,5 @@
1
- const require_projection = require("./projection-C5244vGa.cjs");
2
- //#region ../core/src/projection-sql.ts
3
- /**
4
- * SQL generation for projection-backed entities.
5
- *
6
- * Base and joins are aliased by their ref key (`base`, then each join's `key`),
7
- * which is what allows the same table to be joined twice and keeps generated
8
- * SQL independent of host table names.
9
- *
10
- * Pure string generation — no DB access. Identifiers are escaped so output is
11
- * deterministic and injection-safe.
12
- */
13
- /** Quote a single identifier part, escaping embedded double-quotes. */
14
- function quoteIdent(name) {
15
- return `"${name.replace(/"/g, "\"\"")}"`;
16
- }
17
- function refSql(ref) {
18
- return `${quoteIdent(ref.table)}.${quoteIdent(ref.column)}`;
19
- }
20
- /**
21
- * The identity expression, aliased as `id`. Composite identities concatenate
22
- * their parts with `::`; validation guarantees every part is NOT NULL and
23
- * non-text, which is what makes the concatenation collision-free.
24
- */
25
- function identitySql(projection, basePkColumn) {
26
- const refs = require_projection.identityRefs(projection.identity, basePkColumn);
27
- if (projection.identity.kind === "composite") return `CONCAT_WS('::', ${refs.map((ref) => `${refSql(ref)}::text`).join(", ")}) AS ${quoteIdent("id")}`;
28
- const [ref] = refs;
29
- if (!ref) throw new Error("projection identity resolved to no column");
30
- return `${refSql(ref)} AS ${quoteIdent("id")}`;
31
- }
32
- function compileProjectionSelect(projection, basePkColumn) {
33
- const selectItems = [identitySql(projection, basePkColumn)];
34
- const columns = ["id"];
35
- for (const [field, binding] of Object.entries(projection.fieldBindings)) {
36
- selectItems.push(`${refSql(binding.from)} AS ${quoteIdent(field)}`);
37
- columns.push(field);
38
- }
39
- return {
40
- columns,
41
- selectItems
42
- };
43
- }
44
- function compileProjectionJoins(projection) {
45
- return projection.joins.map((join) => {
46
- const keyword = join.type === "inner" ? "INNER JOIN" : "LEFT JOIN";
47
- const on = join.on.map((c) => `${refSql(c.left)} = ${refSql(c.right)}`).join(" AND ");
48
- return `${keyword} ${quoteIdent(join.table)} AS ${quoteIdent(join.key)} ON ${on}`;
49
- });
50
- }
51
- /** `FROM <baseTable> AS "base"` — the alias every ref resolves against. */
52
- function compileProjectionFrom(projection) {
53
- return `FROM ${quoteIdent(projection.baseTable)} AS ${quoteIdent(require_projection.BASE_REF)}`;
54
- }
55
- //#endregion
1
+ const require_projection = require("./projection-Dz6_i1-w.cjs");
2
+ const require_projection_sql = require("./projection-sql-Cl1qIn8m.cjs");
56
3
  //#region ../core/src/view-compiler.ts
57
4
  /**
58
5
  * View compiler (Phase 2) — turns a validated entity config into read-only
@@ -88,7 +35,7 @@ function quoteList(values) {
88
35
  }
89
36
  /** Compile one column predicate into a SQL boolean expression. */
90
37
  function compilePredicate(table, column, value) {
91
- const col = `${quoteIdent(table)}.${quoteIdent(column)}`;
38
+ const col = `${require_projection_sql.quoteIdent(table)}.${require_projection_sql.quoteIdent(column)}`;
92
39
  if (value === null || typeof value !== "object") return `${col} = ${quoteLiteral(value)}`;
93
40
  if ("eq" in value) return `${col} = ${quoteLiteral(value.eq)}`;
94
41
  if ("ne" in value) return `${col} <> ${quoteLiteral(value.ne)}`;
@@ -121,33 +68,33 @@ function refParts(ref, defaultTable) {
121
68
  }
122
69
  function compileRelationship(relName, rel, source, related) {
123
70
  const refCol = `${relName}_ref`;
124
- const refAlias = quoteIdent(refCol);
71
+ const refAlias = require_projection_sql.quoteIdent(refCol);
125
72
  const { via } = rel;
126
73
  if ("fkOn" in via) {
127
74
  const relatedTable = related?.source ?? "";
128
75
  if (via.fkOn === "company") {
129
76
  const { table, column } = refParts(via.column, relatedTable);
130
77
  const relatedFilter = compileFilterConditions(table, related?.filter);
131
- const on = [`${quoteIdent(table)}.${quoteIdent(column)} = ${quoteIdent(source.source)}.${quoteIdent(SOURCE_KEY)}`, ...relatedFilter].join(" AND ");
78
+ const on = [`${require_projection_sql.quoteIdent(table)}.${require_projection_sql.quoteIdent(column)} = ${require_projection_sql.quoteIdent(source.source)}.${require_projection_sql.quoteIdent(SOURCE_KEY)}`, ...relatedFilter].join(" AND ");
132
79
  return {
133
- clause: `LEFT JOIN ${quoteIdent(table)} ON ${on}`,
134
- refSelect: `${quoteIdent(table)}.${quoteIdent(SOURCE_KEY)} AS ${refAlias}`,
80
+ clause: `LEFT JOIN ${require_projection_sql.quoteIdent(table)} ON ${on}`,
81
+ refSelect: `${require_projection_sql.quoteIdent(table)}.${require_projection_sql.quoteIdent(SOURCE_KEY)} AS ${refAlias}`,
135
82
  refColumn: refCol
136
83
  };
137
84
  }
138
85
  const { table, column } = refParts(via.column, source.source);
139
- const on = [`${quoteIdent(relatedTable)}.${quoteIdent(SOURCE_KEY)} = ${quoteIdent(table)}.${quoteIdent(column)}`, ...compileFilterConditions(relatedTable, related?.filter)].join(" AND ");
86
+ const on = [`${require_projection_sql.quoteIdent(relatedTable)}.${require_projection_sql.quoteIdent(SOURCE_KEY)} = ${require_projection_sql.quoteIdent(table)}.${require_projection_sql.quoteIdent(column)}`, ...compileFilterConditions(relatedTable, related?.filter)].join(" AND ");
140
87
  return {
141
- clause: `LEFT JOIN ${quoteIdent(relatedTable)} ON ${on}`,
142
- refSelect: `${quoteIdent(relatedTable)}.${quoteIdent(SOURCE_KEY)} AS ${refAlias}`,
88
+ clause: `LEFT JOIN ${require_projection_sql.quoteIdent(relatedTable)} ON ${on}`,
89
+ refSelect: `${require_projection_sql.quoteIdent(relatedTable)}.${require_projection_sql.quoteIdent(SOURCE_KEY)} AS ${refAlias}`,
143
90
  refColumn: refCol
144
91
  };
145
92
  }
146
93
  if ("through" in via) {
147
- const on = `${quoteIdent(via.through)}.${quoteIdent(via.localKey)} = ${quoteIdent(source.source)}.${quoteIdent(SOURCE_KEY)}`;
94
+ const on = `${require_projection_sql.quoteIdent(via.through)}.${require_projection_sql.quoteIdent(via.localKey)} = ${require_projection_sql.quoteIdent(source.source)}.${require_projection_sql.quoteIdent(SOURCE_KEY)}`;
148
95
  return {
149
- clause: `LEFT JOIN ${quoteIdent(via.through)} ON ${on}`,
150
- refSelect: `${quoteIdent(via.through)}.${quoteIdent(via.foreignKey)} AS ${refAlias}`,
96
+ clause: `LEFT JOIN ${require_projection_sql.quoteIdent(via.through)} ON ${on}`,
97
+ refSelect: `${require_projection_sql.quoteIdent(via.through)}.${require_projection_sql.quoteIdent(via.foreignKey)} AS ${refAlias}`,
151
98
  refColumn: refCol
152
99
  };
153
100
  }
@@ -159,10 +106,10 @@ function compileRelationship(relName, rel, source, related) {
159
106
  }
160
107
  /** SELECT items for a legacy single-table entity: source key, then fields. */
161
108
  function legacySelect(entity, src) {
162
- const selectItems = [`${quoteIdent(src)}.${quoteIdent(SOURCE_KEY)} AS ${quoteIdent("id")}`];
109
+ const selectItems = [`${require_projection_sql.quoteIdent(src)}.${require_projection_sql.quoteIdent(SOURCE_KEY)} AS ${require_projection_sql.quoteIdent("id")}`];
163
110
  const columns = ["id"];
164
111
  for (const [field, column] of Object.entries(entity.fields)) {
165
- selectItems.push(`${quoteIdent(src)}.${quoteIdent(column)} AS ${quoteIdent(field)}`);
112
+ selectItems.push(`${require_projection_sql.quoteIdent(src)}.${require_projection_sql.quoteIdent(column)} AS ${require_projection_sql.quoteIdent(field)}`);
166
113
  columns.push(field);
167
114
  }
168
115
  return {
@@ -209,14 +156,14 @@ function compileEntityView(config, entityKey, options = {}) {
209
156
  const src = entity.source;
210
157
  const projection = entity.projection;
211
158
  const filterTable = projection ? require_projection.BASE_REF : src;
212
- const { selectItems, columns } = projection ? compileProjectionSelect(projection, SOURCE_KEY) : legacySelect(entity, src);
213
- const joins = projection ? compileProjectionJoins(projection) : legacyJoins(config, entity, columns, selectItems);
159
+ const { selectItems, columns } = projection ? require_projection_sql.compileProjectionSelect(projection, SOURCE_KEY) : legacySelect(entity, src);
160
+ const joins = projection ? require_projection_sql.compileProjectionJoins(projection) : legacyJoins(config, entity, columns, selectItems);
214
161
  const conditions = compileFilterConditions(filterTable, entity.filter);
215
- if (options.orgScope) conditions.push(`${quoteIdent(filterTable)}.${quoteIdent(options.orgScope.column)} = ${quoteLiteral(options.orgScope.value)}`);
162
+ if (options.orgScope) conditions.push(`${require_projection_sql.quoteIdent(filterTable)}.${require_projection_sql.quoteIdent(options.orgScope.column)} = ${quoteLiteral(options.orgScope.value)}`);
216
163
  const lines = [
217
- options.securityInvoker ?? true ? `CREATE OR REPLACE VIEW ${quoteIdent(viewName)} WITH (security_invoker = true) AS` : `CREATE OR REPLACE VIEW ${quoteIdent(viewName)} AS`,
164
+ options.securityInvoker ?? true ? `CREATE OR REPLACE VIEW ${require_projection_sql.quoteIdent(viewName)} WITH (security_invoker = true) AS` : `CREATE OR REPLACE VIEW ${require_projection_sql.quoteIdent(viewName)} AS`,
218
165
  `SELECT ${selectItems.join(", ")}`,
219
- projection ? compileProjectionFrom(projection) : `FROM ${quoteIdent(src)}`,
166
+ projection ? require_projection_sql.compileProjectionFrom(projection) : `FROM ${require_projection_sql.quoteIdent(src)}`,
220
167
  ...joins
221
168
  ];
222
169
  if (conditions.length > 0) lines.push(`WHERE ${conditions.join(" AND ")}`);
@@ -229,7 +176,7 @@ function compileEntityView(config, entityKey, options = {}) {
229
176
  sourceTable: src,
230
177
  columns,
231
178
  sql,
232
- dropSql: `DROP VIEW IF EXISTS ${quoteIdent(viewName)};`
179
+ dropSql: `DROP VIEW IF EXISTS ${require_projection_sql.quoteIdent(viewName)};`
233
180
  };
234
181
  }
235
182
  /** Compile every entity in the config into its view, in declaration order. */
@@ -1,58 +1,5 @@
1
- import { r as identityRefs, t as BASE_REF } from "./projection-D7xmQP4S.mjs";
2
- //#region ../core/src/projection-sql.ts
3
- /**
4
- * SQL generation for projection-backed entities.
5
- *
6
- * Base and joins are aliased by their ref key (`base`, then each join's `key`),
7
- * which is what allows the same table to be joined twice and keeps generated
8
- * SQL independent of host table names.
9
- *
10
- * Pure string generation — no DB access. Identifiers are escaped so output is
11
- * deterministic and injection-safe.
12
- */
13
- /** Quote a single identifier part, escaping embedded double-quotes. */
14
- function quoteIdent(name) {
15
- return `"${name.replace(/"/g, "\"\"")}"`;
16
- }
17
- function refSql(ref) {
18
- return `${quoteIdent(ref.table)}.${quoteIdent(ref.column)}`;
19
- }
20
- /**
21
- * The identity expression, aliased as `id`. Composite identities concatenate
22
- * their parts with `::`; validation guarantees every part is NOT NULL and
23
- * non-text, which is what makes the concatenation collision-free.
24
- */
25
- function identitySql(projection, basePkColumn) {
26
- const refs = identityRefs(projection.identity, basePkColumn);
27
- if (projection.identity.kind === "composite") return `CONCAT_WS('::', ${refs.map((ref) => `${refSql(ref)}::text`).join(", ")}) AS ${quoteIdent("id")}`;
28
- const [ref] = refs;
29
- if (!ref) throw new Error("projection identity resolved to no column");
30
- return `${refSql(ref)} AS ${quoteIdent("id")}`;
31
- }
32
- function compileProjectionSelect(projection, basePkColumn) {
33
- const selectItems = [identitySql(projection, basePkColumn)];
34
- const columns = ["id"];
35
- for (const [field, binding] of Object.entries(projection.fieldBindings)) {
36
- selectItems.push(`${refSql(binding.from)} AS ${quoteIdent(field)}`);
37
- columns.push(field);
38
- }
39
- return {
40
- columns,
41
- selectItems
42
- };
43
- }
44
- function compileProjectionJoins(projection) {
45
- return projection.joins.map((join) => {
46
- const keyword = join.type === "inner" ? "INNER JOIN" : "LEFT JOIN";
47
- const on = join.on.map((c) => `${refSql(c.left)} = ${refSql(c.right)}`).join(" AND ");
48
- return `${keyword} ${quoteIdent(join.table)} AS ${quoteIdent(join.key)} ON ${on}`;
49
- });
50
- }
51
- /** `FROM <baseTable> AS "base"` — the alias every ref resolves against. */
52
- function compileProjectionFrom(projection) {
53
- return `FROM ${quoteIdent(projection.baseTable)} AS ${quoteIdent(BASE_REF)}`;
54
- }
55
- //#endregion
1
+ import { t as BASE_REF } from "./projection-CSGJbZlZ.mjs";
2
+ import { a as quoteIdent, i as compileProjectionSelect, r as compileProjectionJoins, t as compileProjectionFrom } from "./projection-sql-BgnfiGqF.mjs";
56
3
  //#region ../core/src/view-compiler.ts
57
4
  /**
58
5
  * View compiler (Phase 2) — turns a validated entity config into read-only
package/vite.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { o as ClivlySDK } from "./namespace-probe-C6aHjedO.cjs";
1
+ import { o as ClivlySDK } from "./namespace-probe-BoGI18dQ.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-Dj-0Q3Hb.mjs";
1
+ import { o as ClivlySDK } from "./namespace-probe-Cn7voAd0.mjs";
2
2
  import { Plugin } from "vite";
3
3
  //#region ../sdk/src/vite.d.ts
4
4
  interface ClivlyViteOptions {