@clivly/sdk 0.3.0-next.2 → 0.3.0-next.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.
package/README.md CHANGED
@@ -12,18 +12,18 @@ This README stays focused on the SDK surface itself.
12
12
  ## Install
13
13
 
14
14
  ```bash
15
- npm install @clivly/sdk @clivly/core clivly
15
+ npm install clivly
16
16
  ```
17
17
 
18
- Add `drizzle-orm` when you use `@clivly/sdk/drizzle`, and `vite` when you use
19
- the Vite/TanStack Start plugin.
18
+ Add `drizzle-orm` when you use `clivly/drizzle` or `clivly/core/drizzle`, and
19
+ `vite` when you use the Vite/TanStack Start plugin.
20
20
 
21
21
  ## Usage
22
22
 
23
23
  ```ts
24
- import { createClivlySDK } from "@clivly/sdk";
25
- import { fromDrizzle } from "@clivly/sdk/drizzle";
26
- import { defineClivlyConfig } from "@clivly/core";
24
+ import { createClivlySDK } from "clivly/sdk";
25
+ import { fromDrizzle } from "clivly/drizzle";
26
+ import { defineClivlyConfig } from "clivly/core";
27
27
  import { db, participants, accounts } from "./db";
28
28
 
29
29
  // Declarative entity config — the non-deprecated source of truth. It maps your
@@ -64,9 +64,11 @@ const remote = createClivlySDK({
64
64
  entities,
65
65
  source: { /* … */ },
66
66
  syncTrigger: {
67
- url: "https://yourapp.com/api/clivly/tick",
68
- secret: process.env.CLIVLY_TRIGGER_SECRET, // whsec_… from Integrations → Remote sync
67
+ path: "/api/clivly/tick",
68
+ url: process.env.CLIVLY_SYNC_TRIGGER_URL,
69
+ secret: process.env.CLIVLY_SYNC_TRIGGER_SECRET, // whsec_… from Integrations → Remote sync
69
70
  },
71
+ verifyToken: process.env.CLIVLY_VERIFY_TOKEN,
70
72
  });
71
73
 
72
74
  export async function POST(request: Request) {
@@ -90,8 +92,8 @@ the app but cannot start a sync from the dashboard.
90
92
  If you rotate a remote-sync secret from Clivly's dashboard after the encryption
91
93
  rollout, Clivly stores it encrypted at rest. The server-side deployment must
92
94
  have `CLIVLY_TRIGGER_SECRET_WRAPPING_KEY` configured, while your app continues
93
- to use `CLIVLY_TRIGGER_SECRET` unchanged. Existing plaintext rows remain valid
94
- during rollout, and older rows can be backfilled with
95
+ to use `CLIVLY_SYNC_TRIGGER_SECRET`. Existing plaintext rows remain valid during
96
+ rollout, and older rows can be backfilled with
95
97
  `node ./scripts/backfill-sync-trigger-secrets.mjs --write`.
96
98
 
97
99
  ## Vite / TanStack Start
@@ -99,7 +101,7 @@ during rollout, and older rows can be backfilled with
99
101
  For long-lived Vite dev servers, wire the SDK lifecycle through the Vite plugin:
100
102
 
101
103
  ```ts
102
- import { clivlyVite } from "@clivly/sdk/vite";
104
+ import { clivlyVite } from "clivly/vite";
103
105
  import clivly from "./clivly.config";
104
106
  import { defineConfig } from "vite";
105
107
 
@@ -1,4 +1,4 @@
1
- import { d as SyncSource, t as NamespaceIntrospector } from "./namespace-probe-DIBgCQca.cjs";
1
+ import { d as SyncSource, t as NamespaceIntrospector } from "./namespace-probe-9wTakLJu.cjs";
2
2
  import { Table } from "drizzle-orm";
3
3
 
4
4
  //#region src/drizzle.d.ts
@@ -1,4 +1,4 @@
1
- import { d as SyncSource, t as NamespaceIntrospector } from "./namespace-probe-DFpvfl7T.mjs";
1
+ import { d as SyncSource, t as NamespaceIntrospector } from "./namespace-probe-BD1-lqlp.mjs";
2
2
  import { Table } from "drizzle-orm";
3
3
 
4
4
  //#region src/drizzle.d.ts
package/dist/index.cjs CHANGED
@@ -1,5 +1,42 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_drizzle_meta = require("./drizzle-meta-iAu8w1hj.cjs");
3
+ //#region src/custom-slug.ts
4
+ const NON_ALNUM = /[^a-z0-9]+/g;
5
+ const EDGE_HYPHENS = /(^-|-$)/g;
6
+ function slugify(value) {
7
+ return value.toLowerCase().trim().replace(NON_ALNUM, "-").replace(EDGE_HYPHENS, "");
8
+ }
9
+ function checkCustomObjectSlugs(config) {
10
+ const custom = config.source?.custom ?? [];
11
+ if (custom.length === 0) return {
12
+ name: "Custom object slugs",
13
+ ok: false,
14
+ skipped: true,
15
+ detail: "No custom objects configured."
16
+ };
17
+ const problems = [];
18
+ const seen = /* @__PURE__ */ new Map();
19
+ for (const source of custom) {
20
+ const declared = source.objectType;
21
+ const canonical = slugify(declared);
22
+ if (canonical === "") problems.push(`"${source.entity}" has an empty objectType.`);
23
+ else if (canonical !== declared) problems.push(`"${declared}" is not a slug — the dashboard would store it as "${canonical}".`);
24
+ const prior = seen.get(canonical);
25
+ if (prior && canonical !== "") problems.push(`duplicate slug "${canonical}" declared by "${prior}" and "${source.entity}".`);
26
+ else seen.set(canonical, source.entity);
27
+ }
28
+ if (problems.length > 0) return {
29
+ name: "Custom object slugs",
30
+ ok: false,
31
+ detail: problems.join(" ")
32
+ };
33
+ return {
34
+ name: "Custom object slugs",
35
+ ok: true,
36
+ detail: `Ensure these object types exist in Clivly: ${custom.map((source) => source.objectType).join(", ")}.`
37
+ };
38
+ }
39
+ //#endregion
3
40
  //#region src/namespace-probe.ts
4
41
  /**
5
42
  * Verify the tables the integration depends on are genuinely reachable:
@@ -160,6 +197,7 @@ async function runDoctor(args) {
160
197
  ok: result.ok,
161
198
  detail: result.ok ? `Reached Clivly — org "${result.org?.name ?? "(unnamed)"}".` : `Could not connect (${result.reason}).`
162
199
  });
200
+ checks.push(checkCustomObjectSlugs(config));
163
201
  checks.push(await namespaceCheck(config));
164
202
  return {
165
203
  ok: checks.every((check) => check.skipped || check.ok),
@@ -258,6 +296,85 @@ async function fullSyncSource(args) {
258
296
  };
259
297
  }
260
298
  //#endregion
299
+ //#region src/trigger-url.ts
300
+ const SCHEME_REGEX = /^https?:\/\//;
301
+ const INVALID_HOST_CHARS_REGEX = /[/\\@?#\s]/;
302
+ const PLATFORM_ORIGIN_SOURCES = [
303
+ {
304
+ key: "VERCEL_URL",
305
+ toOrigin: (value) => withScheme(value)
306
+ },
307
+ {
308
+ key: "CF_PAGES_URL",
309
+ toOrigin: (value) => withScheme(value)
310
+ },
311
+ {
312
+ key: "RAILWAY_PUBLIC_DOMAIN",
313
+ toOrigin: (value) => withScheme(value)
314
+ },
315
+ {
316
+ key: "RENDER_EXTERNAL_URL",
317
+ toOrigin: (value) => withScheme(value)
318
+ },
319
+ {
320
+ key: "FLY_APP_NAME",
321
+ toOrigin: (value) => `https://${value}.fly.dev`
322
+ }
323
+ ];
324
+ function withScheme(value) {
325
+ return SCHEME_REGEX.test(value) ? value : `https://${value}`;
326
+ }
327
+ function stripTrailingSlash(value) {
328
+ return value.endsWith("/") ? value.slice(0, -1) : value;
329
+ }
330
+ /**
331
+ * Derive the app's public origin from known platform environment variables.
332
+ * Returns an origin with no trailing slash, or undefined when nothing matches.
333
+ */
334
+ function originFromPlatformEnv(env) {
335
+ for (const source of PLATFORM_ORIGIN_SOURCES) {
336
+ const raw = env[source.key]?.trim();
337
+ if (raw) return stripTrailingSlash(source.toOrigin(raw));
338
+ }
339
+ }
340
+ function observedTriggerUrl(req) {
341
+ const host = (req.headers.get("x-forwarded-host") ?? req.headers.get("host"))?.trim();
342
+ if (!host) return;
343
+ if (INVALID_HOST_CHARS_REGEX.test(host)) return;
344
+ const forwardedProto = req.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
345
+ let requestUrl;
346
+ try {
347
+ requestUrl = new URL(req.url);
348
+ } catch {
349
+ return;
350
+ }
351
+ const proto = forwardedProto || requestUrl.protocol.replace(":", "");
352
+ try {
353
+ return new URL(`${proto}://${host}${requestUrl.pathname}`).toString();
354
+ } catch {
355
+ return;
356
+ }
357
+ }
358
+ /**
359
+ * Decide which trigger URL to report, in precedence order:
360
+ *
361
+ * 1. `configuredUrl` — an explicit `syncTrigger.url`. Someone typed this on
362
+ * purpose, so it beats anything inferred.
363
+ * 2. platform env origin + `configuredPath` — available at boot, before any
364
+ * request has arrived. Needs the path because platform variables only give
365
+ * an origin.
366
+ * 3. `observedUrl` — accurate but only after the route has served a request.
367
+ *
368
+ * A URL set in the Clivly dashboard overrides all of these server-side; the SDK
369
+ * doesn't need to know about it.
370
+ */
371
+ function resolveTriggerUrl(args) {
372
+ if (args.configuredUrl) return args.configuredUrl;
373
+ const origin = originFromPlatformEnv(args.env);
374
+ if (origin && args.configuredPath) return `${origin}${args.configuredPath.startsWith("/") ? args.configuredPath : `/${args.configuredPath}`}`;
375
+ return args.observedUrl;
376
+ }
377
+ //#endregion
261
378
  //#region src/errors.ts
262
379
  var ClivlyError = class ClivlyError extends Error {
263
380
  /** HTTP status, or null when the request never completed (network error). */
@@ -548,6 +665,7 @@ function createClivlySDK(config) {
548
665
  const cursorStore = config.cursorStore ?? createMemoryCursorStore();
549
666
  const fetcher = createFetcher(config.retry);
550
667
  let warnedUnsignedTrigger = false;
668
+ let observedUrl;
551
669
  let lastPushFailure = null;
552
670
  const createPush = (runId) => async (path, body) => {
553
671
  const response = await fetcher(`${apiUrl}${path}`, {
@@ -632,7 +750,15 @@ function createClivlySDK(config) {
632
750
  contactEntity: resolveContactEntity(config),
633
751
  namespaceReady: config.namespaceReady ?? false,
634
752
  schema: buildSchema(config),
635
- ...config.syncTrigger?.url ? { syncTrigger: { url: config.syncTrigger.url } } : {}
753
+ ...(() => {
754
+ const url = resolveTriggerUrl({
755
+ configuredUrl: config.syncTrigger?.url,
756
+ configuredPath: config.syncTrigger?.path,
757
+ env: config.env ?? process.env,
758
+ observedUrl
759
+ });
760
+ return url ? { syncTrigger: { url } } : {};
761
+ })()
636
762
  })
637
763
  });
638
764
  const heartbeat = async () => {
@@ -686,6 +812,7 @@ function createClivlySDK(config) {
686
812
  }
687
813
  };
688
814
  const createClivlyHandler = () => async (req) => {
815
+ observedUrl = observedTriggerUrl(req) ?? observedUrl;
689
816
  const rawBody = await req.text().catch(() => "");
690
817
  if (!await triggerRequestAllowed(req, rawBody)) return jsonResponse({
691
818
  ok: false,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ClivlySDKConfig, c as DiscoveredTable, i as ClivlySDK, l as DoctorCheck, n as ClivlyConnectReason, o as ClivlyUser, r as ClivlyConnectResult, s as CursorStore, u as DoctorReport } from "./namespace-probe-DIBgCQca.cjs";
1
+ import { a as ClivlySDKConfig, c as DiscoveredTable, i as ClivlySDK, l as DoctorCheck, n as ClivlyConnectReason, o as ClivlyUser, r as ClivlyConnectResult, s as CursorStore, u as DoctorReport } from "./namespace-probe-9wTakLJu.cjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
4
  declare class ClivlyError extends Error {
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ClivlySDKConfig, c as DiscoveredTable, i as ClivlySDK, l as DoctorCheck, n as ClivlyConnectReason, o as ClivlyUser, r as ClivlyConnectResult, s as CursorStore, u as DoctorReport } from "./namespace-probe-DFpvfl7T.mjs";
1
+ import { a as ClivlySDKConfig, c as DiscoveredTable, i as ClivlySDK, l as DoctorCheck, n as ClivlyConnectReason, o as ClivlyUser, r as ClivlyConnectResult, s as CursorStore, u as DoctorReport } from "./namespace-probe-BD1-lqlp.mjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
4
  declare class ClivlyError extends Error {
package/dist/index.mjs CHANGED
@@ -1,4 +1,41 @@
1
1
  import { t as DRIZZLE_META } from "./drizzle-meta-DMx_9nlj.mjs";
2
+ //#region src/custom-slug.ts
3
+ const NON_ALNUM = /[^a-z0-9]+/g;
4
+ const EDGE_HYPHENS = /(^-|-$)/g;
5
+ function slugify(value) {
6
+ return value.toLowerCase().trim().replace(NON_ALNUM, "-").replace(EDGE_HYPHENS, "");
7
+ }
8
+ function checkCustomObjectSlugs(config) {
9
+ const custom = config.source?.custom ?? [];
10
+ if (custom.length === 0) return {
11
+ name: "Custom object slugs",
12
+ ok: false,
13
+ skipped: true,
14
+ detail: "No custom objects configured."
15
+ };
16
+ const problems = [];
17
+ const seen = /* @__PURE__ */ new Map();
18
+ for (const source of custom) {
19
+ const declared = source.objectType;
20
+ const canonical = slugify(declared);
21
+ if (canonical === "") problems.push(`"${source.entity}" has an empty objectType.`);
22
+ else if (canonical !== declared) problems.push(`"${declared}" is not a slug — the dashboard would store it as "${canonical}".`);
23
+ const prior = seen.get(canonical);
24
+ if (prior && canonical !== "") problems.push(`duplicate slug "${canonical}" declared by "${prior}" and "${source.entity}".`);
25
+ else seen.set(canonical, source.entity);
26
+ }
27
+ if (problems.length > 0) return {
28
+ name: "Custom object slugs",
29
+ ok: false,
30
+ detail: problems.join(" ")
31
+ };
32
+ return {
33
+ name: "Custom object slugs",
34
+ ok: true,
35
+ detail: `Ensure these object types exist in Clivly: ${custom.map((source) => source.objectType).join(", ")}.`
36
+ };
37
+ }
38
+ //#endregion
2
39
  //#region src/namespace-probe.ts
3
40
  /**
4
41
  * Verify the tables the integration depends on are genuinely reachable:
@@ -159,6 +196,7 @@ async function runDoctor(args) {
159
196
  ok: result.ok,
160
197
  detail: result.ok ? `Reached Clivly — org "${result.org?.name ?? "(unnamed)"}".` : `Could not connect (${result.reason}).`
161
198
  });
199
+ checks.push(checkCustomObjectSlugs(config));
162
200
  checks.push(await namespaceCheck(config));
163
201
  return {
164
202
  ok: checks.every((check) => check.skipped || check.ok),
@@ -257,6 +295,85 @@ async function fullSyncSource(args) {
257
295
  };
258
296
  }
259
297
  //#endregion
298
+ //#region src/trigger-url.ts
299
+ const SCHEME_REGEX = /^https?:\/\//;
300
+ const INVALID_HOST_CHARS_REGEX = /[/\\@?#\s]/;
301
+ const PLATFORM_ORIGIN_SOURCES = [
302
+ {
303
+ key: "VERCEL_URL",
304
+ toOrigin: (value) => withScheme(value)
305
+ },
306
+ {
307
+ key: "CF_PAGES_URL",
308
+ toOrigin: (value) => withScheme(value)
309
+ },
310
+ {
311
+ key: "RAILWAY_PUBLIC_DOMAIN",
312
+ toOrigin: (value) => withScheme(value)
313
+ },
314
+ {
315
+ key: "RENDER_EXTERNAL_URL",
316
+ toOrigin: (value) => withScheme(value)
317
+ },
318
+ {
319
+ key: "FLY_APP_NAME",
320
+ toOrigin: (value) => `https://${value}.fly.dev`
321
+ }
322
+ ];
323
+ function withScheme(value) {
324
+ return SCHEME_REGEX.test(value) ? value : `https://${value}`;
325
+ }
326
+ function stripTrailingSlash(value) {
327
+ return value.endsWith("/") ? value.slice(0, -1) : value;
328
+ }
329
+ /**
330
+ * Derive the app's public origin from known platform environment variables.
331
+ * Returns an origin with no trailing slash, or undefined when nothing matches.
332
+ */
333
+ function originFromPlatformEnv(env) {
334
+ for (const source of PLATFORM_ORIGIN_SOURCES) {
335
+ const raw = env[source.key]?.trim();
336
+ if (raw) return stripTrailingSlash(source.toOrigin(raw));
337
+ }
338
+ }
339
+ function observedTriggerUrl(req) {
340
+ const host = (req.headers.get("x-forwarded-host") ?? req.headers.get("host"))?.trim();
341
+ if (!host) return;
342
+ if (INVALID_HOST_CHARS_REGEX.test(host)) return;
343
+ const forwardedProto = req.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
344
+ let requestUrl;
345
+ try {
346
+ requestUrl = new URL(req.url);
347
+ } catch {
348
+ return;
349
+ }
350
+ const proto = forwardedProto || requestUrl.protocol.replace(":", "");
351
+ try {
352
+ return new URL(`${proto}://${host}${requestUrl.pathname}`).toString();
353
+ } catch {
354
+ return;
355
+ }
356
+ }
357
+ /**
358
+ * Decide which trigger URL to report, in precedence order:
359
+ *
360
+ * 1. `configuredUrl` — an explicit `syncTrigger.url`. Someone typed this on
361
+ * purpose, so it beats anything inferred.
362
+ * 2. platform env origin + `configuredPath` — available at boot, before any
363
+ * request has arrived. Needs the path because platform variables only give
364
+ * an origin.
365
+ * 3. `observedUrl` — accurate but only after the route has served a request.
366
+ *
367
+ * A URL set in the Clivly dashboard overrides all of these server-side; the SDK
368
+ * doesn't need to know about it.
369
+ */
370
+ function resolveTriggerUrl(args) {
371
+ if (args.configuredUrl) return args.configuredUrl;
372
+ const origin = originFromPlatformEnv(args.env);
373
+ if (origin && args.configuredPath) return `${origin}${args.configuredPath.startsWith("/") ? args.configuredPath : `/${args.configuredPath}`}`;
374
+ return args.observedUrl;
375
+ }
376
+ //#endregion
260
377
  //#region src/errors.ts
261
378
  var ClivlyError = class ClivlyError extends Error {
262
379
  /** HTTP status, or null when the request never completed (network error). */
@@ -547,6 +664,7 @@ function createClivlySDK(config) {
547
664
  const cursorStore = config.cursorStore ?? createMemoryCursorStore();
548
665
  const fetcher = createFetcher(config.retry);
549
666
  let warnedUnsignedTrigger = false;
667
+ let observedUrl;
550
668
  let lastPushFailure = null;
551
669
  const createPush = (runId) => async (path, body) => {
552
670
  const response = await fetcher(`${apiUrl}${path}`, {
@@ -631,7 +749,15 @@ function createClivlySDK(config) {
631
749
  contactEntity: resolveContactEntity(config),
632
750
  namespaceReady: config.namespaceReady ?? false,
633
751
  schema: buildSchema(config),
634
- ...config.syncTrigger?.url ? { syncTrigger: { url: config.syncTrigger.url } } : {}
752
+ ...(() => {
753
+ const url = resolveTriggerUrl({
754
+ configuredUrl: config.syncTrigger?.url,
755
+ configuredPath: config.syncTrigger?.path,
756
+ env: config.env ?? process.env,
757
+ observedUrl
758
+ });
759
+ return url ? { syncTrigger: { url } } : {};
760
+ })()
635
761
  })
636
762
  });
637
763
  const heartbeat = async () => {
@@ -685,6 +811,7 @@ function createClivlySDK(config) {
685
811
  }
686
812
  };
687
813
  const createClivlyHandler = () => async (req) => {
814
+ observedUrl = observedTriggerUrl(req) ?? observedUrl;
688
815
  const rawBody = await req.text().catch(() => "");
689
816
  if (!await triggerRequestAllowed(req, rawBody)) return jsonResponse({
690
817
  ok: false,
@@ -64,6 +64,12 @@ interface ClivlySDKConfig {
64
64
  * `contactEntity`.
65
65
  */
66
66
  entities?: ClivlyEntitiesConfig;
67
+ /**
68
+ * Environment to read platform variables from when discovering the public
69
+ * trigger URL. Defaults to `process.env`. Injectable so tests and non-Node
70
+ * runtimes can supply their own.
71
+ */
72
+ env?: Record<string, string | undefined>;
67
73
  /**
68
74
  * 🚧 Not implemented in 0.1.x. Reserved options for tunnel mode and CRM
69
75
  * write-back — they have NO effect yet and land with the Cloudflare
@@ -140,8 +146,19 @@ interface ClivlySDKConfig {
140
146
  * Public URL of the route where `createClivlyHandler()` is mounted, e.g.
141
147
  * `https://app.example.com/api/clivly/tick`. Reported to Clivly on each
142
148
  * heartbeat; a URL set in the dashboard overrides it.
149
+ *
150
+ * Optional — leave it unset and the SDK discovers the URL itself, from the
151
+ * hosting platform's environment or from the first request the route
152
+ * serves. Set it only to pin an address the SDK can't infer.
143
153
  */
144
154
  url?: string;
155
+ /**
156
+ * Path where `createClivlyHandler()` is mounted, e.g. `/api/clivly/tick`.
157
+ * Written by `clivly init`. Combined with the origin detected from the
158
+ * hosting platform so the SDK can report a trigger URL on its very first
159
+ * heartbeat, before any request has arrived to observe.
160
+ */
161
+ path?: string;
145
162
  /**
146
163
  * Signing secret (`whsec_…`) issued by Clivly under Integrations → Remote
147
164
  * sync. When set, `createClivlyHandler()` rejects any request that isn't
@@ -64,6 +64,12 @@ interface ClivlySDKConfig {
64
64
  * `contactEntity`.
65
65
  */
66
66
  entities?: ClivlyEntitiesConfig;
67
+ /**
68
+ * Environment to read platform variables from when discovering the public
69
+ * trigger URL. Defaults to `process.env`. Injectable so tests and non-Node
70
+ * runtimes can supply their own.
71
+ */
72
+ env?: Record<string, string | undefined>;
67
73
  /**
68
74
  * 🚧 Not implemented in 0.1.x. Reserved options for tunnel mode and CRM
69
75
  * write-back — they have NO effect yet and land with the Cloudflare
@@ -140,8 +146,19 @@ interface ClivlySDKConfig {
140
146
  * Public URL of the route where `createClivlyHandler()` is mounted, e.g.
141
147
  * `https://app.example.com/api/clivly/tick`. Reported to Clivly on each
142
148
  * heartbeat; a URL set in the dashboard overrides it.
149
+ *
150
+ * Optional — leave it unset and the SDK discovers the URL itself, from the
151
+ * hosting platform's environment or from the first request the route
152
+ * serves. Set it only to pin an address the SDK can't infer.
143
153
  */
144
154
  url?: string;
155
+ /**
156
+ * Path where `createClivlyHandler()` is mounted, e.g. `/api/clivly/tick`.
157
+ * Written by `clivly init`. Combined with the origin detected from the
158
+ * hosting platform so the SDK can report a trigger URL on its very first
159
+ * heartbeat, before any request has arrived to observe.
160
+ */
161
+ path?: string;
145
162
  /**
146
163
  * Signing secret (`whsec_…`) issued by Clivly under Integrations → Remote
147
164
  * sync. When set, `createClivlyHandler()` rejects any request that isn't
package/dist/vite.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ClivlySDK } from "./namespace-probe-DIBgCQca.cjs";
1
+ import { i as ClivlySDK } from "./namespace-probe-9wTakLJu.cjs";
2
2
  import { Plugin } from "vite";
3
3
 
4
4
  //#region src/vite.d.ts
package/dist/vite.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ClivlySDK } from "./namespace-probe-DFpvfl7T.mjs";
1
+ import { i as ClivlySDK } from "./namespace-probe-BD1-lqlp.mjs";
2
2
  import { Plugin } from "vite";
3
3
 
4
4
  //#region src/vite.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clivly/sdk",
3
- "version": "0.3.0-next.2",
3
+ "version": "0.3.0-next.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Clivly SDK — connect your app to Clivly Cloud (heartbeat, discovery, auth bridge).",
@@ -45,7 +45,7 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@clivly/core": "0.3.0-next.2"
48
+ "@clivly/core": "0.3.0-next.4"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "drizzle-orm": ">=0.30",