deepline 0.3.55 → 0.3.56
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 +232 -0
- package/dist/bundling-sources/sdk/src/index.ts +29 -0
- package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +556 -0
- package/dist/bundling-sources/sdk/src/monitor-fleets.ts +31 -0
- package/dist/bundling-sources/sdk/src/play.ts +2 -8
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/monitors/monitor-fleet-limits.ts +14 -0
- package/dist/bundling-sources/shared_libs/monitors/org-monitor-limits.ts +102 -0
- package/dist/bundling-sources/shared_libs/monitors/validation.ts +244 -0
- package/dist/cli/index.js +1680 -354
- package/dist/cli/index.mjs +1616 -290
- package/dist/index.d.mts +220 -9
- package/dist/index.d.ts +220 -9
- package/dist/index.js +474 -14
- package/dist/index.mjs +464 -14
- package/dist/install-integrity.json +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an organization may watch.
|
|
3
|
+
*
|
|
4
|
+
* Monitors are priced and reasoned about in accounts, not in rows: an
|
|
5
|
+
* organization watches five thousand companies, and watches up to five signals
|
|
6
|
+
* on each of them. A flat monitor ceiling could not express either half - it
|
|
7
|
+
* let one company consume the whole allowance, and it made "how many accounts
|
|
8
|
+
* can I watch" unanswerable without knowing how many signals each would use.
|
|
9
|
+
*
|
|
10
|
+
* The two numbers below are the whole policy. Maximum monitors is their
|
|
11
|
+
* product and is deliberately not a third number to reason about.
|
|
12
|
+
*/
|
|
13
|
+
import { ORG_LIMITS, OrgLimit } from '../org-limits/registry';
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_ORG_MONITOR_ENTITY_LIMIT =
|
|
16
|
+
ORG_LIMITS[OrgLimit.MonitorWatchedEntities].defaultValue;
|
|
17
|
+
|
|
18
|
+
/** Signals one account may be watched with, e.g. jobs + funding + news. */
|
|
19
|
+
export const DEFAULT_MONITORS_PER_ENTITY =
|
|
20
|
+
ORG_LIMITS[OrgLimit.MonitorsPerEntity].defaultValue;
|
|
21
|
+
|
|
22
|
+
export type OrgMonitorLimitPolicy = {
|
|
23
|
+
/** Distinct accounts, contacts, campaigns, or connections. */
|
|
24
|
+
entityLimit: number;
|
|
25
|
+
/** Monitors admitted against any one of them. */
|
|
26
|
+
monitorsPerEntity: number;
|
|
27
|
+
overrideApplied: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* What an organization gets before any per-organization override.
|
|
32
|
+
*
|
|
33
|
+
* Overrides used to be a source-controlled map keyed by organization id, so
|
|
34
|
+
* raising one customer's ceiling meant a deploy. They live in Convex now,
|
|
35
|
+
* against the ids declared in the limit registry, which is why this function
|
|
36
|
+
* no longer takes an organization: a caller that can read the override record
|
|
37
|
+
* resolves it there, and a caller that cannot is showing a default.
|
|
38
|
+
*/
|
|
39
|
+
export function defaultOrgMonitorLimitPolicy(): OrgMonitorLimitPolicy {
|
|
40
|
+
return {
|
|
41
|
+
entityLimit: DEFAULT_ORG_MONITOR_ENTITY_LIMIT,
|
|
42
|
+
monitorsPerEntity: DEFAULT_MONITORS_PER_ENTITY,
|
|
43
|
+
overrideApplied: false,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type OrgMonitorCapacity = {
|
|
48
|
+
/** Accounts already watched. */
|
|
49
|
+
used: number;
|
|
50
|
+
/** Accounts held by an in-flight create. */
|
|
51
|
+
reserved: number;
|
|
52
|
+
limit: number;
|
|
53
|
+
remaining: number;
|
|
54
|
+
over_by: number;
|
|
55
|
+
can_create: boolean;
|
|
56
|
+
monitors_per_entity: number;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Capacity in accounts.
|
|
61
|
+
*
|
|
62
|
+
* `used` and `reserved` count DISTINCT entities, so adding a second signal to
|
|
63
|
+
* an account the organization already watches consumes nothing here - that is
|
|
64
|
+
* what the per-entity limit governs instead.
|
|
65
|
+
*/
|
|
66
|
+
export function orgMonitorCapacity(input: {
|
|
67
|
+
used: number;
|
|
68
|
+
reserved: number;
|
|
69
|
+
limit: number;
|
|
70
|
+
monitorsPerEntity?: number;
|
|
71
|
+
}): OrgMonitorCapacity {
|
|
72
|
+
const occupied = input.used + input.reserved;
|
|
73
|
+
return {
|
|
74
|
+
used: input.used,
|
|
75
|
+
reserved: input.reserved,
|
|
76
|
+
limit: input.limit,
|
|
77
|
+
remaining: Math.max(0, input.limit - occupied),
|
|
78
|
+
over_by: Math.max(0, occupied - input.limit),
|
|
79
|
+
can_create: occupied < input.limit,
|
|
80
|
+
monitors_per_entity:
|
|
81
|
+
input.monitorsPerEntity ?? DEFAULT_MONITORS_PER_ENTITY,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Whether one more monitor may be admitted against a given account.
|
|
87
|
+
*
|
|
88
|
+
* Separate from capacity because the two refuse for different reasons and the
|
|
89
|
+
* customer needs to be told which: the organization is watching as many
|
|
90
|
+
* accounts as it may, or this account already carries as many signals as it
|
|
91
|
+
* may.
|
|
92
|
+
*/
|
|
93
|
+
export function entityMonitorAdmission(input: {
|
|
94
|
+
monitorsOnEntity: number;
|
|
95
|
+
monitorsPerEntity: number;
|
|
96
|
+
}): { admitted: boolean; remaining: number } {
|
|
97
|
+
const remaining = Math.max(
|
|
98
|
+
0,
|
|
99
|
+
input.monitorsPerEntity - input.monitorsOnEntity,
|
|
100
|
+
);
|
|
101
|
+
return { admitted: remaining > 0, remaining };
|
|
102
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
export type MonitorSdkValidationIssueEntityType =
|
|
2
|
+
| 'monitor'
|
|
3
|
+
| 'action'
|
|
4
|
+
| 'trigger'
|
|
5
|
+
| 'bundle'
|
|
6
|
+
| 'play'
|
|
7
|
+
| 'listener'
|
|
8
|
+
| 'table'
|
|
9
|
+
| 'tool'
|
|
10
|
+
| 'workflow';
|
|
11
|
+
|
|
12
|
+
export type MonitorSdkValidationIssue = {
|
|
13
|
+
severity: 'error' | 'warning';
|
|
14
|
+
code: string;
|
|
15
|
+
path: string;
|
|
16
|
+
message: string;
|
|
17
|
+
expected?: unknown;
|
|
18
|
+
received?: unknown;
|
|
19
|
+
suggestion?: string;
|
|
20
|
+
entity_type?: MonitorSdkValidationIssueEntityType;
|
|
21
|
+
entity_key?: string;
|
|
22
|
+
docs_ref?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type MonitorSdkValidationResult = {
|
|
26
|
+
valid: boolean;
|
|
27
|
+
issues: MonitorSdkValidationIssue[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const MONITOR_SDK_VALIDATION_ERROR_CODE = 'MONITOR_SDK_VALIDATION_ERROR';
|
|
31
|
+
|
|
32
|
+
export const MONITOR_DEPLOY_VALIDATION_ERROR_CODE =
|
|
33
|
+
'monitor_deploy_validation_failed';
|
|
34
|
+
|
|
35
|
+
export class MonitorSdkValidationError extends Error {
|
|
36
|
+
readonly code = MONITOR_SDK_VALIDATION_ERROR_CODE;
|
|
37
|
+
readonly issues: MonitorSdkValidationIssue[];
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
issues: MonitorSdkValidationIssue[],
|
|
41
|
+
message = 'Monitor SDK validation failed.',
|
|
42
|
+
// Some of these wrap a provider failure whose RETRYABILITY is the only
|
|
43
|
+
// thing a caller can act on. A wrapper that drops it turns a rate limit
|
|
44
|
+
// into a permanent refusal, so the cause travels with the issue list.
|
|
45
|
+
options?: { cause?: unknown },
|
|
46
|
+
) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = 'MonitorSdkValidationError';
|
|
49
|
+
this.issues = normalizeMonitorSdkValidationIssues(issues);
|
|
50
|
+
// Assigned rather than passed to `super`: this module compiles under two
|
|
51
|
+
// tsconfigs and only one of them types the `ErrorOptions` overload.
|
|
52
|
+
if (options?.cause !== undefined) {
|
|
53
|
+
(this as { cause?: unknown }).cause = options.cause;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const SENSITIVE_MONITOR_VALIDATION_KEYS = new Set([
|
|
59
|
+
'access_token',
|
|
60
|
+
'accessToken',
|
|
61
|
+
'api_key',
|
|
62
|
+
'apiKey',
|
|
63
|
+
'authorization',
|
|
64
|
+
'binding_id',
|
|
65
|
+
'bindingId',
|
|
66
|
+
'callback_token',
|
|
67
|
+
'callbackToken',
|
|
68
|
+
'callback_url',
|
|
69
|
+
'callbackUrl',
|
|
70
|
+
'credential',
|
|
71
|
+
'credentials',
|
|
72
|
+
'password',
|
|
73
|
+
'provider_binding',
|
|
74
|
+
'providerBinding',
|
|
75
|
+
'provider_capability',
|
|
76
|
+
'providerCapability',
|
|
77
|
+
'provider_credentials',
|
|
78
|
+
'providerCredentials',
|
|
79
|
+
'provider_marker',
|
|
80
|
+
'providerMarker',
|
|
81
|
+
'refresh_token',
|
|
82
|
+
'refreshToken',
|
|
83
|
+
'runtime_action',
|
|
84
|
+
'runtimeAction',
|
|
85
|
+
'runtime_payload',
|
|
86
|
+
'runtimePayload',
|
|
87
|
+
'secret',
|
|
88
|
+
'source_capability',
|
|
89
|
+
'sourceCapability',
|
|
90
|
+
'upstream_monitor_id',
|
|
91
|
+
'upstreamMonitorId',
|
|
92
|
+
'upstream_resource_id',
|
|
93
|
+
'upstreamResourceId',
|
|
94
|
+
'upstream_response',
|
|
95
|
+
'upstreamResponse',
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
function sanitizeMonitorPublicString(value: string) {
|
|
99
|
+
return value.replace(
|
|
100
|
+
/https?:\/\/\S*\/api\/v2\/monitors\/provider-callbacks\/\S+/g,
|
|
101
|
+
'[redacted-callback-url]',
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function sanitizeMonitorPublicValue(
|
|
106
|
+
value: unknown,
|
|
107
|
+
seen = new WeakSet<object>(),
|
|
108
|
+
allowSetupWebhookEndpoint = false,
|
|
109
|
+
): unknown {
|
|
110
|
+
if (typeof value === 'string') {
|
|
111
|
+
return sanitizeMonitorPublicString(value);
|
|
112
|
+
}
|
|
113
|
+
if (!value || typeof value !== 'object') return value;
|
|
114
|
+
if (seen.has(value)) return '[redacted-circular-reference]';
|
|
115
|
+
seen.add(value);
|
|
116
|
+
if (Array.isArray(value)) {
|
|
117
|
+
const sanitizedArray = value.map((entry) =>
|
|
118
|
+
sanitizeMonitorPublicValue(entry, seen, allowSetupWebhookEndpoint),
|
|
119
|
+
);
|
|
120
|
+
seen.delete(value);
|
|
121
|
+
return sanitizedArray;
|
|
122
|
+
}
|
|
123
|
+
const sanitized: Record<string, unknown> = {};
|
|
124
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
125
|
+
if (SENSITIVE_MONITOR_VALIDATION_KEYS.has(key)) continue;
|
|
126
|
+
// A manual webhook endpoint is deliberately returned only as part of an
|
|
127
|
+
// authenticated deploy response, so the customer can paste it into the
|
|
128
|
+
// provider dashboard. Its token is otherwise redacted from monitor APIs.
|
|
129
|
+
if (
|
|
130
|
+
allowSetupWebhookEndpoint &&
|
|
131
|
+
key === 'webhook_endpoint' &&
|
|
132
|
+
typeof entry === 'string'
|
|
133
|
+
) {
|
|
134
|
+
sanitized[key] = entry;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
sanitized[key] = sanitizeMonitorPublicValue(entry, seen, key === 'setup');
|
|
138
|
+
}
|
|
139
|
+
seen.delete(value);
|
|
140
|
+
return sanitized;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function normalizeMonitorSdkIssueEntityType(
|
|
144
|
+
value: unknown,
|
|
145
|
+
): MonitorSdkValidationIssueEntityType | null {
|
|
146
|
+
if (value === 'provider_capability') return 'tool';
|
|
147
|
+
return isMonitorSdkIssueEntityType(value) ? value : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function monitorSdkIssue(
|
|
151
|
+
issue: Omit<MonitorSdkValidationIssue, 'severity'> & {
|
|
152
|
+
severity?: MonitorSdkValidationIssue['severity'];
|
|
153
|
+
},
|
|
154
|
+
): MonitorSdkValidationIssue {
|
|
155
|
+
const entityType = normalizeMonitorSdkIssueEntityType(issue.entity_type);
|
|
156
|
+
return {
|
|
157
|
+
severity: issue.severity ?? 'error',
|
|
158
|
+
code: issue.code,
|
|
159
|
+
path: issue.path,
|
|
160
|
+
message: issue.message,
|
|
161
|
+
...(Object.prototype.hasOwnProperty.call(issue, 'expected')
|
|
162
|
+
? { expected: sanitizeMonitorPublicValue(issue.expected) }
|
|
163
|
+
: {}),
|
|
164
|
+
...(Object.prototype.hasOwnProperty.call(issue, 'received')
|
|
165
|
+
? { received: sanitizeMonitorPublicValue(issue.received) }
|
|
166
|
+
: {}),
|
|
167
|
+
...(issue.suggestion ? { suggestion: issue.suggestion } : {}),
|
|
168
|
+
...(entityType ? { entity_type: entityType } : {}),
|
|
169
|
+
...(issue.entity_key ? { entity_key: issue.entity_key } : {}),
|
|
170
|
+
...(issue.docs_ref ? { docs_ref: issue.docs_ref } : {}),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function normalizeMonitorSdkValidationIssues(
|
|
175
|
+
issues: unknown,
|
|
176
|
+
): MonitorSdkValidationIssue[] {
|
|
177
|
+
if (!Array.isArray(issues)) return [];
|
|
178
|
+
return issues
|
|
179
|
+
.filter((issue): issue is Record<string, unknown> =>
|
|
180
|
+
Boolean(issue && typeof issue === 'object' && !Array.isArray(issue)),
|
|
181
|
+
)
|
|
182
|
+
.map((issue) => {
|
|
183
|
+
const entityType = normalizeMonitorSdkIssueEntityType(issue.entity_type);
|
|
184
|
+
return monitorSdkIssue({
|
|
185
|
+
code:
|
|
186
|
+
typeof issue.code === 'string' && issue.code.trim()
|
|
187
|
+
? issue.code.trim()
|
|
188
|
+
: 'monitor_validation_error',
|
|
189
|
+
path:
|
|
190
|
+
typeof issue.path === 'string' && issue.path.trim()
|
|
191
|
+
? issue.path.trim()
|
|
192
|
+
: 'bundle',
|
|
193
|
+
message:
|
|
194
|
+
typeof issue.message === 'string' && issue.message.trim()
|
|
195
|
+
? issue.message.trim()
|
|
196
|
+
: 'Monitor validation failed.',
|
|
197
|
+
severity:
|
|
198
|
+
issue.severity === 'warning' || issue.severity === 'error'
|
|
199
|
+
? issue.severity
|
|
200
|
+
: 'error',
|
|
201
|
+
...(Object.prototype.hasOwnProperty.call(issue, 'expected')
|
|
202
|
+
? { expected: issue.expected }
|
|
203
|
+
: {}),
|
|
204
|
+
...(Object.prototype.hasOwnProperty.call(issue, 'received')
|
|
205
|
+
? { received: issue.received }
|
|
206
|
+
: {}),
|
|
207
|
+
...(typeof issue.suggestion === 'string' && issue.suggestion.trim()
|
|
208
|
+
? { suggestion: issue.suggestion.trim() }
|
|
209
|
+
: {}),
|
|
210
|
+
...(entityType ? { entity_type: entityType } : {}),
|
|
211
|
+
...(typeof issue.entity_key === 'string' && issue.entity_key.trim()
|
|
212
|
+
? { entity_key: issue.entity_key.trim() }
|
|
213
|
+
: {}),
|
|
214
|
+
...(typeof issue.docs_ref === 'string' && issue.docs_ref.trim()
|
|
215
|
+
? { docs_ref: issue.docs_ref.trim() }
|
|
216
|
+
: {}),
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function hasMonitorSdkValidationIssues(value: unknown): value is {
|
|
222
|
+
issues: MonitorSdkValidationIssue[];
|
|
223
|
+
} {
|
|
224
|
+
return (
|
|
225
|
+
Boolean(value && typeof value === 'object' && !Array.isArray(value)) &&
|
|
226
|
+
Array.isArray((value as { issues?: unknown }).issues)
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function isMonitorSdkIssueEntityType(
|
|
231
|
+
value: unknown,
|
|
232
|
+
): value is MonitorSdkValidationIssueEntityType {
|
|
233
|
+
return (
|
|
234
|
+
value === 'monitor' ||
|
|
235
|
+
value === 'action' ||
|
|
236
|
+
value === 'trigger' ||
|
|
237
|
+
value === 'bundle' ||
|
|
238
|
+
value === 'play' ||
|
|
239
|
+
value === 'listener' ||
|
|
240
|
+
value === 'table' ||
|
|
241
|
+
value === 'tool' ||
|
|
242
|
+
value === 'workflow'
|
|
243
|
+
);
|
|
244
|
+
}
|