clivly 0.4.1 → 0.7.1
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 +89 -10
- package/{adapter-CXr12l4K.d.cts → adapter-C2eRbBfo.d.cts} +1 -2
- package/{adapter-CvNBD_3y.d.mts → adapter-D5LRa-NA.d.mts} +1 -2
- package/{auth-adapter-CdLODn2p.d.cts → auth-adapter-Bjgo8LhN.d.mts} +1 -2
- package/{auth-adapter-CRBW4elj.d.mts → auth-adapter-DWzgl5Yq.d.cts} +1 -2
- package/auth-better-auth.d.cts +1 -2
- package/auth-better-auth.d.mts +1 -2
- package/auth-clerk.d.cts +1 -2
- package/auth-clerk.d.mts +1 -2
- package/auth-workos.d.cts +1 -2
- package/auth-workos.d.mts +1 -2
- package/core-adapter.cjs +5 -0
- package/core-adapter.d.cts +1 -1
- package/core-adapter.d.mts +1 -1
- package/core-adapter.mjs +5 -0
- package/core-auth-adapter.cjs +6 -1
- package/core-auth-adapter.d.cts +1 -1
- package/core-auth-adapter.d.mts +1 -1
- package/core-auth-adapter.mjs +6 -1
- package/core-drizzle.cjs +6 -30
- package/core-drizzle.d.cts +1 -20
- package/core-drizzle.d.mts +1 -20
- package/core-drizzle.mjs +5 -29
- package/core-entity-config.cjs +4 -1
- package/core-entity-config.d.cts +1 -1
- package/core-entity-config.d.mts +1 -1
- package/core-entity-config.mjs +5 -1
- package/core-entity-heuristics.cjs +14 -453
- package/core-entity-heuristics.d.cts +1 -67
- package/core-entity-heuristics.d.mts +1 -67
- package/core-entity-heuristics.mjs +4 -442
- package/core-mapping-form.cjs +6 -1
- package/core-mapping-form.d.cts +1 -1
- package/core-mapping-form.d.mts +1 -1
- package/core-mapping-form.mjs +6 -1
- package/core-mapping-score.cjs +4 -1
- package/core-mapping-score.d.cts +1 -1
- package/core-mapping-score.d.mts +1 -1
- package/core-mapping-score.mjs +5 -1
- package/core-mappings-config.cjs +6 -1
- package/core-mappings-config.d.cts +1 -1
- package/core-mappings-config.d.mts +1 -1
- package/core-mappings-config.mjs +6 -1
- package/core-sync-engine.cjs +6 -1
- package/core-sync-engine.d.cts +1 -1
- package/core-sync-engine.d.mts +1 -1
- package/core-sync-engine.mjs +6 -1
- package/core-types.cjs +5 -0
- package/core-types.d.cts +1 -1
- package/core-types.d.mts +1 -1
- package/core-types.mjs +5 -0
- package/core-view-compiler.cjs +6 -1
- package/core-view-compiler.d.cts +1 -1
- package/core-view-compiler.d.mts +1 -1
- package/core-view-compiler.mjs +6 -1
- package/core.cjs +11 -6
- package/core.d.cts +9 -9
- package/core.d.mts +9 -9
- package/core.mjs +11 -6
- package/deprecate-subpath-B9ngvizt.cjs +30 -0
- package/deprecate-subpath-CmvZtCpE.mjs +25 -0
- package/drizzle-B89tLo4T.mjs +31 -0
- package/drizzle-CFOr9dU9.d.mts +20 -0
- package/drizzle-DiReZf6d.cjs +36 -0
- package/drizzle-DmeKSqeF.d.cts +20 -0
- package/drizzle.cjs +3 -1
- package/drizzle.d.cts +11 -3
- package/drizzle.d.mts +11 -3
- package/drizzle.mjs +3 -2
- package/{entity-config-DMuZpchz.cjs → entity-config-D87rV-tE.cjs} +194 -192
- package/{entity-config-D1DFyeUp.d.mts → entity-config-DoUCXtq5.d.cts} +48 -35
- package/{entity-config-GczjD3y8.d.cts → entity-config-DoUCXtq5.d.mts} +48 -35
- package/{entity-config-D3YpQB0z.mjs → entity-config-va2bkH5o.mjs} +194 -192
- package/index.cjs +910 -234
- package/index.d.cts +30 -2
- package/index.d.mts +30 -2
- package/index.mjs +900 -226
- package/internal-adapter.cjs +0 -0
- package/internal-adapter.d.cts +2 -0
- package/internal-adapter.d.mts +2 -0
- package/internal-adapter.mjs +1 -0
- package/internal-auth-adapter.cjs +3 -0
- package/internal-auth-adapter.d.cts +2 -0
- package/internal-auth-adapter.d.mts +2 -0
- package/internal-auth-adapter.mjs +2 -0
- package/internal-drizzle.cjs +3 -0
- package/internal-drizzle.d.cts +2 -0
- package/internal-drizzle.d.mts +2 -0
- package/internal-drizzle.mjs +2 -0
- package/internal-entity-config.cjs +13 -0
- package/internal-entity-config.d.cts +2 -0
- package/internal-entity-config.d.mts +2 -0
- package/internal-entity-config.mjs +2 -0
- package/internal-entity-heuristics.cjs +455 -0
- package/internal-entity-heuristics.d.cts +67 -0
- package/internal-entity-heuristics.d.mts +67 -0
- package/internal-entity-heuristics.mjs +444 -0
- package/internal-mapping-form.cjs +5 -0
- package/internal-mapping-form.d.cts +2 -0
- package/internal-mapping-form.d.mts +2 -0
- package/internal-mapping-form.mjs +2 -0
- package/internal-mapping-score.cjs +12 -0
- package/internal-mapping-score.d.cts +2 -0
- package/internal-mapping-score.d.mts +2 -0
- package/internal-mapping-score.mjs +2 -0
- package/internal-mappings-config.cjs +3 -0
- package/internal-mappings-config.d.cts +2 -0
- package/internal-mappings-config.d.mts +2 -0
- package/internal-mappings-config.mjs +2 -0
- package/internal-sync-engine.cjs +6 -0
- package/internal-sync-engine.d.cts +2 -0
- package/internal-sync-engine.d.mts +2 -0
- package/internal-sync-engine.mjs +2 -0
- package/internal-types.cjs +0 -0
- package/internal-types.d.cts +2 -0
- package/internal-types.d.mts +2 -0
- package/internal-types.mjs +1 -0
- package/internal-view-compiler.cjs +6 -0
- package/internal-view-compiler.d.cts +2 -0
- package/internal-view-compiler.d.mts +2 -0
- package/internal-view-compiler.mjs +2 -0
- package/internal.cjs +28 -0
- package/internal.d.cts +9 -0
- package/internal.d.mts +9 -0
- package/internal.mjs +7 -0
- package/{mapping-form-CUlFVfG8.d.cts → mapping-form-D93lhHEc.d.mts} +1 -2
- package/{mapping-form-kjSiJaCX.d.mts → mapping-form-lfyEE7EJ.d.cts} +1 -2
- package/{mappings-config-DYZ_uOOB.cjs → mappings-config-BsRADNRv.cjs} +1 -1
- package/{mappings-config-CNTZRD4g.mjs → mappings-config-Dbgxx3Nv.mjs} +1 -1
- package/{mappings-config-DjRLCb2Q.d.cts → mappings-config-DsUa7-1w.d.mts} +1 -2
- package/{mappings-config-GxiYsSBQ.d.mts → mappings-config-XmzB4dag.d.cts} +1 -2
- package/package.json +152 -4
- package/{sdk-DdzBxgMx.mjs → sdk-C6WANW8M.mjs} +173 -34
- package/{sdk-D1BHQDf5.cjs → sdk-iqOXeWIp.cjs} +173 -34
- package/sdk.cjs +3 -1
- package/sdk.d.cts +1 -41
- package/sdk.d.mts +1 -41
- package/sdk.mjs +3 -2
- package/{sync-engine-DIVMG9EV.d.cts → sync-engine-B7QIbXro.d.cts} +6 -5
- package/{sync-engine-BtzkzKmY.cjs → sync-engine-CzEbpQGv.cjs} +1 -1
- package/{sync-engine-DLx243iw.d.mts → sync-engine-DGk_AeHJ.d.mts} +6 -5
- package/{sync-engine-D9vghQab.mjs → sync-engine-Do5ru3WF.mjs} +1 -1
- package/types-CsL0rFYh.d.cts +155 -0
- package/types-CsL0rFYh.d.mts +155 -0
- package/{view-compiler-4HsRUTWH.d.cts → view-compiler-BWz0sGdm.d.cts} +1 -2
- package/{view-compiler-BpIDExjd.d.mts → view-compiler-Bn_EJJMO.d.mts} +1 -2
- package/vite.d.cts +1 -2
- package/vite.d.mts +1 -2
- package/namespace-probe-CA4Vj40g.d.mts +0 -331
- package/namespace-probe-CkHCj9tQ.d.cts +0 -331
- /package/{auth-adapter-CBOKDhlc.cjs → auth-adapter-CiEXcweZ.cjs} +0 -0
- /package/{auth-adapter-wqnnEjo3.mjs → auth-adapter-gfVDxf3d.mjs} +0 -0
- /package/{drizzle-meta-BVR1qiyu.cjs → drizzle-meta-Bb1JWYqf.cjs} +0 -0
- /package/{drizzle-meta-DpMKataU.mjs → drizzle-meta-D-5k3n0i.mjs} +0 -0
- /package/{mapping-form-DdmDebC3.cjs → mapping-form-BpfON_ME.cjs} +0 -0
- /package/{mapping-form-BHtPexzI.mjs → mapping-form-DigkuvFc.mjs} +0 -0
- /package/{mapping-score-CPPvwoZC.mjs → mapping-score-C68uAqGB.mjs} +0 -0
- /package/{mapping-score-i3p8LWDF.cjs → mapping-score-CaB3F4Uu.cjs} +0 -0
- /package/{mapping-score-A2lRnlpk.d.mts → mapping-score-D7Gzg7Ii.d.cts} +0 -0
- /package/{mapping-score-BcjC0ZQs.d.cts → mapping-score-D7Gzg7Ii.d.mts} +0 -0
- /package/{types-BpsKVccL.d.cts → types-B1oRXdNP.d.cts} +0 -0
- /package/{types-_qbJXMt_.d.mts → types-B1oRXdNP.d.mts} +0 -0
- /package/{view-compiler-BcgJINr7.cjs → view-compiler-BIwvm-o2.cjs} +0 -0
- /package/{view-compiler-DeZzx_jn.mjs → view-compiler-ChWr_Lml.mjs} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clivly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Clivly CLI — scaffold a CRM into your app (clivly init).",
|
|
@@ -11,6 +11,34 @@
|
|
|
11
11
|
"main": "./index.cjs",
|
|
12
12
|
"module": "./index.mjs",
|
|
13
13
|
"types": "./index.d.mts",
|
|
14
|
+
"sideEffects": [
|
|
15
|
+
"./index.mjs",
|
|
16
|
+
"./index.cjs",
|
|
17
|
+
"./core.mjs",
|
|
18
|
+
"./core.cjs",
|
|
19
|
+
"./core-adapter.mjs",
|
|
20
|
+
"./core-adapter.cjs",
|
|
21
|
+
"./core-auth-adapter.mjs",
|
|
22
|
+
"./core-auth-adapter.cjs",
|
|
23
|
+
"./core-drizzle.mjs",
|
|
24
|
+
"./core-drizzle.cjs",
|
|
25
|
+
"./core-entity-config.mjs",
|
|
26
|
+
"./core-entity-config.cjs",
|
|
27
|
+
"./core-entity-heuristics.mjs",
|
|
28
|
+
"./core-entity-heuristics.cjs",
|
|
29
|
+
"./core-mapping-form.mjs",
|
|
30
|
+
"./core-mapping-form.cjs",
|
|
31
|
+
"./core-mapping-score.mjs",
|
|
32
|
+
"./core-mapping-score.cjs",
|
|
33
|
+
"./core-mappings-config.mjs",
|
|
34
|
+
"./core-mappings-config.cjs",
|
|
35
|
+
"./core-sync-engine.mjs",
|
|
36
|
+
"./core-sync-engine.cjs",
|
|
37
|
+
"./core-types.mjs",
|
|
38
|
+
"./core-types.cjs",
|
|
39
|
+
"./core-view-compiler.mjs",
|
|
40
|
+
"./core-view-compiler.cjs"
|
|
41
|
+
],
|
|
14
42
|
"files": [
|
|
15
43
|
"*.cjs",
|
|
16
44
|
"*.mjs",
|
|
@@ -151,6 +179,126 @@
|
|
|
151
179
|
"default": "./core-view-compiler.cjs"
|
|
152
180
|
}
|
|
153
181
|
},
|
|
182
|
+
"./internal": {
|
|
183
|
+
"import": {
|
|
184
|
+
"types": "./internal.d.mts",
|
|
185
|
+
"default": "./internal.mjs"
|
|
186
|
+
},
|
|
187
|
+
"require": {
|
|
188
|
+
"types": "./internal.d.cts",
|
|
189
|
+
"default": "./internal.cjs"
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"./internal/adapter": {
|
|
193
|
+
"import": {
|
|
194
|
+
"types": "./internal-adapter.d.mts",
|
|
195
|
+
"default": "./internal-adapter.mjs"
|
|
196
|
+
},
|
|
197
|
+
"require": {
|
|
198
|
+
"types": "./internal-adapter.d.cts",
|
|
199
|
+
"default": "./internal-adapter.cjs"
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"./internal/auth-adapter": {
|
|
203
|
+
"import": {
|
|
204
|
+
"types": "./internal-auth-adapter.d.mts",
|
|
205
|
+
"default": "./internal-auth-adapter.mjs"
|
|
206
|
+
},
|
|
207
|
+
"require": {
|
|
208
|
+
"types": "./internal-auth-adapter.d.cts",
|
|
209
|
+
"default": "./internal-auth-adapter.cjs"
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"./internal/drizzle": {
|
|
213
|
+
"import": {
|
|
214
|
+
"types": "./internal-drizzle.d.mts",
|
|
215
|
+
"default": "./internal-drizzle.mjs"
|
|
216
|
+
},
|
|
217
|
+
"require": {
|
|
218
|
+
"types": "./internal-drizzle.d.cts",
|
|
219
|
+
"default": "./internal-drizzle.cjs"
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"./internal/entity-config": {
|
|
223
|
+
"import": {
|
|
224
|
+
"types": "./internal-entity-config.d.mts",
|
|
225
|
+
"default": "./internal-entity-config.mjs"
|
|
226
|
+
},
|
|
227
|
+
"require": {
|
|
228
|
+
"types": "./internal-entity-config.d.cts",
|
|
229
|
+
"default": "./internal-entity-config.cjs"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"./internal/entity-heuristics": {
|
|
233
|
+
"import": {
|
|
234
|
+
"types": "./internal-entity-heuristics.d.mts",
|
|
235
|
+
"default": "./internal-entity-heuristics.mjs"
|
|
236
|
+
},
|
|
237
|
+
"require": {
|
|
238
|
+
"types": "./internal-entity-heuristics.d.cts",
|
|
239
|
+
"default": "./internal-entity-heuristics.cjs"
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"./internal/mapping-form": {
|
|
243
|
+
"import": {
|
|
244
|
+
"types": "./internal-mapping-form.d.mts",
|
|
245
|
+
"default": "./internal-mapping-form.mjs"
|
|
246
|
+
},
|
|
247
|
+
"require": {
|
|
248
|
+
"types": "./internal-mapping-form.d.cts",
|
|
249
|
+
"default": "./internal-mapping-form.cjs"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"./internal/mapping-score": {
|
|
253
|
+
"import": {
|
|
254
|
+
"types": "./internal-mapping-score.d.mts",
|
|
255
|
+
"default": "./internal-mapping-score.mjs"
|
|
256
|
+
},
|
|
257
|
+
"require": {
|
|
258
|
+
"types": "./internal-mapping-score.d.cts",
|
|
259
|
+
"default": "./internal-mapping-score.cjs"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
"./internal/mappings-config": {
|
|
263
|
+
"import": {
|
|
264
|
+
"types": "./internal-mappings-config.d.mts",
|
|
265
|
+
"default": "./internal-mappings-config.mjs"
|
|
266
|
+
},
|
|
267
|
+
"require": {
|
|
268
|
+
"types": "./internal-mappings-config.d.cts",
|
|
269
|
+
"default": "./internal-mappings-config.cjs"
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"./internal/sync-engine": {
|
|
273
|
+
"import": {
|
|
274
|
+
"types": "./internal-sync-engine.d.mts",
|
|
275
|
+
"default": "./internal-sync-engine.mjs"
|
|
276
|
+
},
|
|
277
|
+
"require": {
|
|
278
|
+
"types": "./internal-sync-engine.d.cts",
|
|
279
|
+
"default": "./internal-sync-engine.cjs"
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
"./internal/types": {
|
|
283
|
+
"import": {
|
|
284
|
+
"types": "./internal-types.d.mts",
|
|
285
|
+
"default": "./internal-types.mjs"
|
|
286
|
+
},
|
|
287
|
+
"require": {
|
|
288
|
+
"types": "./internal-types.d.cts",
|
|
289
|
+
"default": "./internal-types.cjs"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
"./internal/view-compiler": {
|
|
293
|
+
"import": {
|
|
294
|
+
"types": "./internal-view-compiler.d.mts",
|
|
295
|
+
"default": "./internal-view-compiler.mjs"
|
|
296
|
+
},
|
|
297
|
+
"require": {
|
|
298
|
+
"types": "./internal-view-compiler.d.cts",
|
|
299
|
+
"default": "./internal-view-compiler.cjs"
|
|
300
|
+
}
|
|
301
|
+
},
|
|
154
302
|
"./sdk": {
|
|
155
303
|
"import": {
|
|
156
304
|
"types": "./sdk.d.mts",
|
|
@@ -219,8 +367,8 @@
|
|
|
219
367
|
"peerDependencies": {
|
|
220
368
|
"@clerk/backend": ">=1",
|
|
221
369
|
"@workos-inc/node": ">=7",
|
|
222
|
-
"better-auth": ">=1",
|
|
223
|
-
"drizzle-orm": ">=0.30",
|
|
370
|
+
"better-auth": ">=1.6.22",
|
|
371
|
+
"drizzle-orm": ">=0.30 || >=1.0.0-rc.0",
|
|
224
372
|
"vite": ">=5"
|
|
225
373
|
},
|
|
226
374
|
"peerDependenciesMeta": {
|
|
@@ -242,7 +390,7 @@
|
|
|
242
390
|
},
|
|
243
391
|
"author": "Joseph Amani",
|
|
244
392
|
"engines": {
|
|
245
|
-
"node": ">=
|
|
393
|
+
"node": ">=22"
|
|
246
394
|
},
|
|
247
395
|
"repository": {
|
|
248
396
|
"type": "git",
|
|
@@ -1,4 +1,83 @@
|
|
|
1
|
-
import { t as DRIZZLE_META } from "./drizzle-meta-
|
|
1
|
+
import { t as DRIZZLE_META } from "./drizzle-meta-D-5k3n0i.mjs";
|
|
2
|
+
//#region ../sdk/src/entity-source.ts
|
|
3
|
+
const CONCEPT_KEYS = {
|
|
4
|
+
contact: "contacts",
|
|
5
|
+
company: "companies",
|
|
6
|
+
deal: "deals"
|
|
7
|
+
};
|
|
8
|
+
function resolveEntitySource(config, entityKey) {
|
|
9
|
+
const entity = config.entities?.entities?.[entityKey];
|
|
10
|
+
const src = config.source;
|
|
11
|
+
if (!(entity && src)) return null;
|
|
12
|
+
const conceptKey = CONCEPT_KEYS[entity.concept];
|
|
13
|
+
if (conceptKey) {
|
|
14
|
+
const source = src[conceptKey];
|
|
15
|
+
return source ? {
|
|
16
|
+
concept: entity.concept,
|
|
17
|
+
expectedKey: conceptKey,
|
|
18
|
+
source
|
|
19
|
+
} : null;
|
|
20
|
+
}
|
|
21
|
+
if (entity.concept === "custom") {
|
|
22
|
+
const match = (src.custom ?? []).find((c) => c.entity === entity.source || c.entity === entityKey);
|
|
23
|
+
return match ? {
|
|
24
|
+
concept: "custom",
|
|
25
|
+
expectedKey: "custom",
|
|
26
|
+
source: match
|
|
27
|
+
} : null;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/** The `config.source` key an entity's concept requires, present or not. */
|
|
32
|
+
function expectedSourceKey(concept) {
|
|
33
|
+
return CONCEPT_KEYS[concept] ?? "custom";
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region ../sdk/src/concept-coverage.ts
|
|
37
|
+
const CHECK_NAME = "Entity → source coverage";
|
|
38
|
+
function configuredKeys(config) {
|
|
39
|
+
const src = config.source;
|
|
40
|
+
if (!src) return [];
|
|
41
|
+
return Object.entries(src).filter(([, value]) => Array.isArray(value) ? value.length > 0 : Boolean(value)).map(([key]) => key);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Every configured entity must resolve to a source, or it silently syncs
|
|
45
|
+
* nothing. This is the check that catches `source` keyed by entity name rather
|
|
46
|
+
* than by CRM concept — a mistake that otherwise shows up only as a run that
|
|
47
|
+
* succeeds with zero rows.
|
|
48
|
+
*/
|
|
49
|
+
function checkConceptCoverage(config) {
|
|
50
|
+
const entities = config.entities?.entities ?? {};
|
|
51
|
+
const keys = Object.keys(entities);
|
|
52
|
+
if (keys.length === 0) return {
|
|
53
|
+
name: CHECK_NAME,
|
|
54
|
+
ok: false,
|
|
55
|
+
skipped: true,
|
|
56
|
+
detail: "No entities configured — nothing to cross-check."
|
|
57
|
+
};
|
|
58
|
+
const unresolved = keys.filter((key) => resolveEntitySource(config, key) === null);
|
|
59
|
+
if (unresolved.length === 0) return {
|
|
60
|
+
name: CHECK_NAME,
|
|
61
|
+
ok: true,
|
|
62
|
+
detail: `${keys.length} entit${keys.length === 1 ? "y" : "ies"} resolve to a configured source.`
|
|
63
|
+
};
|
|
64
|
+
const available = configuredKeys(config);
|
|
65
|
+
const listed = available.length > 0 ? available.join(", ") : "(none)";
|
|
66
|
+
const problems = unresolved.map((key) => {
|
|
67
|
+
const concept = entities[key]?.concept ?? "unknown";
|
|
68
|
+
if (concept === "custom") {
|
|
69
|
+
const custom = config.source?.custom ?? [];
|
|
70
|
+
if (custom.length > 0) return `"${key}" has concept "custom" but no entry in \`source.custom\` matches it — it will never sync. Entities configured in \`source.custom\`: ${custom.map((c) => c.entity).join(", ")}.`;
|
|
71
|
+
}
|
|
72
|
+
return `"${key}" has concept "${concept}" but no \`source.${expectedSourceKey(concept)}\` is configured — it will never sync.`;
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
name: CHECK_NAME,
|
|
76
|
+
ok: false,
|
|
77
|
+
detail: `${problems.join(" ")} Configured source keys: ${listed}. \`source\` is keyed by CRM concept, not by entity key.`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
2
81
|
//#region ../sdk/src/custom-slug.ts
|
|
3
82
|
const NON_ALNUM = /[^a-z0-9]+/g;
|
|
4
83
|
const EDGE_HYPHENS = /(^-|-$)/g;
|
|
@@ -79,6 +158,56 @@ function describeFetchError(entity, error) {
|
|
|
79
158
|
return `Couldn't read "${entity}": ${firstLine(root instanceof Error ? root.message : String(root?.message ?? root ?? "unknown error"))}`;
|
|
80
159
|
}
|
|
81
160
|
//#endregion
|
|
161
|
+
//#region ../sdk/src/mapping-dry-run.ts
|
|
162
|
+
/**
|
|
163
|
+
* Fetch one real row and push it through the entity's field map.
|
|
164
|
+
*
|
|
165
|
+
* The distinction from "Sample fetch": that proves the query runs, this proves
|
|
166
|
+
* the row that comes back actually carries the columns `fields` names. A
|
|
167
|
+
* mapping that points at a column the row lacks produces empty CRM records
|
|
168
|
+
* rather than an error, so it has to be caught here.
|
|
169
|
+
*
|
|
170
|
+
* An empty table SKIPS rather than fails — a fresh database is not a
|
|
171
|
+
* misconfiguration, and failing on it would train people to ignore the check.
|
|
172
|
+
*/
|
|
173
|
+
async function runMappingDryRun(config, entityKey) {
|
|
174
|
+
const name = `Field mapping dry run (${entityKey})`;
|
|
175
|
+
const resolved = resolveEntitySource(config, entityKey);
|
|
176
|
+
if (!resolved) return {
|
|
177
|
+
name,
|
|
178
|
+
ok: false,
|
|
179
|
+
skipped: true,
|
|
180
|
+
detail: `"${entityKey}" resolves to no source — see the coverage check above.`
|
|
181
|
+
};
|
|
182
|
+
const fields = config.entities?.entities?.[entityKey]?.fields ?? {};
|
|
183
|
+
let rows;
|
|
184
|
+
try {
|
|
185
|
+
rows = await resolved.source.fetchPage({
|
|
186
|
+
since: null,
|
|
187
|
+
limit: 1
|
|
188
|
+
});
|
|
189
|
+
} catch (error) {
|
|
190
|
+
return {
|
|
191
|
+
name,
|
|
192
|
+
ok: false,
|
|
193
|
+
detail: describeFetchError(entityKey, error)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const row = rows[0];
|
|
197
|
+
if (row === void 0) return {
|
|
198
|
+
name,
|
|
199
|
+
ok: false,
|
|
200
|
+
skipped: true,
|
|
201
|
+
detail: `"${resolved.source.entity}" is empty — nothing to map yet.`
|
|
202
|
+
};
|
|
203
|
+
const missing = Object.entries(fields).filter(([, column]) => !(column in row)).map(([field, column]) => `${field} → ${column}`);
|
|
204
|
+
return {
|
|
205
|
+
name,
|
|
206
|
+
ok: missing.length === 0,
|
|
207
|
+
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(", ")}.`
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
82
211
|
//#region ../sdk/src/namespace-probe.ts
|
|
83
212
|
/**
|
|
84
213
|
* Verify the tables the integration depends on are genuinely reachable:
|
|
@@ -169,6 +298,11 @@ async function namespaceCheck(config) {
|
|
|
169
298
|
detail: probeResult.reachable ? "All required source tables are reachable." : probeResult.error?.message ?? "namespace unreachable"
|
|
170
299
|
};
|
|
171
300
|
}
|
|
301
|
+
async function mappingDryRunChecks(config) {
|
|
302
|
+
const checks = [];
|
|
303
|
+
for (const entityKey of Object.keys(config.entities?.entities ?? {})) checks.push(await runMappingDryRun(config, entityKey));
|
|
304
|
+
return checks;
|
|
305
|
+
}
|
|
172
306
|
/**
|
|
173
307
|
* Run the read-only setup checks and return a structured report. Every check
|
|
174
308
|
* captures its own error into `detail` rather than throwing, so one failure never
|
|
@@ -195,6 +329,7 @@ async function runDoctor(args) {
|
|
|
195
329
|
ok: sources.length > 0,
|
|
196
330
|
detail: sources.length > 0 ? `${sources.length} source(s) to mirror.` : "No `source.contacts` — nothing to sync."
|
|
197
331
|
});
|
|
332
|
+
checks.push(checkConceptCoverage(config));
|
|
198
333
|
for (const source of sources) {
|
|
199
334
|
const meta = source[DRIZZLE_META];
|
|
200
335
|
if (!meta) {
|
|
@@ -233,6 +368,7 @@ async function runDoctor(args) {
|
|
|
233
368
|
detail: describeFetchError(source.entity, error)
|
|
234
369
|
});
|
|
235
370
|
}
|
|
371
|
+
checks.push(...await mappingDryRunChecks(config));
|
|
236
372
|
const result = await connect();
|
|
237
373
|
checks.push({
|
|
238
374
|
name: "Heartbeat",
|
|
@@ -276,6 +412,7 @@ async function syncSource(args) {
|
|
|
276
412
|
const idField = source.idField ?? DEFAULT_ID_FIELD;
|
|
277
413
|
let cursor = since;
|
|
278
414
|
let pushed = 0;
|
|
415
|
+
const resumedFrom = since === null ? null : since.time.toISOString();
|
|
279
416
|
for (;;) {
|
|
280
417
|
const rows = await source.fetchPage({
|
|
281
418
|
since: cursor,
|
|
@@ -287,6 +424,8 @@ async function syncSource(args) {
|
|
|
287
424
|
source: source.entity,
|
|
288
425
|
rows: capped,
|
|
289
426
|
mode: "delta",
|
|
427
|
+
fetched: rows.length,
|
|
428
|
+
cursor: resumedFrom,
|
|
290
429
|
...objectType ? { objectType } : {}
|
|
291
430
|
})) return {
|
|
292
431
|
pushed,
|
|
@@ -329,6 +468,8 @@ async function fullSyncSource(args) {
|
|
|
329
468
|
source: source.entity,
|
|
330
469
|
rows: all,
|
|
331
470
|
mode: "full",
|
|
471
|
+
fetched: all.length,
|
|
472
|
+
cursor: null,
|
|
332
473
|
...objectType ? { objectType } : {}
|
|
333
474
|
});
|
|
334
475
|
return {
|
|
@@ -393,9 +534,7 @@ function observedTriggerUrl(req) {
|
|
|
393
534
|
const proto = forwardedProto || requestUrl.protocol.replace(":", "");
|
|
394
535
|
try {
|
|
395
536
|
return new URL(`${proto}://${host}${requestUrl.pathname}`).toString();
|
|
396
|
-
} catch {
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
537
|
+
} catch {}
|
|
399
538
|
}
|
|
400
539
|
/**
|
|
401
540
|
* Decide which trigger URL to report, in precedence order:
|
|
@@ -454,7 +593,7 @@ function originAllowed(origin, allowedOrigins) {
|
|
|
454
593
|
if (!origin) return false;
|
|
455
594
|
return allowedOrigins.includes(origin);
|
|
456
595
|
}
|
|
457
|
-
function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API_URL$1, fetchImpl = fetch }) {
|
|
596
|
+
function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API_URL$1, fetchImpl = fetch, resolveUser }) {
|
|
458
597
|
const sessionUrl = `${normalizeApiUrl(apiUrl)}/clivly/widget/session`;
|
|
459
598
|
return async (request) => {
|
|
460
599
|
if (request.method !== "POST") return new Response(JSON.stringify({ error: "method_not_allowed" }), {
|
|
@@ -473,6 +612,12 @@ function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API
|
|
|
473
612
|
return jsonResponse$1({ error: "invalid_json" }, 400);
|
|
474
613
|
}
|
|
475
614
|
if (!isChatSessionRequestBody(body)) return jsonResponse$1({ error: "invalid_request" }, 400);
|
|
615
|
+
let hostUser = null;
|
|
616
|
+
if (resolveUser) try {
|
|
617
|
+
hostUser = await resolveUser(request);
|
|
618
|
+
} catch {
|
|
619
|
+
console.warn("[clivly] resolveUser threw; continuing without host identity");
|
|
620
|
+
}
|
|
476
621
|
try {
|
|
477
622
|
const upstream = await fetchImpl(sessionUrl, {
|
|
478
623
|
method: "POST",
|
|
@@ -485,7 +630,8 @@ function createChatSessionHandler({ allowedOrigins, apiKey, apiUrl = DEFAULT_API
|
|
|
485
630
|
widgetId: body.widgetId,
|
|
486
631
|
visitor: body.visitor,
|
|
487
632
|
visitorToken: body.visitorToken,
|
|
488
|
-
origin
|
|
633
|
+
origin,
|
|
634
|
+
...hostUser ? { hostUser } : {}
|
|
489
635
|
})
|
|
490
636
|
});
|
|
491
637
|
const responseBody = await upstream.text();
|
|
@@ -675,9 +821,7 @@ function connectReason(status) {
|
|
|
675
821
|
async function resolveOrg(response) {
|
|
676
822
|
try {
|
|
677
823
|
return (await response.json())?.org;
|
|
678
|
-
} catch {
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
824
|
+
} catch {}
|
|
681
825
|
}
|
|
682
826
|
function retryAfterMs(res) {
|
|
683
827
|
const header = res.headers.get("retry-after");
|
|
@@ -700,35 +844,30 @@ function createFetcher(retry) {
|
|
|
700
844
|
}
|
|
701
845
|
if (!(res === null || isRetryableStatus(res.status)) || attempt >= maxAttempts) return res;
|
|
702
846
|
const backoff = baseDelayMs * 2 ** (attempt - 1) + Math.random() * baseDelayMs;
|
|
703
|
-
|
|
847
|
+
const wait = res ? retryAfterMs(res) ?? backoff : backoff;
|
|
848
|
+
await sleep(wait);
|
|
704
849
|
}
|
|
705
850
|
};
|
|
706
851
|
}
|
|
852
|
+
const CONCEPT_PATHS = {
|
|
853
|
+
contacts: SYNC_CONTACTS_PATH,
|
|
854
|
+
companies: SYNC_COMPANIES_PATH,
|
|
855
|
+
deals: SYNC_DEALS_PATH,
|
|
856
|
+
custom: SYNC_CUSTOM_PATH
|
|
857
|
+
};
|
|
707
858
|
function resolveSampleSource(config, entityKey) {
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (entity.concept === "deal" && src.deals) return {
|
|
720
|
-
source: src.deals,
|
|
721
|
-
path: SYNC_DEALS_PATH
|
|
859
|
+
const resolved = resolveEntitySource(config, entityKey);
|
|
860
|
+
if (!resolved) return null;
|
|
861
|
+
const path = CONCEPT_PATHS[resolved.expectedKey];
|
|
862
|
+
if (!path) return null;
|
|
863
|
+
return resolved.expectedKey === "custom" ? {
|
|
864
|
+
source: resolved.source,
|
|
865
|
+
path,
|
|
866
|
+
objectType: resolved.source.objectType
|
|
867
|
+
} : {
|
|
868
|
+
source: resolved.source,
|
|
869
|
+
path
|
|
722
870
|
};
|
|
723
|
-
if (entity.concept === "custom") {
|
|
724
|
-
const custom = (src.custom ?? []).find((c) => c.entity === entity.source || c.entity === entityKey);
|
|
725
|
-
return custom ? {
|
|
726
|
-
source: custom,
|
|
727
|
-
path: SYNC_CUSTOM_PATH,
|
|
728
|
-
objectType: custom.objectType
|
|
729
|
-
} : null;
|
|
730
|
-
}
|
|
731
|
-
return null;
|
|
732
871
|
}
|
|
733
872
|
const PREVIEW_LIMIT = 5;
|
|
734
873
|
function resolvePreviewSource(config, sourceTable) {
|
|
@@ -757,7 +896,7 @@ async function handlePreviewRequest(config, preview) {
|
|
|
757
896
|
if (!source) return jsonResponse({ error: `No configured source for table "${preview.sourceTable}"` }, 400);
|
|
758
897
|
const idField = source.idField ?? "id";
|
|
759
898
|
const filterColumns = preview.filter ? Object.keys(preview.filter).filter((k) => k !== "$raw") : [];
|
|
760
|
-
const needed = new Set([
|
|
899
|
+
const needed = /* @__PURE__ */ new Set([
|
|
761
900
|
idField,
|
|
762
901
|
...Object.values(preview.fieldMap),
|
|
763
902
|
...filterColumns
|