@hasna/contacts 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -13
- package/dist/browser/cli.d.ts +4 -0
- package/dist/browser/cli.d.ts.map +1 -0
- package/dist/browser/identity.d.ts +3 -0
- package/dist/browser/identity.d.ts.map +1 -0
- package/dist/browser/install.d.ts +32 -0
- package/dist/browser/install.d.ts.map +1 -0
- package/dist/browser/native.d.ts +3 -0
- package/dist/browser/native.d.ts.map +1 -0
- package/dist/browser/native.js +822 -0
- package/dist/browser/protocol.d.ts +26 -0
- package/dist/browser/protocol.d.ts.map +1 -0
- package/dist/browser/values.d.ts +18 -0
- package/dist/browser/values.d.ts.map +1 -0
- package/dist/cli/commands/core.d.ts.map +1 -1
- package/dist/cli/index.js +479 -149
- package/dist/cli/status-domain.preload.d.ts +1 -1
- package/dist/cli/status-domain.preload.d.ts.map +1 -1
- package/dist/cli/status-fixture.d.ts +17 -0
- package/dist/cli/status-fixture.d.ts.map +1 -0
- package/dist/cloud/http-storage.d.ts +20 -12
- package/dist/cloud/http-storage.d.ts.map +1 -1
- package/dist/cloud/resolver-inputs.d.ts +51 -0
- package/dist/cloud/resolver-inputs.d.ts.map +1 -0
- package/dist/db/paths.d.ts +4 -4
- package/dist/db/paths.d.ts.map +1 -1
- package/dist/generated/storage-kit/backend.d.ts +19 -0
- package/dist/generated/storage-kit/backend.d.ts.map +1 -0
- package/dist/generated/storage-kit/index.d.ts +2 -1
- package/dist/generated/storage-kit/index.d.ts.map +1 -1
- package/dist/generated/storage-kit/migrations.d.ts +21 -0
- package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
- package/dist/generated/storage-kit/own.d.ts +11 -0
- package/dist/generated/storage-kit/own.d.ts.map +1 -0
- package/dist/generated/storage-kit/pool.d.ts +5 -17
- package/dist/generated/storage-kit/pool.d.ts.map +1 -1
- package/dist/generated/storage-kit/query.d.ts +1 -1
- package/dist/generated/storage-kit/query.d.ts.map +1 -1
- package/dist/generated/storage-kit/tls.d.ts +30 -3
- package/dist/generated/storage-kit/tls.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -28
- package/dist/lib/audience-contract.d.ts +9 -9
- package/dist/lib/compact-output.d.ts +67 -0
- package/dist/lib/compact-output.d.ts.map +1 -0
- package/dist/mcp/handlers/core.d.ts.map +1 -1
- package/dist/mcp/index.d.ts +11 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +490 -212
- package/dist/mcp/profile.d.ts +8 -0
- package/dist/mcp/profile.d.ts.map +1 -0
- package/dist/mcp/register-tools.d.ts +3 -1
- package/dist/mcp/register-tools.d.ts.map +1 -1
- package/dist/mcp/startup-gate.d.ts +48 -0
- package/dist/mcp/startup-gate.d.ts.map +1 -0
- package/dist/mcp/storage-tools.d.ts +2 -1
- package/dist/mcp/storage-tools.d.ts.map +1 -1
- package/dist/mcp/tools.d.ts +7 -45
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +70 -3
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +990 -7
- package/dist/server/index.js +231 -59
- package/dist/server/pg-store.d.ts +1 -0
- package/dist/server/pg-store.d.ts.map +1 -1
- package/dist/store/index.d.ts.map +1 -1
- package/docs/chrome-autofill.md +45 -0
- package/extension/background.js +284 -0
- package/extension/content.js +387 -0
- package/extension/detect.js +228 -0
- package/extension/fill.js +112 -0
- package/extension/icons/128.png +0 -0
- package/extension/icons/16.png +0 -0
- package/extension/icons/32.png +0 -0
- package/extension/icons/48.png +0 -0
- package/extension/icons/icon.svg +17 -0
- package/extension/manifest.json +54 -0
- package/extension/popup.css +78 -0
- package/extension/popup.html +47 -0
- package/extension/popup.js +166 -0
- package/hasna.contract.json +20 -6
- package/package.json +10 -6
- package/dist/lib/config.d.ts +0 -7
- package/dist/lib/config.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/cloud/http-storage.ts
|
|
3
3
|
import {
|
|
4
|
+
ClientTransportConfigurationError,
|
|
4
5
|
createHasnaHttpTransport,
|
|
5
6
|
resolveCredential,
|
|
6
7
|
resolveClientTransport as resolveSharedClientTransport
|
|
@@ -90,6 +91,27 @@ function assertConfigurationUnchanged(env, expected) {
|
|
|
90
91
|
invalid();
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
// src/cloud/resolver-inputs.ts
|
|
95
|
+
import {
|
|
96
|
+
clientTransportEnvKeys as clientTransportEnvKeys2,
|
|
97
|
+
credentialOverrideEnvKey,
|
|
98
|
+
credentialPointerEnvKey,
|
|
99
|
+
CREDENTIAL_PROFILE_ENV_KEY
|
|
100
|
+
} from "@hasna/contracts/client";
|
|
101
|
+
var CONTRACTS_AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
102
|
+
function isAmbientContactsEnv(env) {
|
|
103
|
+
if (typeof process !== "undefined" && env === process.env)
|
|
104
|
+
return true;
|
|
105
|
+
return env[CONTRACTS_AMBIENT_ENVIRONMENT] === true;
|
|
106
|
+
}
|
|
107
|
+
function contactsResolverCredentials(env, credentials = {}) {
|
|
108
|
+
const keychain = { ...credentials.keychain };
|
|
109
|
+
if (keychain.enabled === undefined && keychain.run === undefined) {
|
|
110
|
+
keychain.enabled = isAmbientContactsEnv(env);
|
|
111
|
+
}
|
|
112
|
+
return { ...credentials, keychain };
|
|
113
|
+
}
|
|
114
|
+
|
|
93
115
|
// src/cloud/http-storage.ts
|
|
94
116
|
var RETIRED_CLIENT_SELECTOR_KEYS = [
|
|
95
117
|
"HASNA_CONTACTS_STORAGE_MODE",
|
|
@@ -125,37 +147,44 @@ class ContactsClientConfigurationError extends Error {
|
|
|
125
147
|
this.name = "ContactsClientConfigurationError";
|
|
126
148
|
}
|
|
127
149
|
}
|
|
128
|
-
function unconfiguredResolution(resolution,
|
|
150
|
+
function unconfiguredResolution(issue, resolution, warning = null) {
|
|
129
151
|
return {
|
|
130
152
|
transport: "unconfigured",
|
|
131
153
|
baseUrl: null,
|
|
132
|
-
apiUrlSource: resolution
|
|
133
|
-
apiKeyPresent: resolution
|
|
134
|
-
apiKeySource: resolution
|
|
135
|
-
apiKeyTier: resolution
|
|
154
|
+
apiUrlSource: resolution?.apiUrlSource ?? null,
|
|
155
|
+
apiKeyPresent: resolution?.apiKeyPresent ?? false,
|
|
156
|
+
apiKeySource: resolution?.apiKeySource ?? null,
|
|
157
|
+
apiKeyTier: resolution?.apiKeyTier ?? null,
|
|
136
158
|
configured: false,
|
|
137
159
|
misconfigured: true,
|
|
138
160
|
issue,
|
|
139
|
-
warning
|
|
161
|
+
warning
|
|
140
162
|
};
|
|
141
163
|
}
|
|
142
|
-
function resolveContactsClientTransport(name, env = process.env) {
|
|
164
|
+
function resolveContactsClientTransport(name, env = process.env, credentials = {}) {
|
|
143
165
|
if (name !== "contacts") {
|
|
144
166
|
throw new ContactsClientConfigurationError("CONTACTS_CLIENT_NAME_INVALID", "This resolver only accepts the contacts app slug.");
|
|
145
167
|
}
|
|
146
168
|
assertNoRetiredClientSelectors(env);
|
|
147
169
|
const stamp = clientConfigurationStamp(env);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
170
|
+
let resolution;
|
|
171
|
+
try {
|
|
172
|
+
resolution = resolveSharedClientTransport(name, env, {
|
|
173
|
+
credentials: contactsResolverCredentials(env, credentials)
|
|
174
|
+
});
|
|
175
|
+
} catch (error) {
|
|
176
|
+
assertConfigurationUnchanged(env, stamp);
|
|
177
|
+
if (error instanceof ClientTransportConfigurationError) {
|
|
178
|
+
return unconfiguredResolution(error.message, null);
|
|
179
|
+
}
|
|
180
|
+
throw error;
|
|
153
181
|
}
|
|
182
|
+
assertConfigurationUnchanged(env, stamp);
|
|
154
183
|
try {
|
|
155
184
|
assertHttpsBaseUrl(resolution.baseUrl);
|
|
156
185
|
} catch (error) {
|
|
157
186
|
return {
|
|
158
|
-
...unconfiguredResolution(
|
|
187
|
+
...unconfiguredResolution(error instanceof Error ? error.message : String(error), resolution),
|
|
159
188
|
apiKeyPresent: resolution.apiKeyPresent
|
|
160
189
|
};
|
|
161
190
|
}
|
|
@@ -169,7 +198,7 @@ function resolveContactsClientTransport(name, env = process.env) {
|
|
|
169
198
|
configured: true,
|
|
170
199
|
misconfigured: false,
|
|
171
200
|
issue: null,
|
|
172
|
-
warning:
|
|
201
|
+
warning: resolution.warning
|
|
173
202
|
};
|
|
174
203
|
}
|
|
175
204
|
function resourcePath(resource) {
|
|
@@ -223,20 +252,21 @@ function createStorageClient(name, transport) {
|
|
|
223
252
|
}
|
|
224
253
|
};
|
|
225
254
|
}
|
|
226
|
-
function resolveContactsStorageClient(name, env = process.env) {
|
|
227
|
-
const resolution = resolveContactsClientTransport(name, env);
|
|
255
|
+
function resolveContactsStorageClient(name, env = process.env, credentials = {}) {
|
|
256
|
+
const resolution = resolveContactsClientTransport(name, env, credentials);
|
|
228
257
|
if (!resolution.configured || !resolution.baseUrl) {
|
|
229
258
|
throw new ContactsClientConfigurationError("CONTACTS_API_NOT_CONFIGURED", `${resolution.issue ?? "The contacts API client is not configured."} ` + "Configure HASNA_CONTACTS_API_URL and a contacts API key; the client will not read or create a local SQLite database.");
|
|
230
259
|
}
|
|
231
260
|
const baseUrl = resolution.baseUrl;
|
|
261
|
+
const chainOptions = contactsResolverCredentials(env, credentials);
|
|
232
262
|
const request = async (method, path, body, opts) => {
|
|
233
263
|
const stamp = clientConfigurationStamp(env);
|
|
234
264
|
const snapshot = { ...env };
|
|
235
|
-
const current = resolveContactsClientTransport(name, snapshot);
|
|
265
|
+
const current = resolveContactsClientTransport(name, snapshot, chainOptions);
|
|
236
266
|
if (!current.configured || current.baseUrl !== baseUrl) {
|
|
237
267
|
throw new ContactsClientConfigurationError("CONTACTS_AUTHORITY_CHANGED", "Client authority changed or disappeared; construct a new client before sending data.");
|
|
238
268
|
}
|
|
239
|
-
const credential = resolveCredential(name, snapshot);
|
|
269
|
+
const credential = resolveCredential(name, snapshot, chainOptions);
|
|
240
270
|
if (!credential)
|
|
241
271
|
throw new ContactsClientConfigurationError("CONTACTS_API_NOT_CONFIGURED", "No credential is available.");
|
|
242
272
|
assertConfigurationUnchanged(env, stamp);
|
|
@@ -286,6 +316,39 @@ function stripUndefined(input) {
|
|
|
286
316
|
return out;
|
|
287
317
|
}
|
|
288
318
|
|
|
319
|
+
class ContactsApiResponseError extends Error {
|
|
320
|
+
constructor(operation, detail) {
|
|
321
|
+
super(`contacts: malformed /v1 response for ${operation}: ${detail}`);
|
|
322
|
+
this.name = "ContactsApiResponseError";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function requireAppendedContact(response, contactId, collection, matchKey, value) {
|
|
326
|
+
const operation = collection === "emails" ? "addEmailToContact" : "addPhoneToContact";
|
|
327
|
+
const contact = pick(response, "contact");
|
|
328
|
+
if (!contact || typeof contact !== "object" || Array.isArray(contact)) {
|
|
329
|
+
throw new ContactsApiResponseError(operation, "expected an object at response.contact");
|
|
330
|
+
}
|
|
331
|
+
if (contact.id !== contactId) {
|
|
332
|
+
throw new ContactsApiResponseError(operation, "response.contact.id did not match the requested contact");
|
|
333
|
+
}
|
|
334
|
+
const items = contact[collection];
|
|
335
|
+
if (!Array.isArray(items)) {
|
|
336
|
+
throw new ContactsApiResponseError(operation, `response.contact.${collection} was not an array`);
|
|
337
|
+
}
|
|
338
|
+
const normalize = collection === "emails" ? (input) => input.toLowerCase() : (input) => input;
|
|
339
|
+
const wanted = normalize(value);
|
|
340
|
+
const appended = items.find((item) => {
|
|
341
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
342
|
+
return false;
|
|
343
|
+
const record = item;
|
|
344
|
+
return typeof record.id === "string" && record.contact_id === contactId && typeof record[matchKey] === "string" && normalize(record[matchKey]) === wanted;
|
|
345
|
+
});
|
|
346
|
+
if (!appended) {
|
|
347
|
+
throw new ContactsApiResponseError(operation, `response.contact.${collection} did not contain the requested value`);
|
|
348
|
+
}
|
|
349
|
+
return contact;
|
|
350
|
+
}
|
|
351
|
+
|
|
289
352
|
class ApiStore {
|
|
290
353
|
client;
|
|
291
354
|
mode = "api";
|
|
@@ -355,11 +418,17 @@ class ApiStore {
|
|
|
355
418
|
async mergeContacts() {
|
|
356
419
|
return unavailable("mergeContacts");
|
|
357
420
|
}
|
|
358
|
-
async addEmailToContact() {
|
|
359
|
-
|
|
421
|
+
async addEmailToContact(contactId, email) {
|
|
422
|
+
const res = await this.patch(`/contacts/${this.enc(contactId)}`, {
|
|
423
|
+
emails_add: [stripUndefined(email)]
|
|
424
|
+
});
|
|
425
|
+
return requireAppendedContact(res, contactId, "emails", "address", email.address);
|
|
360
426
|
}
|
|
361
|
-
async addPhoneToContact() {
|
|
362
|
-
|
|
427
|
+
async addPhoneToContact(contactId, phone) {
|
|
428
|
+
const res = await this.patch(`/contacts/${this.enc(contactId)}`, {
|
|
429
|
+
phones_add: [stripUndefined(phone)]
|
|
430
|
+
});
|
|
431
|
+
return requireAppendedContact(res, contactId, "phones", "number", phone.number);
|
|
363
432
|
}
|
|
364
433
|
async archiveContact() {
|
|
365
434
|
return unavailable("archiveContact");
|
|
@@ -979,6 +1048,9 @@ class InvalidAudienceDefinitionError extends Error {
|
|
|
979
1048
|
this.name = "InvalidAudienceDefinitionError";
|
|
980
1049
|
}
|
|
981
1050
|
}
|
|
1051
|
+
// src/sdk/index.ts
|
|
1052
|
+
import { resolveCredential as resolveCredential2 } from "@hasna/contracts/client";
|
|
1053
|
+
|
|
982
1054
|
// src/sdk/v1.generated.ts
|
|
983
1055
|
class ApiError extends Error {
|
|
984
1056
|
status;
|
|
@@ -1239,15 +1311,11 @@ function validateBaseUrl(raw) {
|
|
|
1239
1311
|
throw new Error("ContactsV1Client baseUrl must not contain credentials.");
|
|
1240
1312
|
if (url.search || url.hash)
|
|
1241
1313
|
throw new Error("ContactsV1Client baseUrl must not contain a query or fragment.");
|
|
1242
|
-
|
|
1243
|
-
if (path && path !== "/v1") {
|
|
1244
|
-
throw new Error("ContactsV1Client baseUrl must be an authority root or end in /v1.");
|
|
1245
|
-
}
|
|
1246
|
-
url.pathname = "";
|
|
1314
|
+
url.pathname = url.pathname.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
1247
1315
|
return url.toString().replace(/\/+$/, "");
|
|
1248
1316
|
}
|
|
1249
1317
|
function validateApiKey(apiKey) {
|
|
1250
|
-
const key = apiKey.trim();
|
|
1318
|
+
const key = (apiKey ?? "").trim();
|
|
1251
1319
|
if (!key)
|
|
1252
1320
|
throw new Error("ContactsV1Client requires an API key.");
|
|
1253
1321
|
if (/[^\t\x20-\x7e]/.test(key)) {
|
|
@@ -1267,6 +1335,56 @@ class ContactsV1Client2 extends ContactsV1Client {
|
|
|
1267
1335
|
});
|
|
1268
1336
|
}
|
|
1269
1337
|
}
|
|
1338
|
+
var CONTACTS_APP_NAME = "contacts";
|
|
1339
|
+
function contactsSdkAuthorityPinMessage() {
|
|
1340
|
+
return "an explicit baseUrl requires an explicit apiKey. The SDK never attaches a credential that " + "resolved for a different authority: pass `apiKey` explicitly, or omit `baseUrl` and let the " + "@hasna/contracts chain resolve both halves together.";
|
|
1341
|
+
}
|
|
1342
|
+
var SDK_HOSTED_ONLY = "The contacts SDK is hosted-only and never falls back to local data.";
|
|
1343
|
+
function resolveSdkCredential(env, chainOptions) {
|
|
1344
|
+
const credential = resolveCredential2(CONTACTS_APP_NAME, env, chainOptions);
|
|
1345
|
+
if (!credential) {
|
|
1346
|
+
const diagnosis = resolveContactsClientTransport(CONTACTS_APP_NAME, env, chainOptions);
|
|
1347
|
+
throw new ContactsClientConfigurationError("CONTACTS_API_NOT_CONFIGURED", `${diagnosis.issue ?? "No contacts credential resolved."} ${SDK_HOSTED_ONLY}`);
|
|
1348
|
+
}
|
|
1349
|
+
if (credential.tier === "pointer") {
|
|
1350
|
+
throw new ContactsClientConfigurationError("CONTACTS_CREDENTIAL_POINTER_UNSUPPORTED", `The contacts SDK resolves credentials synchronously and cannot complete the secrets-vault pointer ` + `${credential.source} per request. Use a literal tier instead: an explicit apiKey, the Keychain item ` + `hasna.credentials.${CONTACTS_APP_NAME}.api-key, ~/.hasna/${CONTACTS_APP_NAME}/config/credentials, ` + `or HASNA_CONTACTS_API_KEY.`);
|
|
1351
|
+
}
|
|
1352
|
+
return credential.apiKey;
|
|
1353
|
+
}
|
|
1354
|
+
function createContactsClient(options = {}) {
|
|
1355
|
+
const { baseUrl, apiKey, env, profile, keychain, ...clientOptions } = options;
|
|
1356
|
+
if (baseUrl !== undefined) {
|
|
1357
|
+
if (!apiKey)
|
|
1358
|
+
throw new ContactsClientConfigurationError("CONTACTS_CREDENTIAL_PINNED", contactsSdkAuthorityPinMessage());
|
|
1359
|
+
return new ContactsV1Client2({ ...clientOptions, baseUrl, apiKey });
|
|
1360
|
+
}
|
|
1361
|
+
const envObject = env ?? (typeof process !== "undefined" ? process.env : {});
|
|
1362
|
+
const requested = {
|
|
1363
|
+
...apiKey !== undefined ? { apiKey } : {},
|
|
1364
|
+
...profile !== undefined ? { profile } : {},
|
|
1365
|
+
...keychain !== undefined ? { keychain } : {}
|
|
1366
|
+
};
|
|
1367
|
+
const chainOptions = contactsResolverCredentials(envObject, requested);
|
|
1368
|
+
const initialKey = resolveSdkCredential(envObject, chainOptions);
|
|
1369
|
+
const resolution = resolveContactsClientTransport(CONTACTS_APP_NAME, envObject, { ...chainOptions, apiKey: initialKey });
|
|
1370
|
+
if (!resolution.configured || !resolution.baseUrl) {
|
|
1371
|
+
throw new ContactsClientConfigurationError("CONTACTS_API_NOT_CONFIGURED", `${resolution.issue ?? "The contacts API client is not configured."} ${SDK_HOSTED_ONLY}`);
|
|
1372
|
+
}
|
|
1373
|
+
const pinnedBaseUrl = resolution.baseUrl;
|
|
1374
|
+
const baseFetch = clientOptions.fetch ?? globalThis.fetch;
|
|
1375
|
+
const chainFetch = async (input, init) => {
|
|
1376
|
+
const snapshot = { ...envObject };
|
|
1377
|
+
const freshKey = resolveSdkCredential(snapshot, chainOptions);
|
|
1378
|
+
const current = resolveContactsClientTransport(CONTACTS_APP_NAME, snapshot, { ...chainOptions, apiKey: freshKey });
|
|
1379
|
+
if (!current.configured || current.baseUrl !== pinnedBaseUrl) {
|
|
1380
|
+
throw new ContactsClientConfigurationError("CONTACTS_AUTHORITY_CHANGED", "Client authority changed or disappeared; construct a new client before sending data.");
|
|
1381
|
+
}
|
|
1382
|
+
const headers = new Headers(init?.headers);
|
|
1383
|
+
headers.set("x-api-key", freshKey);
|
|
1384
|
+
return baseFetch(input, { ...init, headers });
|
|
1385
|
+
};
|
|
1386
|
+
return new ContactsV1Client2({ ...clientOptions, baseUrl: pinnedBaseUrl, apiKey: initialKey, fetch: chainFetch });
|
|
1387
|
+
}
|
|
1270
1388
|
// src/lib/package-version.ts
|
|
1271
1389
|
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
1272
1390
|
import { dirname, join } from "path";
|
|
@@ -1864,6 +1982,8 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
|
|
|
1864
1982
|
export {
|
|
1865
1983
|
resetStoreCache,
|
|
1866
1984
|
getStore,
|
|
1985
|
+
createContactsClient,
|
|
1986
|
+
contactsSdkAuthorityPinMessage,
|
|
1867
1987
|
buildV1OpenApiDocument,
|
|
1868
1988
|
TagNotFoundError,
|
|
1869
1989
|
InvalidAudienceDefinitionError,
|
|
@@ -19,8 +19,8 @@ export declare const AudiencePredicateContractSchema: z.ZodEffects<z.ZodObject<{
|
|
|
19
19
|
values: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
|
|
20
20
|
}, "strict", z.ZodTypeAny, {
|
|
21
21
|
values: (string | number | boolean)[];
|
|
22
|
-
kind: "tag" | "attribute" | "group";
|
|
23
22
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
23
|
+
kind: "tag" | "attribute" | "group";
|
|
24
24
|
key?: string | undefined;
|
|
25
25
|
value?: string | number | boolean | undefined;
|
|
26
26
|
}, {
|
|
@@ -31,8 +31,8 @@ export declare const AudiencePredicateContractSchema: z.ZodEffects<z.ZodObject<{
|
|
|
31
31
|
op?: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists" | undefined;
|
|
32
32
|
}>, {
|
|
33
33
|
values: (string | number | boolean)[];
|
|
34
|
-
kind: "tag" | "attribute" | "group";
|
|
35
34
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
35
|
+
kind: "tag" | "attribute" | "group";
|
|
36
36
|
key?: string | undefined;
|
|
37
37
|
value?: string | number | boolean | undefined;
|
|
38
38
|
}, {
|
|
@@ -52,8 +52,8 @@ export declare const AudienceDefinitionContractSchema: z.ZodObject<{
|
|
|
52
52
|
values: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
|
|
53
53
|
}, "strict", z.ZodTypeAny, {
|
|
54
54
|
values: (string | number | boolean)[];
|
|
55
|
-
kind: "tag" | "attribute" | "group";
|
|
56
55
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
56
|
+
kind: "tag" | "attribute" | "group";
|
|
57
57
|
key?: string | undefined;
|
|
58
58
|
value?: string | number | boolean | undefined;
|
|
59
59
|
}, {
|
|
@@ -64,8 +64,8 @@ export declare const AudienceDefinitionContractSchema: z.ZodObject<{
|
|
|
64
64
|
op?: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists" | undefined;
|
|
65
65
|
}>, {
|
|
66
66
|
values: (string | number | boolean)[];
|
|
67
|
-
kind: "tag" | "attribute" | "group";
|
|
68
67
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
68
|
+
kind: "tag" | "attribute" | "group";
|
|
69
69
|
key?: string | undefined;
|
|
70
70
|
value?: string | number | boolean | undefined;
|
|
71
71
|
}, {
|
|
@@ -79,8 +79,8 @@ export declare const AudienceDefinitionContractSchema: z.ZodObject<{
|
|
|
79
79
|
match: "all" | "any";
|
|
80
80
|
predicates: {
|
|
81
81
|
values: (string | number | boolean)[];
|
|
82
|
-
kind: "tag" | "attribute" | "group";
|
|
83
82
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
83
|
+
kind: "tag" | "attribute" | "group";
|
|
84
84
|
key?: string | undefined;
|
|
85
85
|
value?: string | number | boolean | undefined;
|
|
86
86
|
}[];
|
|
@@ -113,8 +113,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
|
|
|
113
113
|
values: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
|
|
114
114
|
}, "strict", z.ZodTypeAny, {
|
|
115
115
|
values: (string | number | boolean)[];
|
|
116
|
-
kind: "tag" | "attribute" | "group";
|
|
117
116
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
117
|
+
kind: "tag" | "attribute" | "group";
|
|
118
118
|
key?: string | undefined;
|
|
119
119
|
value?: string | number | boolean | undefined;
|
|
120
120
|
}, {
|
|
@@ -125,8 +125,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
|
|
|
125
125
|
op?: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists" | undefined;
|
|
126
126
|
}>, {
|
|
127
127
|
values: (string | number | boolean)[];
|
|
128
|
-
kind: "tag" | "attribute" | "group";
|
|
129
128
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
129
|
+
kind: "tag" | "attribute" | "group";
|
|
130
130
|
key?: string | undefined;
|
|
131
131
|
value?: string | number | boolean | undefined;
|
|
132
132
|
}, {
|
|
@@ -140,8 +140,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
|
|
|
140
140
|
match: "all" | "any";
|
|
141
141
|
predicates: {
|
|
142
142
|
values: (string | number | boolean)[];
|
|
143
|
-
kind: "tag" | "attribute" | "group";
|
|
144
143
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
144
|
+
kind: "tag" | "attribute" | "group";
|
|
145
145
|
key?: string | undefined;
|
|
146
146
|
value?: string | number | boolean | undefined;
|
|
147
147
|
}[];
|
|
@@ -167,8 +167,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
|
|
|
167
167
|
match: "all" | "any";
|
|
168
168
|
predicates: {
|
|
169
169
|
values: (string | number | boolean)[];
|
|
170
|
-
kind: "tag" | "attribute" | "group";
|
|
171
170
|
op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
|
|
171
|
+
kind: "tag" | "attribute" | "group";
|
|
172
172
|
key?: string | undefined;
|
|
173
173
|
value?: string | number | boolean | undefined;
|
|
174
174
|
}[];
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ContactWithDetails } from "../types/index.js";
|
|
2
|
+
export declare const CONTACTS_COMPACT_LIMIT = 20;
|
|
3
|
+
export declare const CONTACTS_MAX_LIMIT = 500;
|
|
4
|
+
export declare function normalizeContactsLimit(value: unknown, fallback?: number): number;
|
|
5
|
+
export declare function normalizeContactsOffset(value: unknown): number;
|
|
6
|
+
export declare function summarizeContact(contact: ContactWithDetails): {
|
|
7
|
+
id: string;
|
|
8
|
+
display_name: string;
|
|
9
|
+
job_title: string | null;
|
|
10
|
+
company: {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
} | null;
|
|
14
|
+
primary_email: string;
|
|
15
|
+
primary_phone: string;
|
|
16
|
+
status: import("../index.js").ContactStatus;
|
|
17
|
+
follow_up_at: string | null;
|
|
18
|
+
last_contacted_at: string | null;
|
|
19
|
+
archived: boolean;
|
|
20
|
+
sensitivity: import("../index.js").Sensitivity;
|
|
21
|
+
tags: {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
}[];
|
|
25
|
+
updated_at: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function compareContactsByDisplayNameAndId(left: Pick<ContactWithDetails, "display_name" | "id">, right: Pick<ContactWithDetails, "display_name" | "id">): number;
|
|
28
|
+
export declare function compactContactsPage(contacts: ContactWithDetails[], options: {
|
|
29
|
+
total: number;
|
|
30
|
+
limit: number;
|
|
31
|
+
offset: number;
|
|
32
|
+
}): {
|
|
33
|
+
contacts: {
|
|
34
|
+
id: string;
|
|
35
|
+
display_name: string;
|
|
36
|
+
job_title: string | null;
|
|
37
|
+
company: {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
} | null;
|
|
41
|
+
primary_email: string;
|
|
42
|
+
primary_phone: string;
|
|
43
|
+
status: import("../index.js").ContactStatus;
|
|
44
|
+
follow_up_at: string | null;
|
|
45
|
+
last_contacted_at: string | null;
|
|
46
|
+
archived: boolean;
|
|
47
|
+
sensitivity: import("../index.js").Sensitivity;
|
|
48
|
+
tags: {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
}[];
|
|
52
|
+
updated_at: string;
|
|
53
|
+
}[];
|
|
54
|
+
count: number;
|
|
55
|
+
total: number;
|
|
56
|
+
limit: number;
|
|
57
|
+
cursor: number;
|
|
58
|
+
next_cursor: number | null;
|
|
59
|
+
has_more: boolean;
|
|
60
|
+
compact: true;
|
|
61
|
+
sort: {
|
|
62
|
+
fields: string[];
|
|
63
|
+
direction: "asc";
|
|
64
|
+
};
|
|
65
|
+
hint: string;
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=compact-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact-output.d.ts","sourceRoot":"","sources":["../../src/lib/compact-output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAyB,GAAG,MAAM,CAIhG;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI9D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;;;EAgB3D;AAED,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI,CAAC,EACrD,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI,CAAC,GACrD,MAAM,CAER;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,kBAAkB,EAAE,EAC9B,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/mcp/handlers/core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/mcp/handlers/core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4C9C,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA0YpD,CAAC"}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
|
|
3
|
+
import { type ContactsMcpProfile } from "./profile.js";
|
|
4
|
+
export declare function buildServer(profile?: ContactsMcpProfile): McpServer;
|
|
5
|
+
/**
|
|
6
|
+
* Classify early-exit arguments before any http-mode parse, server build, or
|
|
7
|
+
* stdio bind. `--help` / `--version` answer with rc=0 and the MCP server never
|
|
8
|
+
* starts: previously `contacts-mcp --version` fell through to the stdio
|
|
9
|
+
* JSON-RPC loop and printed "running on stdio" instead of the version
|
|
10
|
+
* (hasna/apps#1720 validation, the binds-before-version class).
|
|
11
|
+
*/
|
|
12
|
+
export declare function handleEarlyArgs(argv: string[]): "help" | "version" | "start";
|
|
13
|
+
export declare function mcpUsage(): string;
|
|
4
14
|
export declare function isDirectMcpEntry(entry?: string): boolean;
|
|
5
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,OAAO,EAA6B,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAYlF,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAA2B,GAAG,SAAS,CAQ3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAI5E;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAWjC;AA4CD,wBAAgB,gBAAgB,CAAC,KAAK,SAAkB,GAAG,OAAO,CAIjE"}
|