clivly 0.10.8 → 0.11.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -1
- package/{adapter-1TN0zohk.d.cts → adapter-BQl13eS3.d.mts} +1 -1
- package/{adapter-uxirB88i.d.mts → adapter-CA8bA6o-.d.cts} +1 -1
- package/{auth-adapter-CXTiW3Mb.d.cts → auth-adapter-B4vVyUiX.d.mts} +1 -1
- package/{auth-adapter-DSuYwv1c.d.mts → auth-adapter-Cvc_sOpY.d.cts} +1 -1
- package/auth-better-auth.d.cts +1 -1
- package/auth-better-auth.d.mts +1 -1
- package/auth-clerk.d.cts +1 -1
- package/auth-clerk.d.mts +1 -1
- package/auth-workos.d.cts +1 -1
- package/auth-workos.d.mts +1 -1
- package/core-adapter.d.cts +1 -1
- package/core-adapter.d.mts +1 -1
- package/core-auth-adapter.d.cts +1 -1
- package/core-auth-adapter.d.mts +1 -1
- package/core-drizzle.d.cts +1 -1
- package/core-drizzle.d.mts +1 -1
- package/core-entity-config.cjs +1 -1
- package/core-entity-config.d.cts +1 -1
- package/core-entity-config.d.mts +1 -1
- package/core-entity-config.mjs +1 -1
- package/core-entity-heuristics.d.cts +1 -1
- package/core-entity-heuristics.d.mts +1 -1
- package/core-mapping-form.d.cts +1 -1
- package/core-mapping-form.d.mts +1 -1
- package/core-mappings-config.cjs +1 -1
- package/core-mappings-config.d.cts +1 -1
- package/core-mappings-config.d.mts +1 -1
- package/core-mappings-config.mjs +1 -1
- package/core-sync-engine.d.cts +1 -1
- package/core-sync-engine.d.mts +1 -1
- package/core-types.d.cts +1 -1
- package/core-types.d.mts +1 -1
- package/core-view-compiler.d.cts +1 -1
- package/core-view-compiler.d.mts +1 -1
- package/core.cjs +2 -2
- package/core.d.cts +9 -9
- package/core.d.mts +9 -9
- package/core.mjs +2 -2
- package/{drizzle-SD8WCvYj.d.cts → drizzle-C_0pIDpx.d.mts} +1 -1
- package/{drizzle-axugRJ0u.d.mts → drizzle-D3DcaC2d.d.cts} +1 -1
- package/drizzle.d.cts +3 -3
- package/drizzle.d.mts +3 -3
- package/{entity-config-bC3DX9f1.mjs → entity-config-CO0TEwZC.mjs} +1 -0
- package/{entity-config-w8oMBWf8.d.cts → entity-config-CbS2DGmA.d.cts} +1 -1
- package/{entity-config-w8oMBWf8.d.mts → entity-config-CbS2DGmA.d.mts} +1 -1
- package/{entity-config-C2MfIDL2.cjs → entity-config-EZg9BtqD.cjs} +1 -0
- package/index.cjs +207 -14
- package/index.d.cts +2 -0
- package/index.d.mts +2 -0
- package/index.mjs +207 -14
- package/{internal-CHvZMvxC.d.cts → internal-B8cq-xP-.d.cts} +1 -1
- package/{internal-WximMGmH.d.mts → internal-DEV1NCQc.d.mts} +1 -1
- package/internal-adapter.d.cts +1 -1
- package/internal-adapter.d.mts +1 -1
- package/internal-auth-adapter.d.cts +1 -1
- package/internal-auth-adapter.d.mts +1 -1
- package/internal-drizzle.d.cts +1 -1
- package/internal-drizzle.d.mts +1 -1
- package/internal-entity-config.cjs +1 -1
- package/internal-entity-config.d.cts +1 -1
- package/internal-entity-config.d.mts +1 -1
- package/internal-entity-config.mjs +1 -1
- package/internal-entity-heuristics.cjs +35 -18
- package/internal-entity-heuristics.d.cts +1 -1
- package/internal-entity-heuristics.d.mts +1 -1
- package/internal-entity-heuristics.mjs +35 -18
- package/internal-mapping-form.d.cts +1 -1
- package/internal-mapping-form.d.mts +1 -1
- package/internal-mappings-config.cjs +1 -1
- package/internal-mappings-config.d.cts +1 -1
- package/internal-mappings-config.d.mts +1 -1
- package/internal-mappings-config.mjs +1 -1
- package/internal-sync-engine.d.cts +1 -1
- package/internal-sync-engine.d.mts +1 -1
- package/internal-types.d.cts +1 -1
- package/internal-types.d.mts +1 -1
- package/internal-view-compiler.d.cts +1 -1
- package/internal-view-compiler.d.mts +1 -1
- package/internal.cjs +2 -2
- package/internal.d.cts +9 -9
- package/internal.d.mts +9 -9
- package/internal.mjs +2 -2
- package/{mapping-form-BsTxv8w3.d.cts → mapping-form-BBgP1iEf.d.cts} +1 -1
- package/{mapping-form-OTFwr1sN.d.mts → mapping-form-B_vX_kZJ.d.mts} +1 -1
- package/{mappings-config-Dpv08-x4.cjs → mappings-config-BRP_Dev5.cjs} +1 -1
- package/{mappings-config-DbznSjTX.d.cts → mappings-config-BXdSUl-K.d.mts} +1 -1
- package/{mappings-config-SXu_zlmp.d.mts → mappings-config-Cvw7RDSb.d.cts} +1 -1
- package/{mappings-config-CRSL9dzw.mjs → mappings-config-fAfUoVuD.mjs} +1 -1
- package/{namespace-probe-BmxtnOfc.d.mts → namespace-probe-BWZ7f1fg.d.mts} +1 -1
- package/{namespace-probe-C3xMOqWE.d.cts → namespace-probe-DC4YsI6m.d.cts} +1 -1
- package/package.json +1 -1
- package/{sdk-C0DU5KDS.mjs → sdk-CsR4W9QQ.mjs} +71 -14
- package/{sdk-BAHcnhm7.cjs → sdk-UCBezLoT.cjs} +71 -14
- package/sdk.cjs +2 -2
- package/sdk.d.cts +2 -2
- package/sdk.d.mts +2 -2
- package/sdk.mjs +2 -2
- package/{sync-engine-CUKWXUv7.d.mts → sync-engine-BQRApDAG.d.mts} +2 -2
- package/{sync-engine-D2YlIHZB.d.cts → sync-engine-qxbrOEJX.d.cts} +2 -2
- package/{types-Cq1uHUKp.d.cts → types-S0N0hqOV.d.cts} +3 -0
- package/{types-Cq1uHUKp.d.mts → types-S0N0hqOV.d.mts} +3 -0
- package/{view-compiler-BO4CKamn.d.cts → view-compiler-CdnLqPQx.d.mts} +1 -1
- package/{view-compiler-iEwUOuba.d.mts → view-compiler-P4GHpOHt.d.cts} +1 -1
- package/vite.d.cts +1 -1
- package/vite.d.mts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as projectionSchema } from "./projection-CSGJbZlZ.mjs";
|
|
2
|
-
import { _ as validateProjection, s as customObjectDeclarations, w as primaryKeyColumns } from "./entity-config-
|
|
3
|
-
import { t as entitiesToMappings } from "./mappings-config-
|
|
2
|
+
import { _ as validateProjection, s as customObjectDeclarations, w as primaryKeyColumns } from "./entity-config-CO0TEwZC.mjs";
|
|
3
|
+
import { t as entitiesToMappings } from "./mappings-config-fAfUoVuD.mjs";
|
|
4
4
|
import { t as DRIZZLE_META } from "./drizzle-meta-D-5k3n0i.mjs";
|
|
5
5
|
//#region ../sdk/src/deployment-identity.ts
|
|
6
6
|
const MAX_DEPLOYMENT_ID_LENGTH = 128;
|
|
@@ -392,11 +392,15 @@ function errorMessage(error) {
|
|
|
392
392
|
/**
|
|
393
393
|
* The entities to ask about, in the exact terms the sync pushes them.
|
|
394
394
|
*
|
|
395
|
-
* `source` is the
|
|
395
|
+
* `source` is whatever the push will actually send — the value that arrives at
|
|
396
396
|
* `ingestPush` as `input.source` and is compared against `mapping.sourceTable`.
|
|
397
|
+
* Usually that is `SyncSource.entity`, but a projection pushes under its base
|
|
398
|
+
* table, so this asks `customPushSource` rather than reading `entity` directly.
|
|
399
|
+
*
|
|
397
400
|
* It is NOT the entity config's own `source` field, which names a host table;
|
|
398
|
-
* the two are routinely conflated, and using the wrong one
|
|
399
|
-
*
|
|
401
|
+
* the two are routinely conflated, and using the wrong one reports a correctly
|
|
402
|
+
* mapped workspace as unmapped — which is exactly what happened to every
|
|
403
|
+
* projection until this used the push label.
|
|
400
404
|
*/
|
|
401
405
|
function readinessEntitiesFromConfig(config) {
|
|
402
406
|
const entities = [];
|
|
@@ -405,7 +409,7 @@ function readinessEntitiesFromConfig(config) {
|
|
|
405
409
|
if (!resolved) continue;
|
|
406
410
|
const objectTypeSlug = resolved.source.objectType;
|
|
407
411
|
entities.push({
|
|
408
|
-
source: resolved.source
|
|
412
|
+
source: customPushSource(config, resolved.source),
|
|
409
413
|
concept: resolved.concept,
|
|
410
414
|
...resolved.concept === "custom" && objectTypeSlug ? { objectTypeSlug } : {}
|
|
411
415
|
});
|
|
@@ -1468,8 +1472,18 @@ function jsonResponse$1(body, status) {
|
|
|
1468
1472
|
function normalizeApiUrl(apiUrl) {
|
|
1469
1473
|
return apiUrl.replace(TRAILING_SLASH$1, "");
|
|
1470
1474
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1475
|
+
/**
|
|
1476
|
+
* The origin *claimed* by the request, for reporting upstream.
|
|
1477
|
+
*
|
|
1478
|
+
* Falls back to the request URL so Clivly still receives an origin for a
|
|
1479
|
+
* non-browser caller. This value is reported, never trusted: only a real
|
|
1480
|
+
* `Origin` header is evidence of where a request came from, so the access
|
|
1481
|
+
* decision uses {@link trustedOrigin} instead. Keeping the two apart is the
|
|
1482
|
+
* point — conflating them let a caller that simply omitted the header be
|
|
1483
|
+
* judged against the server's own origin, which is usually in the allowlist.
|
|
1484
|
+
*/
|
|
1485
|
+
function reportedOrigin(req) {
|
|
1486
|
+
const headerOrigin = trustedOrigin(req);
|
|
1473
1487
|
if (headerOrigin) return headerOrigin;
|
|
1474
1488
|
try {
|
|
1475
1489
|
return new URL(req.url).origin;
|
|
@@ -1477,6 +1491,15 @@ function resolveOrigin(req) {
|
|
|
1477
1491
|
return null;
|
|
1478
1492
|
}
|
|
1479
1493
|
}
|
|
1494
|
+
/**
|
|
1495
|
+
* The only origin worth an access decision: one the browser set itself.
|
|
1496
|
+
*
|
|
1497
|
+
* A missing header means "not a browser request we can vouch for", which is
|
|
1498
|
+
* untrusted — never the server's own origin.
|
|
1499
|
+
*/
|
|
1500
|
+
function trustedOrigin(req) {
|
|
1501
|
+
return req.headers.get("origin");
|
|
1502
|
+
}
|
|
1480
1503
|
function isChatSessionRequestBody(value) {
|
|
1481
1504
|
if (typeof value !== "object" || value === null) return false;
|
|
1482
1505
|
const body = value;
|
|
@@ -1487,6 +1510,17 @@ function isChatSessionRequestBody(value) {
|
|
|
1487
1510
|
if (typeof visitor.email !== "string" || visitor.email.trim().length === 0) return false;
|
|
1488
1511
|
return body.visitorToken === void 0 || body.visitorToken === null || typeof body.visitorToken === "string";
|
|
1489
1512
|
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Judge a request against the configured allowlist.
|
|
1515
|
+
*
|
|
1516
|
+
* `origin` must be a *trusted* origin (see {@link trustedOrigin}) — passing
|
|
1517
|
+
* the reported one would reinstate the bypass this guards against.
|
|
1518
|
+
*
|
|
1519
|
+
* An unset allowlist still admits every origin, because requiring it would
|
|
1520
|
+
* break every existing deployment on upgrade. The unset case is instead
|
|
1521
|
+
* warned about once at construction, so the permissive default is loud
|
|
1522
|
+
* rather than silent.
|
|
1523
|
+
*/
|
|
1490
1524
|
function originAllowed(origin, allowedOrigins) {
|
|
1491
1525
|
if (!allowedOrigins || allowedOrigins.length === 0) return true;
|
|
1492
1526
|
if (!origin) return false;
|
|
@@ -1494,6 +1528,7 @@ function originAllowed(origin, allowedOrigins) {
|
|
|
1494
1528
|
}
|
|
1495
1529
|
function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API_URL$1, fetchImpl = fetch, resolveUser }) {
|
|
1496
1530
|
const sessionUrl = `${normalizeApiUrl(apiUrl)}/clivly/widget/session`;
|
|
1531
|
+
if (!allowedOrigins || allowedOrigins.length === 0) console.warn("[clivly] createChatSessionHandler has no allowedOrigins; every origin can open a chat session against this workspace. Pass allowedOrigins to restrict it.");
|
|
1497
1532
|
return async (request) => {
|
|
1498
1533
|
if (request.method !== "POST") return new Response(JSON.stringify({ error: "method_not_allowed" }), {
|
|
1499
1534
|
status: 405,
|
|
@@ -1502,8 +1537,8 @@ function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API
|
|
|
1502
1537
|
allow: "POST"
|
|
1503
1538
|
}
|
|
1504
1539
|
});
|
|
1505
|
-
|
|
1506
|
-
|
|
1540
|
+
if (!originAllowed(trustedOrigin(request), allowedOrigins)) return jsonResponse$1({ error: "origin_not_allowed" }, 403);
|
|
1541
|
+
const origin = reportedOrigin(request);
|
|
1507
1542
|
let body;
|
|
1508
1543
|
try {
|
|
1509
1544
|
body = await request.json();
|
|
@@ -1701,6 +1736,18 @@ var TriggerRequestError = class extends Error {
|
|
|
1701
1736
|
function triggerErrorStatus(error) {
|
|
1702
1737
|
return error instanceof TriggerRequestError ? error.status : 500;
|
|
1703
1738
|
}
|
|
1739
|
+
const SENTENCE_END_RE = /[.!?]$/;
|
|
1740
|
+
async function readPushFailureMessage(response) {
|
|
1741
|
+
if (!response || typeof response.json !== "function") return null;
|
|
1742
|
+
try {
|
|
1743
|
+
const body = await response.json();
|
|
1744
|
+
if (typeof body !== "object" || body === null) return null;
|
|
1745
|
+
const { message } = body;
|
|
1746
|
+
return typeof message === "string" && message.trim().length > 0 ? message : null;
|
|
1747
|
+
} catch {
|
|
1748
|
+
return null;
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1704
1751
|
const SIGNATURE_TOLERANCE_SECONDS = 300;
|
|
1705
1752
|
const SIGNATURE_HEADER_RE = /^t=(\d+),v1=([0-9a-f]+)$/;
|
|
1706
1753
|
const SECONDS_PER_MS = 1e3;
|
|
@@ -1923,17 +1970,27 @@ function createClivlySDK(config) {
|
|
|
1923
1970
|
}, response);
|
|
1924
1971
|
return true;
|
|
1925
1972
|
}
|
|
1926
|
-
lastPushFailure ??= {
|
|
1973
|
+
lastPushFailure ??= {
|
|
1974
|
+
status: response?.status ?? null,
|
|
1975
|
+
message: await readPushFailureMessage(response)
|
|
1976
|
+
};
|
|
1927
1977
|
return false;
|
|
1928
1978
|
};
|
|
1929
1979
|
const describePushFailure = (entities) => {
|
|
1930
1980
|
const base = `Clivly sync: push failed for ${entities.join(", ")}`;
|
|
1931
1981
|
const status = lastPushFailure?.status ?? null;
|
|
1982
|
+
const serverMessage = lastPushFailure?.message ?? null;
|
|
1932
1983
|
let cause;
|
|
1933
1984
|
if (status === 401 || status === 403) cause = "the API key was rejected — check CLIVLY_API_KEY is set to a valid key for this org";
|
|
1934
1985
|
else if (status === null) cause = `couldn't reach Clivly at ${apiUrl} — check network access and CLIVLY_API_URL`;
|
|
1986
|
+
else if (serverMessage) cause = `Clivly returned HTTP ${status}: ${serverMessage}`;
|
|
1935
1987
|
else cause = `Clivly returned HTTP ${status}`;
|
|
1936
|
-
|
|
1988
|
+
const separator = SENTENCE_END_RE.test(cause) ? "" : ".";
|
|
1989
|
+
return `${base}: ${cause}${separator} Run \`clivly doctor\` to diagnose.`;
|
|
1990
|
+
};
|
|
1991
|
+
const pushFailureError = (message) => {
|
|
1992
|
+
const status = lastPushFailure?.status ?? null;
|
|
1993
|
+
return status !== null && status >= CLIENT_ERROR_FLOOR && status < RETRYABLE_STATUS_FLOOR ? new TriggerRequestError(status, message) : new Error(message);
|
|
1937
1994
|
};
|
|
1938
1995
|
const syncOne = async (source, path, mode, objectType, runId, batchSizeOverride, maxRowsOverride, persistCursor = true) => {
|
|
1939
1996
|
const since = mode === "full" ? null : await cursorStore.get(source.entity) ?? null;
|
|
@@ -2023,7 +2080,7 @@ function createClivlySDK(config) {
|
|
|
2023
2080
|
failed: true,
|
|
2024
2081
|
error: message
|
|
2025
2082
|
};
|
|
2026
|
-
throw
|
|
2083
|
+
throw pushFailureError(message);
|
|
2027
2084
|
}
|
|
2028
2085
|
lastPush = { failed: false };
|
|
2029
2086
|
};
|
|
@@ -2031,7 +2088,7 @@ function createClivlySDK(config) {
|
|
|
2031
2088
|
const resolved = resolveSampleSource(config, entityKey);
|
|
2032
2089
|
if (!resolved) throw new TriggerRequestError(400, `Clivly sync: no source is configured for entity "${entityKey}". The dashboard maps this table, but clivly.config declares no matching entity — add it to \`entities\`, or remove the mapping in Integrations → Mapping.`);
|
|
2033
2090
|
lastPushFailure = null;
|
|
2034
|
-
if (!await syncOne(resolved.source, resolved.path, "delta", resolved.objectType, runId, SAMPLE_BATCH_SIZE, SAMPLE_BATCH_SIZE, false)) throw
|
|
2091
|
+
if (!await syncOne(resolved.source, resolved.path, "delta", resolved.objectType, runId, SAMPLE_BATCH_SIZE, SAMPLE_BATCH_SIZE, false)) throw pushFailureError(describePushFailure([resolved.source.entity]));
|
|
2035
2092
|
};
|
|
2036
2093
|
const describeSyncTrigger = () => ({
|
|
2037
2094
|
configured: config.syncTrigger?.url,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_projection = require("./projection-Dz6_i1-w.cjs");
|
|
2
|
-
const require_entity_config = require("./entity-config-
|
|
3
|
-
const require_mappings_config = require("./mappings-config-
|
|
2
|
+
const require_entity_config = require("./entity-config-EZg9BtqD.cjs");
|
|
3
|
+
const require_mappings_config = require("./mappings-config-BRP_Dev5.cjs");
|
|
4
4
|
const require_drizzle_meta = require("./drizzle-meta-Bb1JWYqf.cjs");
|
|
5
5
|
//#region ../sdk/src/deployment-identity.ts
|
|
6
6
|
const MAX_DEPLOYMENT_ID_LENGTH = 128;
|
|
@@ -392,11 +392,15 @@ function errorMessage(error) {
|
|
|
392
392
|
/**
|
|
393
393
|
* The entities to ask about, in the exact terms the sync pushes them.
|
|
394
394
|
*
|
|
395
|
-
* `source` is the
|
|
395
|
+
* `source` is whatever the push will actually send — the value that arrives at
|
|
396
396
|
* `ingestPush` as `input.source` and is compared against `mapping.sourceTable`.
|
|
397
|
+
* Usually that is `SyncSource.entity`, but a projection pushes under its base
|
|
398
|
+
* table, so this asks `customPushSource` rather than reading `entity` directly.
|
|
399
|
+
*
|
|
397
400
|
* It is NOT the entity config's own `source` field, which names a host table;
|
|
398
|
-
* the two are routinely conflated, and using the wrong one
|
|
399
|
-
*
|
|
401
|
+
* the two are routinely conflated, and using the wrong one reports a correctly
|
|
402
|
+
* mapped workspace as unmapped — which is exactly what happened to every
|
|
403
|
+
* projection until this used the push label.
|
|
400
404
|
*/
|
|
401
405
|
function readinessEntitiesFromConfig(config) {
|
|
402
406
|
const entities = [];
|
|
@@ -405,7 +409,7 @@ function readinessEntitiesFromConfig(config) {
|
|
|
405
409
|
if (!resolved) continue;
|
|
406
410
|
const objectTypeSlug = resolved.source.objectType;
|
|
407
411
|
entities.push({
|
|
408
|
-
source: resolved.source
|
|
412
|
+
source: customPushSource(config, resolved.source),
|
|
409
413
|
concept: resolved.concept,
|
|
410
414
|
...resolved.concept === "custom" && objectTypeSlug ? { objectTypeSlug } : {}
|
|
411
415
|
});
|
|
@@ -1468,8 +1472,18 @@ function jsonResponse$1(body, status) {
|
|
|
1468
1472
|
function normalizeApiUrl(apiUrl) {
|
|
1469
1473
|
return apiUrl.replace(TRAILING_SLASH$1, "");
|
|
1470
1474
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1475
|
+
/**
|
|
1476
|
+
* The origin *claimed* by the request, for reporting upstream.
|
|
1477
|
+
*
|
|
1478
|
+
* Falls back to the request URL so Clivly still receives an origin for a
|
|
1479
|
+
* non-browser caller. This value is reported, never trusted: only a real
|
|
1480
|
+
* `Origin` header is evidence of where a request came from, so the access
|
|
1481
|
+
* decision uses {@link trustedOrigin} instead. Keeping the two apart is the
|
|
1482
|
+
* point — conflating them let a caller that simply omitted the header be
|
|
1483
|
+
* judged against the server's own origin, which is usually in the allowlist.
|
|
1484
|
+
*/
|
|
1485
|
+
function reportedOrigin(req) {
|
|
1486
|
+
const headerOrigin = trustedOrigin(req);
|
|
1473
1487
|
if (headerOrigin) return headerOrigin;
|
|
1474
1488
|
try {
|
|
1475
1489
|
return new URL(req.url).origin;
|
|
@@ -1477,6 +1491,15 @@ function resolveOrigin(req) {
|
|
|
1477
1491
|
return null;
|
|
1478
1492
|
}
|
|
1479
1493
|
}
|
|
1494
|
+
/**
|
|
1495
|
+
* The only origin worth an access decision: one the browser set itself.
|
|
1496
|
+
*
|
|
1497
|
+
* A missing header means "not a browser request we can vouch for", which is
|
|
1498
|
+
* untrusted — never the server's own origin.
|
|
1499
|
+
*/
|
|
1500
|
+
function trustedOrigin(req) {
|
|
1501
|
+
return req.headers.get("origin");
|
|
1502
|
+
}
|
|
1480
1503
|
function isChatSessionRequestBody(value) {
|
|
1481
1504
|
if (typeof value !== "object" || value === null) return false;
|
|
1482
1505
|
const body = value;
|
|
@@ -1487,6 +1510,17 @@ function isChatSessionRequestBody(value) {
|
|
|
1487
1510
|
if (typeof visitor.email !== "string" || visitor.email.trim().length === 0) return false;
|
|
1488
1511
|
return body.visitorToken === void 0 || body.visitorToken === null || typeof body.visitorToken === "string";
|
|
1489
1512
|
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Judge a request against the configured allowlist.
|
|
1515
|
+
*
|
|
1516
|
+
* `origin` must be a *trusted* origin (see {@link trustedOrigin}) — passing
|
|
1517
|
+
* the reported one would reinstate the bypass this guards against.
|
|
1518
|
+
*
|
|
1519
|
+
* An unset allowlist still admits every origin, because requiring it would
|
|
1520
|
+
* break every existing deployment on upgrade. The unset case is instead
|
|
1521
|
+
* warned about once at construction, so the permissive default is loud
|
|
1522
|
+
* rather than silent.
|
|
1523
|
+
*/
|
|
1490
1524
|
function originAllowed(origin, allowedOrigins) {
|
|
1491
1525
|
if (!allowedOrigins || allowedOrigins.length === 0) return true;
|
|
1492
1526
|
if (!origin) return false;
|
|
@@ -1494,6 +1528,7 @@ function originAllowed(origin, allowedOrigins) {
|
|
|
1494
1528
|
}
|
|
1495
1529
|
function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API_URL$1, fetchImpl = fetch, resolveUser }) {
|
|
1496
1530
|
const sessionUrl = `${normalizeApiUrl(apiUrl)}/clivly/widget/session`;
|
|
1531
|
+
if (!allowedOrigins || allowedOrigins.length === 0) console.warn("[clivly] createChatSessionHandler has no allowedOrigins; every origin can open a chat session against this workspace. Pass allowedOrigins to restrict it.");
|
|
1497
1532
|
return async (request) => {
|
|
1498
1533
|
if (request.method !== "POST") return new Response(JSON.stringify({ error: "method_not_allowed" }), {
|
|
1499
1534
|
status: 405,
|
|
@@ -1502,8 +1537,8 @@ function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API
|
|
|
1502
1537
|
allow: "POST"
|
|
1503
1538
|
}
|
|
1504
1539
|
});
|
|
1505
|
-
|
|
1506
|
-
|
|
1540
|
+
if (!originAllowed(trustedOrigin(request), allowedOrigins)) return jsonResponse$1({ error: "origin_not_allowed" }, 403);
|
|
1541
|
+
const origin = reportedOrigin(request);
|
|
1507
1542
|
let body;
|
|
1508
1543
|
try {
|
|
1509
1544
|
body = await request.json();
|
|
@@ -1701,6 +1736,18 @@ var TriggerRequestError = class extends Error {
|
|
|
1701
1736
|
function triggerErrorStatus(error) {
|
|
1702
1737
|
return error instanceof TriggerRequestError ? error.status : 500;
|
|
1703
1738
|
}
|
|
1739
|
+
const SENTENCE_END_RE = /[.!?]$/;
|
|
1740
|
+
async function readPushFailureMessage(response) {
|
|
1741
|
+
if (!response || typeof response.json !== "function") return null;
|
|
1742
|
+
try {
|
|
1743
|
+
const body = await response.json();
|
|
1744
|
+
if (typeof body !== "object" || body === null) return null;
|
|
1745
|
+
const { message } = body;
|
|
1746
|
+
return typeof message === "string" && message.trim().length > 0 ? message : null;
|
|
1747
|
+
} catch {
|
|
1748
|
+
return null;
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1704
1751
|
const SIGNATURE_TOLERANCE_SECONDS = 300;
|
|
1705
1752
|
const SIGNATURE_HEADER_RE = /^t=(\d+),v1=([0-9a-f]+)$/;
|
|
1706
1753
|
const SECONDS_PER_MS = 1e3;
|
|
@@ -1923,17 +1970,27 @@ function createClivlySDK(config) {
|
|
|
1923
1970
|
}, response);
|
|
1924
1971
|
return true;
|
|
1925
1972
|
}
|
|
1926
|
-
lastPushFailure ??= {
|
|
1973
|
+
lastPushFailure ??= {
|
|
1974
|
+
status: response?.status ?? null,
|
|
1975
|
+
message: await readPushFailureMessage(response)
|
|
1976
|
+
};
|
|
1927
1977
|
return false;
|
|
1928
1978
|
};
|
|
1929
1979
|
const describePushFailure = (entities) => {
|
|
1930
1980
|
const base = `Clivly sync: push failed for ${entities.join(", ")}`;
|
|
1931
1981
|
const status = lastPushFailure?.status ?? null;
|
|
1982
|
+
const serverMessage = lastPushFailure?.message ?? null;
|
|
1932
1983
|
let cause;
|
|
1933
1984
|
if (status === 401 || status === 403) cause = "the API key was rejected — check CLIVLY_API_KEY is set to a valid key for this org";
|
|
1934
1985
|
else if (status === null) cause = `couldn't reach Clivly at ${apiUrl} — check network access and CLIVLY_API_URL`;
|
|
1986
|
+
else if (serverMessage) cause = `Clivly returned HTTP ${status}: ${serverMessage}`;
|
|
1935
1987
|
else cause = `Clivly returned HTTP ${status}`;
|
|
1936
|
-
|
|
1988
|
+
const separator = SENTENCE_END_RE.test(cause) ? "" : ".";
|
|
1989
|
+
return `${base}: ${cause}${separator} Run \`clivly doctor\` to diagnose.`;
|
|
1990
|
+
};
|
|
1991
|
+
const pushFailureError = (message) => {
|
|
1992
|
+
const status = lastPushFailure?.status ?? null;
|
|
1993
|
+
return status !== null && status >= CLIENT_ERROR_FLOOR && status < RETRYABLE_STATUS_FLOOR ? new TriggerRequestError(status, message) : new Error(message);
|
|
1937
1994
|
};
|
|
1938
1995
|
const syncOne = async (source, path, mode, objectType, runId, batchSizeOverride, maxRowsOverride, persistCursor = true) => {
|
|
1939
1996
|
const since = mode === "full" ? null : await cursorStore.get(source.entity) ?? null;
|
|
@@ -2023,7 +2080,7 @@ function createClivlySDK(config) {
|
|
|
2023
2080
|
failed: true,
|
|
2024
2081
|
error: message
|
|
2025
2082
|
};
|
|
2026
|
-
throw
|
|
2083
|
+
throw pushFailureError(message);
|
|
2027
2084
|
}
|
|
2028
2085
|
lastPush = { failed: false };
|
|
2029
2086
|
};
|
|
@@ -2031,7 +2088,7 @@ function createClivlySDK(config) {
|
|
|
2031
2088
|
const resolved = resolveSampleSource(config, entityKey);
|
|
2032
2089
|
if (!resolved) throw new TriggerRequestError(400, `Clivly sync: no source is configured for entity "${entityKey}". The dashboard maps this table, but clivly.config declares no matching entity — add it to \`entities\`, or remove the mapping in Integrations → Mapping.`);
|
|
2033
2090
|
lastPushFailure = null;
|
|
2034
|
-
if (!await syncOne(resolved.source, resolved.path, "delta", resolved.objectType, runId, SAMPLE_BATCH_SIZE, SAMPLE_BATCH_SIZE, false)) throw
|
|
2091
|
+
if (!await syncOne(resolved.source, resolved.path, "delta", resolved.objectType, runId, SAMPLE_BATCH_SIZE, SAMPLE_BATCH_SIZE, false)) throw pushFailureError(describePushFailure([resolved.source.entity]));
|
|
2035
2092
|
};
|
|
2036
2093
|
const describeSyncTrigger = () => ({
|
|
2037
2094
|
configured: config.syncTrigger?.url,
|
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-
|
|
3
|
-
const require_sdk = require("./sdk-
|
|
2
|
+
const require_entity_config = require("./entity-config-EZg9BtqD.cjs");
|
|
3
|
+
const require_sdk = require("./sdk-UCBezLoT.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
|
-
import { C as customObjectDeclarations, M as validateEntitiesConfig, a as ClivlyEntitiesConfig, f as CustomObjectDeclaration, l as ConfigValidationError, m as DiscoveredSchemaTable, u as ConfigValidationResult, w as defineClivlyConfig } from "./entity-config-
|
|
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-
|
|
1
|
+
import { C as customObjectDeclarations, M as validateEntitiesConfig, a as ClivlyEntitiesConfig, f as CustomObjectDeclaration, l as ConfigValidationError, m as DiscoveredSchemaTable, u as ConfigValidationResult, w as defineClivlyConfig } from "./entity-config-CbS2DGmA.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-DC4YsI6m.cjs";
|
|
3
3
|
//#region ../sdk/src/trigger-url.d.ts
|
|
4
4
|
declare function isPlaceholderUrl(value: string): boolean;
|
|
5
5
|
//#endregion
|
package/sdk.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as customObjectDeclarations, M as validateEntitiesConfig, a as ClivlyEntitiesConfig, f as CustomObjectDeclaration, l as ConfigValidationError, m as DiscoveredSchemaTable, u as ConfigValidationResult, w as defineClivlyConfig } from "./entity-config-
|
|
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-
|
|
1
|
+
import { C as customObjectDeclarations, M as validateEntitiesConfig, a as ClivlyEntitiesConfig, f as CustomObjectDeclaration, l as ConfigValidationError, m as DiscoveredSchemaTable, u as ConfigValidationResult, w as defineClivlyConfig } from "./entity-config-CbS2DGmA.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-BWZ7f1fg.mjs";
|
|
3
3
|
//#region ../sdk/src/trigger-url.d.ts
|
|
4
4
|
declare function isPlaceholderUrl(value: string): boolean;
|
|
5
5
|
//#endregion
|
package/sdk.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as defineClivlyConfig, g as validateEntitiesConfig, s as customObjectDeclarations } from "./entity-config-
|
|
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-
|
|
1
|
+
import { c as defineClivlyConfig, g as validateEntitiesConfig, s as customObjectDeclarations } from "./entity-config-CO0TEwZC.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-CsR4W9QQ.mjs";
|
|
3
3
|
export { ClivlyAuthError, ClivlyError, ClivlyNetworkError, ClivlyRateLimitError, createChatSessionHandler, createClivlySDK, customObjectDeclarations, defineClivlyConfig, isPlaceholderUrl, validateEntitiesConfig };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as ClivlyEntitiesConfig } from "./entity-config-
|
|
2
|
-
import { n as CompiledView, t as CompileOptions } from "./view-compiler-
|
|
1
|
+
import { a as ClivlyEntitiesConfig } from "./entity-config-CbS2DGmA.mjs";
|
|
2
|
+
import { n as CompiledView, t as CompileOptions } from "./view-compiler-CdnLqPQx.mjs";
|
|
3
3
|
//#region ../core/src/sync-engine.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Sync engine (Phase 3) — materializes the read-only entity views into Clivly's
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as ClivlyEntitiesConfig } from "./entity-config-
|
|
2
|
-
import { n as CompiledView, t as CompileOptions } from "./view-compiler-
|
|
1
|
+
import { a as ClivlyEntitiesConfig } from "./entity-config-CbS2DGmA.cjs";
|
|
2
|
+
import { n as CompiledView, t as CompileOptions } from "./view-compiler-P4GHpOHt.cjs";
|
|
3
3
|
//#region ../core/src/sync-engine.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Sync engine (Phase 3) — materializes the read-only entity views into Clivly's
|
|
@@ -39,6 +39,7 @@ interface Contact {
|
|
|
39
39
|
lastActivityAt: Date | null;
|
|
40
40
|
name: string;
|
|
41
41
|
orgId: string;
|
|
42
|
+
phone: string | null;
|
|
42
43
|
status: ContactStatus;
|
|
43
44
|
title: string | null;
|
|
44
45
|
}
|
|
@@ -108,6 +109,7 @@ interface CreateContactInput {
|
|
|
108
109
|
companyId?: string;
|
|
109
110
|
email: string;
|
|
110
111
|
name: string;
|
|
112
|
+
phone?: string;
|
|
111
113
|
status?: ContactStatus;
|
|
112
114
|
title?: string;
|
|
113
115
|
}
|
|
@@ -115,6 +117,7 @@ interface UpdateContactInput {
|
|
|
115
117
|
companyId?: string | null;
|
|
116
118
|
email?: string;
|
|
117
119
|
name?: string;
|
|
120
|
+
phone?: string | null;
|
|
118
121
|
status?: ContactStatus;
|
|
119
122
|
title?: string | null;
|
|
120
123
|
}
|
|
@@ -39,6 +39,7 @@ interface Contact {
|
|
|
39
39
|
lastActivityAt: Date | null;
|
|
40
40
|
name: string;
|
|
41
41
|
orgId: string;
|
|
42
|
+
phone: string | null;
|
|
42
43
|
status: ContactStatus;
|
|
43
44
|
title: string | null;
|
|
44
45
|
}
|
|
@@ -108,6 +109,7 @@ interface CreateContactInput {
|
|
|
108
109
|
companyId?: string;
|
|
109
110
|
email: string;
|
|
110
111
|
name: string;
|
|
112
|
+
phone?: string;
|
|
111
113
|
status?: ContactStatus;
|
|
112
114
|
title?: string;
|
|
113
115
|
}
|
|
@@ -115,6 +117,7 @@ interface UpdateContactInput {
|
|
|
115
117
|
companyId?: string | null;
|
|
116
118
|
email?: string;
|
|
117
119
|
name?: string;
|
|
120
|
+
phone?: string | null;
|
|
118
121
|
status?: ContactStatus;
|
|
119
122
|
title?: string | null;
|
|
120
123
|
}
|
package/vite.d.cts
CHANGED
package/vite.d.mts
CHANGED