deepline 0.3.87 → 0.3.88
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/dist/bundling-sources/sdk/src/client.ts +2 -2
- package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +1 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/monitors/org-monitor-limits.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +0 -6
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +0 -302
- package/dist/bundling-sources/shared_libs/plays/email-status.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +2 -2
- package/dist/bundling-sources/shared_libs/runtime-env.ts +0 -6
- package/dist/cli/index.js +4 -6
- package/dist/cli/index.mjs +4 -6
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/dist/install-integrity.json +2 -45
- package/package.json +1 -3
- package/dist/bundling-sources/shared_libs/integration-contracts/AGENTS.md +0 -9
- package/dist/bundling-sources/shared_libs/integration-contracts/README.md +0 -3
- package/dist/bundling-sources/shared_libs/integration-contracts/index.ts +0 -2
- package/dist/bundling-sources/shared_libs/monitors/analytics-install-guides.ts +0 -77
- package/dist/bundling-sources/shared_libs/monitors/billing/charges.ts +0 -125
- package/dist/bundling-sources/shared_libs/monitors/billing/policy-builders.ts +0 -686
- package/dist/bundling-sources/shared_libs/monitors/billing/pricing.ts +0 -54
- package/dist/bundling-sources/shared_libs/monitors/billing/public-pricing.ts +0 -72
- package/dist/bundling-sources/shared_libs/monitors/billing/session.ts +0 -45
- package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +0 -454
- package/dist/bundling-sources/shared_libs/monitors/billing/tamradar.ts +0 -260
- package/dist/bundling-sources/shared_libs/monitors/billing/types.ts +0 -215
- package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +0 -333
- package/dist/bundling-sources/shared_libs/monitors/cursor-page.ts +0 -42
- package/dist/bundling-sources/shared_libs/monitors/framework-managed-payload-fields.ts +0 -71
- package/dist/bundling-sources/shared_libs/monitors/generated/provider-monitor-callback-admission-targets.ts +0 -16
- package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +0 -267
- package/dist/bundling-sources/shared_libs/monitors/inbound-publish-key.ts +0 -39
- package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +0 -82
- package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +0 -473
- package/dist/bundling-sources/shared_libs/monitors/package.json +0 -29
- package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +0 -1125
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-capability.ts +0 -964
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +0 -56
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-errors.ts +0 -131
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +0 -527
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-legacy-aliases.ts +0 -16
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-priority-execution.ts +0 -56
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +0 -28
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-runtime-read-eligibility.ts +0 -38
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-status.ts +0 -10
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +0 -112
- package/dist/bundling-sources/shared_libs/monitors/provider-webhook-monitor-runtime.ts +0 -300
- package/dist/bundling-sources/shared_libs/monitors/quickstart-prompts.ts +0 -22
- package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +0 -93
- package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +0 -332
- package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +0 -221
- package/dist/bundling-sources/shared_libs/monitors/starter-templates.ts +0 -105
- package/dist/bundling-sources/shared_libs/monitors/tracking-provider-guidance.ts +0 -73
- package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +0 -81
- package/dist/bundling-sources/shared_libs/monitors/tsconfig.json +0 -10
- package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +0 -28
- package/dist/bundling-sources/shared_libs/security/secret-redaction.ts +0 -267
- /package/dist/bundling-sources/shared_libs/{integration-contracts/bettercontact/execution-policy.ts → integrations/bettercontact-execution-policy.ts} +0 -0
- /package/dist/bundling-sources/shared_libs/{integration-contracts/theirstack/execution-policy.ts → integrations/theirstack-execution-policy.ts} +0 -0
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const LEGACY_STORED_PROVIDER_MONITOR_CAPABILITY_ALIASES: Readonly<
|
|
2
|
-
Record<string, string>
|
|
3
|
-
> = {
|
|
4
|
-
'tamradar.company_radar': 'deepline_native.company_radar',
|
|
5
|
-
'tamradar.contact_radar': 'deepline_native.contact_radar',
|
|
6
|
-
'tamradar.industry_radar': 'deepline_native.industry_radar',
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export function canonicalizeStoredProviderMonitorCapabilityId(
|
|
10
|
-
providerCapability: string,
|
|
11
|
-
): string {
|
|
12
|
-
return (
|
|
13
|
-
LEGACY_STORED_PROVIDER_MONITOR_CAPABILITY_ALIASES[providerCapability] ??
|
|
14
|
-
providerCapability
|
|
15
|
-
);
|
|
16
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { ProviderMonitorCapabilityDefinition } from '@deepline/monitors/provider-monitor-capability';
|
|
2
|
-
import type { ProviderMonitorStatus } from './provider-monitor-status';
|
|
3
|
-
|
|
4
|
-
export const PRIORITY_MONITOR_EXECUTION_TYPE = 'priority' as const;
|
|
5
|
-
export const MAX_PRIORITY_MONITORS_PER_ORG = 10;
|
|
6
|
-
|
|
7
|
-
export const PRIORITY_MONITOR_SLOT_STATUSES = [
|
|
8
|
-
'active',
|
|
9
|
-
// A billing suspension writes disabled before upstream deprovisioning. Keep
|
|
10
|
-
// the slot occupied until that delete confirms success and clears the
|
|
11
|
-
// projection; a failed cleanup can leave the priority radar live.
|
|
12
|
-
'disabled',
|
|
13
|
-
'deleting',
|
|
14
|
-
'error',
|
|
15
|
-
'deleted',
|
|
16
|
-
// A fleet monitor holds its priority reservation from the commit that
|
|
17
|
-
// records the desired state, not from the provider create that follows it.
|
|
18
|
-
'pending_create',
|
|
19
|
-
] as const satisfies readonly ProviderMonitorStatus[];
|
|
20
|
-
|
|
21
|
-
const PRIORITY_MONITOR_SLOT_STATUS_SET = new Set<ProviderMonitorStatus>(
|
|
22
|
-
PRIORITY_MONITOR_SLOT_STATUSES,
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
export function requestedPriorityMonitorExecution(definition: {
|
|
26
|
-
controls?: Record<string, unknown>;
|
|
27
|
-
}) {
|
|
28
|
-
return (
|
|
29
|
-
definition.controls?.execution_type === PRIORITY_MONITOR_EXECUTION_TYPE
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function priorityMonitorExecutionIsSupported(
|
|
34
|
-
capability: ProviderMonitorCapabilityDefinition,
|
|
35
|
-
) {
|
|
36
|
-
return capability.provider === 'deepline_native';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function priorityMonitorConsumesSlot(input: {
|
|
40
|
-
priorityExecution: boolean;
|
|
41
|
-
status: ProviderMonitorStatus;
|
|
42
|
-
}) {
|
|
43
|
-
return (
|
|
44
|
-
input.priorityExecution &&
|
|
45
|
-
PRIORITY_MONITOR_SLOT_STATUS_SET.has(input.status)
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function priorityMonitorReservedSlotCount(input: {
|
|
50
|
-
priorityExecution: boolean;
|
|
51
|
-
status: ProviderMonitorStatus;
|
|
52
|
-
priorityExecutionSlots?: number;
|
|
53
|
-
}) {
|
|
54
|
-
if (!priorityMonitorConsumesSlot(input)) return 0;
|
|
55
|
-
return input.priorityExecutionSlots === 2 ? 2 : 1;
|
|
56
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ANALYTICS_INTEGRATION_SLUG,
|
|
3
|
-
ANALYTICS_PUBLIC_PROVIDER,
|
|
4
|
-
ANALYTICS_PUBLIC_TOOL,
|
|
5
|
-
} from '@/lib/analytics/public';
|
|
6
|
-
|
|
7
|
-
export const ANALYTICS_MONITOR_KEY = ANALYTICS_INTEGRATION_SLUG;
|
|
8
|
-
export const ANALYTICS_INTERNAL_MONITOR_KEY = 'snitcher-website-sessions';
|
|
9
|
-
export const ANALYTICS_INTERNAL_TOOL = 'snitcher.website_sessions';
|
|
10
|
-
|
|
11
|
-
export function canonicalProviderMonitorKey(key: string) {
|
|
12
|
-
return key === ANALYTICS_MONITOR_KEY ? ANALYTICS_INTERNAL_MONITOR_KEY : key;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** Convert a customer-facing monitor tool id to its internal registry id. */
|
|
16
|
-
export function canonicalProviderMonitorTool(tool: string) {
|
|
17
|
-
return tool === ANALYTICS_PUBLIC_TOOL ? ANALYTICS_INTERNAL_TOOL : tool;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Convert an internal registry id to the stable customer-facing tool id. */
|
|
21
|
-
export function publicProviderMonitorTool(tool: string) {
|
|
22
|
-
return tool === ANALYTICS_INTERNAL_TOOL ? ANALYTICS_PUBLIC_TOOL : tool;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Convert an internal provider name to the stable customer-facing name. */
|
|
26
|
-
export function publicProviderMonitorProvider(provider: string) {
|
|
27
|
-
return provider === 'snitcher' ? ANALYTICS_PUBLIC_PROVIDER : provider;
|
|
28
|
-
}
|
package/dist/bundling-sources/shared_libs/monitors/provider-monitor-runtime-read-eligibility.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
type ProviderMonitorCallbackRuntimeRow = {
|
|
2
|
-
status: string;
|
|
3
|
-
billing_state: unknown;
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
function billingStateKind(value: unknown) {
|
|
7
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
8
|
-
const state = (value as Record<string, unknown>).state;
|
|
9
|
-
return typeof state === 'string' && state.trim() ? state.trim() : null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/** True when an admitted callback is allowed to write an event for this monitor. */
|
|
13
|
-
export function isProviderMonitorCallbackWriteEnabled(
|
|
14
|
-
row: Pick<ProviderMonitorCallbackRuntimeRow, 'status'>,
|
|
15
|
-
) {
|
|
16
|
-
return row.status === 'active';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Matches the Customer DB callback lookup predicate for a row that has already
|
|
21
|
-
* been selected from the Convex callback-token projection.
|
|
22
|
-
*/
|
|
23
|
-
export function isProviderMonitorCallbackRuntimeEligible(
|
|
24
|
-
row: ProviderMonitorCallbackRuntimeRow,
|
|
25
|
-
) {
|
|
26
|
-
if (isProviderMonitorCallbackWriteEnabled(row)) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
return (
|
|
30
|
-
row.status === 'disabled' &&
|
|
31
|
-
(billingStateKind(row.billing_state) === 'upstream_disable_pending' ||
|
|
32
|
-
billingStateKind(row.billing_state) === 'upstream_disable_failed' ||
|
|
33
|
-
// A credit suspension turns the provider resource off but does not turn
|
|
34
|
-
// off receipt capture. The inbound processor stores raw provenance and
|
|
35
|
-
// returns its explicit billing-suspended outcome without typed writes.
|
|
36
|
-
billingStateKind(row.billing_state) === 'billing_suspended')
|
|
37
|
-
);
|
|
38
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
// Convex-safe provider monitor identity contract.
|
|
2
|
-
//
|
|
3
|
-
// This deliberately contains only declarative identity metadata and pure
|
|
4
|
-
// normalization. Convex claim mutations import it directly, so it must not
|
|
5
|
-
// pull in the Node-only provider registry, generated OpenAPI loaders, or any
|
|
6
|
-
// deployment runtime. A monitor provider adds its account-unique identity here
|
|
7
|
-
// and declares the same fields on its capability; registry validation keeps the
|
|
8
|
-
// two declarations aligned.
|
|
9
|
-
|
|
10
|
-
export type ProviderMonitorUpstreamIdentityValue = string | null;
|
|
11
|
-
|
|
12
|
-
export type ProviderMonitorUpstreamIdentitySignature = {
|
|
13
|
-
tool: string;
|
|
14
|
-
key: Record<string, ProviderMonitorUpstreamIdentityValue>;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type ProviderMonitorUpstreamIdentityField = {
|
|
18
|
-
name: string;
|
|
19
|
-
// A provider runtime payload can use its upstream request name while the
|
|
20
|
-
// public monitor definition uses a clearer field name. Identity backfills
|
|
21
|
-
// use this declarative alias rather than provider-specific conditionals.
|
|
22
|
-
runtimePayloadAliases?: readonly string[];
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const PROVIDER_MONITOR_UPSTREAM_IDENTITY_FIELDS = {
|
|
26
|
-
'deepline_native.company_radar': [{ name: 'radar_type' }, { name: 'domain' }],
|
|
27
|
-
'deepline_native.contact_radar': [
|
|
28
|
-
{ name: 'radar_type' },
|
|
29
|
-
{ name: 'profile_url' },
|
|
30
|
-
],
|
|
31
|
-
'deepline_native.industry_radar': [
|
|
32
|
-
{ name: 'radar_type' },
|
|
33
|
-
{ name: 'industry', runtimePayloadAliases: ['keyword'] },
|
|
34
|
-
],
|
|
35
|
-
} as const satisfies Record<
|
|
36
|
-
string,
|
|
37
|
-
readonly ProviderMonitorUpstreamIdentityField[]
|
|
38
|
-
>;
|
|
39
|
-
|
|
40
|
-
function canonicalMonitorTool(tool: string) {
|
|
41
|
-
// Public TamRadar ids existed before the deepline_native hard cutover. Keep
|
|
42
|
-
// their legacy control records in the same claim namespace during migration.
|
|
43
|
-
return tool.startsWith('tamradar.')
|
|
44
|
-
? `deepline_native.${tool.slice('tamradar.'.length)}`
|
|
45
|
-
: tool;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function stableJson(value: unknown): string {
|
|
49
|
-
if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`;
|
|
50
|
-
if (value && typeof value === 'object') {
|
|
51
|
-
const entries = Object.entries(value as Record<string, unknown>)
|
|
52
|
-
.filter(([, entry]) => entry !== undefined)
|
|
53
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
54
|
-
.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`);
|
|
55
|
-
return `{${entries.join(',')}}`;
|
|
56
|
-
}
|
|
57
|
-
return JSON.stringify(value) ?? 'null';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function normalizeProviderMonitorUpstreamIdentityValue(
|
|
61
|
-
value: unknown,
|
|
62
|
-
): ProviderMonitorUpstreamIdentityValue {
|
|
63
|
-
if (value === null || value === undefined) return null;
|
|
64
|
-
if (typeof value === 'string') {
|
|
65
|
-
const normalized = value.trim().toLowerCase();
|
|
66
|
-
return normalized || null;
|
|
67
|
-
}
|
|
68
|
-
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
69
|
-
return String(value);
|
|
70
|
-
}
|
|
71
|
-
if (Array.isArray(value)) {
|
|
72
|
-
const normalized = value
|
|
73
|
-
.map(normalizeProviderMonitorUpstreamIdentityValue)
|
|
74
|
-
.filter((entry): entry is string => entry !== null)
|
|
75
|
-
.sort();
|
|
76
|
-
return normalized.length ? normalized.join(',') : null;
|
|
77
|
-
}
|
|
78
|
-
return stableJson(value).toLowerCase();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function providerMonitorUpstreamIdentityFields(tool: string) {
|
|
82
|
-
const canonical = canonicalMonitorTool(tool);
|
|
83
|
-
return PROVIDER_MONITOR_UPSTREAM_IDENTITY_FIELDS[
|
|
84
|
-
canonical as keyof typeof PROVIDER_MONITOR_UPSTREAM_IDENTITY_FIELDS
|
|
85
|
-
]?.map((field) => field.name);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function providerMonitorUpstreamIdentitySignature(
|
|
89
|
-
tool: string,
|
|
90
|
-
payload: Record<string, unknown> | null | undefined,
|
|
91
|
-
): ProviderMonitorUpstreamIdentitySignature | null {
|
|
92
|
-
const canonical = canonicalMonitorTool(tool);
|
|
93
|
-
const fields =
|
|
94
|
-
PROVIDER_MONITOR_UPSTREAM_IDENTITY_FIELDS[
|
|
95
|
-
canonical as keyof typeof PROVIDER_MONITOR_UPSTREAM_IDENTITY_FIELDS
|
|
96
|
-
];
|
|
97
|
-
if (!fields?.length) return null;
|
|
98
|
-
const key: Record<string, ProviderMonitorUpstreamIdentityValue> = {};
|
|
99
|
-
for (const field of fields) {
|
|
100
|
-
const aliases =
|
|
101
|
-
'runtimePayloadAliases' in field
|
|
102
|
-
? field.runtimePayloadAliases
|
|
103
|
-
: undefined;
|
|
104
|
-
const value =
|
|
105
|
-
payload?.[field.name] ??
|
|
106
|
-
aliases
|
|
107
|
-
?.map((alias) => payload?.[alias])
|
|
108
|
-
.find((aliasValue) => aliasValue !== undefined);
|
|
109
|
-
key[field.name] = normalizeProviderMonitorUpstreamIdentityValue(value);
|
|
110
|
-
}
|
|
111
|
-
return { tool: canonical, key };
|
|
112
|
-
}
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import type { ProviderMonitorCapabilityDefinition } from '@deepline/monitors/provider-monitor-capability';
|
|
4
|
-
import {
|
|
5
|
-
createProviderCallbackSecret,
|
|
6
|
-
MONITOR_CALLBACK_SECRET_HEADER,
|
|
7
|
-
} from '@deepline/monitors/provider-callback-verification';
|
|
8
|
-
|
|
9
|
-
type ProviderMonitorDefinitionLike = {
|
|
10
|
-
key: string;
|
|
11
|
-
name?: string;
|
|
12
|
-
payload?: Record<string, unknown>;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const DEFAULT_MONITOR_CALLBACK_BASE_URL = 'http://localhost:3000';
|
|
16
|
-
const DEFAULT_PREVIEW_CALLBACK_URL_FILE =
|
|
17
|
-
'.cache/dev/plays-preview-callback-url';
|
|
18
|
-
|
|
19
|
-
function readRecord(value: unknown): Record<string, unknown> {
|
|
20
|
-
return value && typeof value === 'object' && !Array.isArray(value)
|
|
21
|
-
? (value as Record<string, unknown>)
|
|
22
|
-
: {};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function readString(value: unknown) {
|
|
26
|
-
if (typeof value === 'number' && Number.isFinite(value)) return String(value);
|
|
27
|
-
if (typeof value !== 'string') return null;
|
|
28
|
-
const trimmed = value.trim();
|
|
29
|
-
return trimmed || null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function firstString(...values: unknown[]) {
|
|
33
|
-
for (const value of values) {
|
|
34
|
-
const string = readString(value);
|
|
35
|
-
if (string) return string;
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function isAbsoluteFilePath(value: string) {
|
|
41
|
-
return value.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(value);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function cwdRelativePath(value: string) {
|
|
45
|
-
return isAbsoluteFilePath(value) ? value : `${process.cwd()}/${value}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function readPreviewCallbackUrlFile(
|
|
49
|
-
environment: NodeJS.ProcessEnv = process.env,
|
|
50
|
-
) {
|
|
51
|
-
const configuredPath = environment.DEEPLINE_PREVIEW_CALLBACK_URL_FILE?.trim();
|
|
52
|
-
const filePath = cwdRelativePath(
|
|
53
|
-
configuredPath || DEFAULT_PREVIEW_CALLBACK_URL_FILE,
|
|
54
|
-
);
|
|
55
|
-
try {
|
|
56
|
-
if (!existsSync(filePath)) return null;
|
|
57
|
-
return readString(readFileSync(filePath, 'utf8'));
|
|
58
|
-
} catch {
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function readStringArray(value: unknown) {
|
|
64
|
-
if (!Array.isArray(value)) return [];
|
|
65
|
-
return value
|
|
66
|
-
.map((item) => readString(item))
|
|
67
|
-
.filter((item): item is string => Boolean(item));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function readNumberArray(value: unknown) {
|
|
71
|
-
if (!Array.isArray(value)) return [];
|
|
72
|
-
return value.filter(
|
|
73
|
-
(item): item is number =>
|
|
74
|
-
typeof item === 'number' && Number.isInteger(item),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function boundedName(value: string, maxLength: number) {
|
|
79
|
-
const normalized = value.replace(/\s+/g, ' ').trim();
|
|
80
|
-
if (normalized.length <= maxLength) return normalized;
|
|
81
|
-
return normalized.slice(0, maxLength).trim();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function managedWebhookName(input: {
|
|
85
|
-
definition: ProviderMonitorDefinitionLike;
|
|
86
|
-
provider: string;
|
|
87
|
-
maxLength?: number;
|
|
88
|
-
}) {
|
|
89
|
-
const source = input.definition.name ?? input.definition.key;
|
|
90
|
-
const name = `Deepline ${input.provider} ${source}`;
|
|
91
|
-
return boundedName(name, input.maxLength ?? 80);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Resolve the externally reachable origin for provider callbacks and durable
|
|
96
|
-
* workers. Local Convex actions need the preview tunnel, not a loopback URL.
|
|
97
|
-
*/
|
|
98
|
-
export function resolveProviderMonitorCallbackBaseUrl(
|
|
99
|
-
explicit?: string | null,
|
|
100
|
-
environment: NodeJS.ProcessEnv = process.env,
|
|
101
|
-
) {
|
|
102
|
-
const baseUrl =
|
|
103
|
-
explicit ||
|
|
104
|
-
environment.DEEPLINE_WORKER_CALLBACK_URL ||
|
|
105
|
-
readPreviewCallbackUrlFile(environment) ||
|
|
106
|
-
environment.WORKTREE_PUBLIC_APP_URL ||
|
|
107
|
-
environment.DEEPLINE_API_BASE_URL ||
|
|
108
|
-
environment.NEXT_PUBLIC_APP_URL ||
|
|
109
|
-
environment.APP_URL ||
|
|
110
|
-
environment.VERCEL_URL ||
|
|
111
|
-
DEFAULT_MONITOR_CALLBACK_BASE_URL;
|
|
112
|
-
return baseUrl.startsWith('http') ? baseUrl : `https://${baseUrl}`;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function createProviderWebhookCallbackToken() {
|
|
116
|
-
return randomBytes(32).toString('hex');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function providerWebhookCallbackPath(input: {
|
|
120
|
-
provider: string;
|
|
121
|
-
orgId: string;
|
|
122
|
-
token: string;
|
|
123
|
-
}) {
|
|
124
|
-
return `/api/v2/monitors/provider-callbacks/webhook/${encodeURIComponent(
|
|
125
|
-
input.provider,
|
|
126
|
-
)}/${encodeURIComponent(input.orgId)}/${encodeURIComponent(input.token)}`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function buildProviderWebhookCallbackUrl(input: {
|
|
130
|
-
provider: string;
|
|
131
|
-
orgId: string;
|
|
132
|
-
token: string;
|
|
133
|
-
callbackBaseUrl?: string | null;
|
|
134
|
-
}) {
|
|
135
|
-
const baseUrl = resolveProviderMonitorCallbackBaseUrl(input.callbackBaseUrl);
|
|
136
|
-
if (input.provider === 'snitcher') {
|
|
137
|
-
return `${baseUrl.replace(/\/$/, '')}/api/v2/monitors/provider-callbacks/deepline-analytics`;
|
|
138
|
-
}
|
|
139
|
-
return `${baseUrl.replace(/\/$/, '')}${providerWebhookCallbackPath(input)}`;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export function readProviderWebhookCallbackUrl(
|
|
143
|
-
payload: Record<string, unknown>,
|
|
144
|
-
) {
|
|
145
|
-
const webhook = readRecord(payload.webhook);
|
|
146
|
-
return firstString(
|
|
147
|
-
payload.target_url,
|
|
148
|
-
payload.target_hook_url,
|
|
149
|
-
payload.webhook_url,
|
|
150
|
-
webhook.webhook_url,
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function extractProviderWebhookId(raw: unknown) {
|
|
155
|
-
const root = readRecord(raw);
|
|
156
|
-
const data = readRecord(root.data);
|
|
157
|
-
const result = readRecord(root.result);
|
|
158
|
-
const resultData = readRecord(result.data);
|
|
159
|
-
const webhook = readRecord(root.webhook);
|
|
160
|
-
const dataWebhook = readRecord(data.webhook);
|
|
161
|
-
const id = readRecord(root.id);
|
|
162
|
-
const dataId = readRecord(data.id);
|
|
163
|
-
const resultDataId = readRecord(resultData.id);
|
|
164
|
-
return firstString(
|
|
165
|
-
root.webhook_id,
|
|
166
|
-
root.webhookId,
|
|
167
|
-
root.hook_id,
|
|
168
|
-
root.hookId,
|
|
169
|
-
root.id,
|
|
170
|
-
root._id,
|
|
171
|
-
data.webhook_id,
|
|
172
|
-
data.webhookId,
|
|
173
|
-
data.hook_id,
|
|
174
|
-
data.hookId,
|
|
175
|
-
data.id,
|
|
176
|
-
data._id,
|
|
177
|
-
result.webhook_id,
|
|
178
|
-
result.webhookId,
|
|
179
|
-
result.hook_id,
|
|
180
|
-
result.hookId,
|
|
181
|
-
result.id,
|
|
182
|
-
result._id,
|
|
183
|
-
resultData.webhook_id,
|
|
184
|
-
resultData.webhookId,
|
|
185
|
-
resultData.hook_id,
|
|
186
|
-
resultData.hookId,
|
|
187
|
-
resultData.id,
|
|
188
|
-
resultData._id,
|
|
189
|
-
webhook.webhook_id,
|
|
190
|
-
webhook.id,
|
|
191
|
-
dataWebhook.webhook_id,
|
|
192
|
-
dataWebhook.id,
|
|
193
|
-
id.webhook_id,
|
|
194
|
-
dataId.webhook_id,
|
|
195
|
-
resultDataId.webhook_id,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export function buildProviderWebhookRuntimePayload(input: {
|
|
200
|
-
definition: ProviderMonitorDefinitionLike;
|
|
201
|
-
capability: ProviderMonitorCapabilityDefinition;
|
|
202
|
-
callbackUrl: string;
|
|
203
|
-
}) {
|
|
204
|
-
const payload = input.definition.payload ?? {};
|
|
205
|
-
const provider = input.capability.provider;
|
|
206
|
-
switch (provider) {
|
|
207
|
-
case 'attio':
|
|
208
|
-
return {
|
|
209
|
-
target_url: input.callbackUrl,
|
|
210
|
-
subscriptions: readStringArray(payload.event_types).map(
|
|
211
|
-
(eventType) => ({
|
|
212
|
-
event_type: eventType,
|
|
213
|
-
}),
|
|
214
|
-
),
|
|
215
|
-
};
|
|
216
|
-
case 'lemlist':
|
|
217
|
-
return {
|
|
218
|
-
target_url: input.callbackUrl,
|
|
219
|
-
type: readString(payload.event_type),
|
|
220
|
-
secret: createProviderCallbackSecret('lemlist'),
|
|
221
|
-
...(readString(payload.campaign_id)
|
|
222
|
-
? { campaign_id: readString(payload.campaign_id) }
|
|
223
|
-
: {}),
|
|
224
|
-
};
|
|
225
|
-
case 'instantly':
|
|
226
|
-
return {
|
|
227
|
-
target_hook_url: input.callbackUrl,
|
|
228
|
-
event_type: readString(payload.event_type),
|
|
229
|
-
headers: {
|
|
230
|
-
[MONITOR_CALLBACK_SECRET_HEADER]:
|
|
231
|
-
createProviderCallbackSecret('instantly'),
|
|
232
|
-
},
|
|
233
|
-
name: managedWebhookName({
|
|
234
|
-
definition: input.definition,
|
|
235
|
-
provider,
|
|
236
|
-
}),
|
|
237
|
-
...(readString(payload.campaign_id)
|
|
238
|
-
? { campaign: readString(payload.campaign_id) }
|
|
239
|
-
: {}),
|
|
240
|
-
};
|
|
241
|
-
case 'smartlead':
|
|
242
|
-
return {
|
|
243
|
-
campaign_id: payload.campaign_id,
|
|
244
|
-
webhook: {
|
|
245
|
-
id: null,
|
|
246
|
-
name: managedWebhookName({
|
|
247
|
-
definition: input.definition,
|
|
248
|
-
provider,
|
|
249
|
-
}),
|
|
250
|
-
webhook_url: input.callbackUrl,
|
|
251
|
-
event_types: readStringArray(payload.event_types),
|
|
252
|
-
...(readStringArray(payload.categories).length
|
|
253
|
-
? { categories: readStringArray(payload.categories) }
|
|
254
|
-
: {}),
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
case 'heyreach':
|
|
258
|
-
return {
|
|
259
|
-
webhook_name: managedWebhookName({
|
|
260
|
-
definition: input.definition,
|
|
261
|
-
provider,
|
|
262
|
-
maxLength: 25,
|
|
263
|
-
}),
|
|
264
|
-
webhook_url: input.callbackUrl,
|
|
265
|
-
event_type: readString(payload.event_type),
|
|
266
|
-
...(readNumberArray(payload.campaign_ids).length
|
|
267
|
-
? { campaign_ids: readNumberArray(payload.campaign_ids) }
|
|
268
|
-
: {}),
|
|
269
|
-
};
|
|
270
|
-
case 'vector':
|
|
271
|
-
// Vector's dashboard owns the webhook resource. This payload is durable
|
|
272
|
-
// setup evidence, not an upstream API request.
|
|
273
|
-
return {
|
|
274
|
-
callback_url: input.callbackUrl,
|
|
275
|
-
event_type: 'contact.visited',
|
|
276
|
-
};
|
|
277
|
-
case 'rb2b':
|
|
278
|
-
// RB2B's dashboard owns the single webhook connection. This payload is
|
|
279
|
-
// durable setup evidence, not an upstream API request.
|
|
280
|
-
return {
|
|
281
|
-
callback_url: input.callbackUrl,
|
|
282
|
-
};
|
|
283
|
-
case 'snitcher':
|
|
284
|
-
// Radar is configured at the operator level. The callback URL is durable
|
|
285
|
-
// evidence of the Deepline-owned receiver; the setup API creates the
|
|
286
|
-
// customer tracker and configures session delivery upstream.
|
|
287
|
-
return {
|
|
288
|
-
callback_url: input.callbackUrl,
|
|
289
|
-
domains: readStringArray(payload.domains),
|
|
290
|
-
form_tracking: payload.formTracking === true,
|
|
291
|
-
click_tracking: payload.clickTracking === true,
|
|
292
|
-
custom_events: payload.customEvents !== false,
|
|
293
|
-
wait_for_consent: payload.waitForConsent !== false,
|
|
294
|
-
};
|
|
295
|
-
default:
|
|
296
|
-
throw new Error(
|
|
297
|
-
`Provider webhook monitor payload builder is not implemented for ${provider}.`,
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export type MonitorQuickstartPrompt = {
|
|
2
|
-
prompt: string;
|
|
3
|
-
icon: 'job-change' | 'new-hires' | 'hiring-signal';
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
export const MONITOR_QUICKSTART_PROMPTS: MonitorQuickstartPrompt[] = [
|
|
7
|
-
{
|
|
8
|
-
prompt:
|
|
9
|
-
'/deepline-gtm Monitor my target accounts for new VP Sales, Marketing, and Revenue hires.',
|
|
10
|
-
icon: 'new-hires',
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
prompt:
|
|
14
|
-
'/deepline-gtm Monitor when people at my target accounts change jobs.',
|
|
15
|
-
icon: 'job-change',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
prompt:
|
|
19
|
-
'/deepline-gtm Monitor my target accounts for job openings in the roles I sell to.',
|
|
20
|
-
icon: 'hiring-signal',
|
|
21
|
-
},
|
|
22
|
-
];
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { lookup } from 'node:dns/promises';
|
|
2
|
-
import { isIP } from 'node:net';
|
|
3
|
-
import { DEEPLINE_ANALYTICS_BROWSER_OBJECT } from '@/lib/analytics/public';
|
|
4
|
-
|
|
5
|
-
export type SnitcherInstallationCheck = {
|
|
6
|
-
domain: string;
|
|
7
|
-
status: 'installed' | 'not_found' | 'unreachable';
|
|
8
|
-
message: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export async function validateSnitcherInstallation(input: {
|
|
12
|
-
domains: string[];
|
|
13
|
-
trackingScriptId: string;
|
|
14
|
-
}) {
|
|
15
|
-
return await Promise.all(
|
|
16
|
-
input.domains.map(async (domain): Promise<SnitcherInstallationCheck> => {
|
|
17
|
-
// Domains were validated and stored during setup. Never accept arbitrary URLs here.
|
|
18
|
-
if (isIP(domain) || domain === 'localhost')
|
|
19
|
-
return {
|
|
20
|
-
domain,
|
|
21
|
-
status: 'unreachable',
|
|
22
|
-
message: 'This domain cannot be checked.',
|
|
23
|
-
};
|
|
24
|
-
try {
|
|
25
|
-
const addresses = await lookup(domain, { all: true });
|
|
26
|
-
if (
|
|
27
|
-
!addresses.length ||
|
|
28
|
-
addresses.some(({ address }) => {
|
|
29
|
-
if (isIP(address) === 6) {
|
|
30
|
-
const lower = address.toLowerCase();
|
|
31
|
-
return (
|
|
32
|
-
lower === '::1' ||
|
|
33
|
-
lower.startsWith('fc') ||
|
|
34
|
-
lower.startsWith('fd') ||
|
|
35
|
-
lower.startsWith('fe80:')
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
const [a, b] = address.split('.').map(Number);
|
|
39
|
-
return (
|
|
40
|
-
a === 0 ||
|
|
41
|
-
a === 10 ||
|
|
42
|
-
a === 127 ||
|
|
43
|
-
(a === 169 && b === 254) ||
|
|
44
|
-
(a === 172 && b >= 16 && b <= 31) ||
|
|
45
|
-
(a === 192 && b === 168) ||
|
|
46
|
-
(a === 100 && b >= 64 && b <= 127)
|
|
47
|
-
);
|
|
48
|
-
})
|
|
49
|
-
)
|
|
50
|
-
return {
|
|
51
|
-
domain,
|
|
52
|
-
status: 'unreachable',
|
|
53
|
-
message: 'This domain cannot be checked.',
|
|
54
|
-
};
|
|
55
|
-
const response = await fetch(`https://${domain}`, {
|
|
56
|
-
redirect: 'error',
|
|
57
|
-
signal: AbortSignal.timeout(10_000),
|
|
58
|
-
headers: {
|
|
59
|
-
Accept: 'text/html',
|
|
60
|
-
'User-Agent': 'DeeplineTrackerValidator/1.0',
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
if (!response.ok)
|
|
64
|
-
return {
|
|
65
|
-
domain,
|
|
66
|
-
status: 'unreachable',
|
|
67
|
-
message: `The site returned HTTP ${response.status}.`,
|
|
68
|
-
};
|
|
69
|
-
const body = (await response.text()).slice(0, 500_000);
|
|
70
|
-
const installed =
|
|
71
|
-
body.includes(input.trackingScriptId) &&
|
|
72
|
-
body.includes(DEEPLINE_ANALYTICS_BROWSER_OBJECT);
|
|
73
|
-
return installed
|
|
74
|
-
? {
|
|
75
|
-
domain,
|
|
76
|
-
status: 'installed',
|
|
77
|
-
message: 'Tracker found in the page source.',
|
|
78
|
-
}
|
|
79
|
-
: {
|
|
80
|
-
domain,
|
|
81
|
-
status: 'not_found',
|
|
82
|
-
message: 'Tracker was not found in the page source yet.',
|
|
83
|
-
};
|
|
84
|
-
} catch {
|
|
85
|
-
return {
|
|
86
|
-
domain,
|
|
87
|
-
status: 'unreachable',
|
|
88
|
-
message: 'Could not reach this site over HTTPS.',
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
}),
|
|
92
|
-
);
|
|
93
|
-
}
|