@hasna/contacts 0.6.36 → 0.7.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.
Files changed (50) hide show
  1. package/README.md +53 -69
  2. package/dist/cli/commands/advanced.d.ts.map +1 -1
  3. package/dist/cli/commands/core.d.ts +1 -1
  4. package/dist/cli/commands/core.d.ts.map +1 -1
  5. package/dist/cli/commands/crm.d.ts.map +1 -1
  6. package/dist/cli/index.js +9158 -39958
  7. package/dist/cli/legacy.d.ts +18 -0
  8. package/dist/cli/legacy.d.ts.map +1 -0
  9. package/dist/cli/status-domain.preload.d.ts +2 -0
  10. package/dist/cli/status-domain.preload.d.ts.map +1 -0
  11. package/dist/cli/storage.d.ts.map +1 -1
  12. package/dist/cloud/client-config.d.ts +6 -0
  13. package/dist/cloud/client-config.d.ts.map +1 -0
  14. package/dist/cloud/http-storage.d.ts +40 -69
  15. package/dist/cloud/http-storage.d.ts.map +1 -1
  16. package/dist/db/paths.d.ts +13 -7
  17. package/dist/db/paths.d.ts.map +1 -1
  18. package/dist/generated/storage-kit/index.d.ts +0 -1
  19. package/dist/generated/storage-kit/index.d.ts.map +1 -1
  20. package/dist/generated/storage-kit/pool.d.ts +13 -3
  21. package/dist/generated/storage-kit/pool.d.ts.map +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +373 -5713
  24. package/dist/lib/images.d.ts.map +1 -1
  25. package/dist/mcp/handlers/advanced.d.ts.map +1 -1
  26. package/dist/mcp/handlers/core.d.ts +1 -1
  27. package/dist/mcp/index.js +461 -5901
  28. package/dist/mcp/storage-tools.d.ts.map +1 -1
  29. package/dist/sdk/index.d.ts +15 -13
  30. package/dist/sdk/index.d.ts.map +1 -1
  31. package/dist/sdk/index.js +44 -1
  32. package/dist/server/cloud.d.ts +6 -7
  33. package/dist/server/cloud.d.ts.map +1 -1
  34. package/dist/server/index.d.ts +2 -1
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +3744 -35305
  37. package/dist/server/security.d.ts +1 -1
  38. package/dist/server/security.d.ts.map +1 -1
  39. package/dist/server/serve.d.ts.map +1 -1
  40. package/dist/store/index.d.ts +66 -93
  41. package/dist/store/index.d.ts.map +1 -1
  42. package/dist/types/store-dto.d.ts +273 -0
  43. package/dist/types/store-dto.d.ts.map +1 -0
  44. package/hasna.contract.json +63 -10
  45. package/package.json +23 -14
  46. package/dashboard/dist/assets/index-0l6aQb1t.css +0 -1
  47. package/dashboard/dist/assets/index-opnZdkVD.js +0 -229
  48. package/dashboard/dist/index.html +0 -13
  49. package/dist/generated/storage-kit/mode.d.ts +0 -48
  50. package/dist/generated/storage-kit/mode.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"storage-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/storage-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0CzE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4CpE"}
1
+ {"version":3,"file":"storage-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/storage-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8BzE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAapE"}
@@ -1,16 +1,18 @@
1
+ /** @hasna/contacts SDK — explicit authenticated HTTPS `/v1` client. */
2
+ import { ContactsV1Client as GeneratedContactsV1Client, ApiError, type ContactsV1ClientOptions as GeneratedContactsV1ClientOptions } from "./v1.generated.js";
3
+ export interface ContactsV1ClientOptions extends Omit<GeneratedContactsV1ClientOptions, "baseUrl" | "apiKey"> {
4
+ /** Explicit HTTPS service authority. No default is composed. */
5
+ baseUrl: string;
6
+ /** API key sent to the configured authority. Required and never logged. */
7
+ apiKey: string;
8
+ }
1
9
  /**
2
- * @hasna/contacts SDK typed `/v1` cloud client.
3
- *
4
- * Generated from the serve OpenAPI document (src/server/openapi.ts).
5
- * Regenerate with `bun run scripts/generate-sdk.ts`.
6
- *
7
- * import { ContactsV1Client } from "@hasna/contacts/sdk";
8
- * const client = new ContactsV1Client({
9
- * baseUrl: process.env.CONTACTS_API_URL!, // self_hosted service URL
10
- * apiKey: process.env.CONTACTS_API_KEY!, // contracts-issued key
11
- * });
12
- * const { contacts } = await client.listContacts({ limit: 20 });
10
+ * Validated wrapper around the generated API surface. Redirects are never
11
+ * followed, so credentials cannot cross to another authority.
13
12
  */
14
- export { ContactsV1Client, ApiError as ContactsV1ApiError } from "./v1.generated.js";
15
- export type { ContactsV1ClientOptions, Contact as ContactsV1Contact, Company as ContactsV1Company, Tag as ContactsV1Tag, CreateContactInput as ContactsV1CreateContactInput, UpdateContactInput as ContactsV1UpdateContactInput, CreateCompanyInput as ContactsV1CreateCompanyInput, UpdateCompanyInput as ContactsV1UpdateCompanyInput, CreateTagInput as ContactsV1CreateTagInput, UpdateTagInput as ContactsV1UpdateTagInput, ProjectIdsInput as ContactsV1ProjectIdsInput, ContactProjectMembershipSnapshot as ContactsV1ProjectMembershipSnapshot, ContactProjectMembershipMutationInput as ContactsV1ProjectMembershipMutationInput, ContactProjectMembershipMutationResult as ContactsV1ProjectMembershipMutationResult, ContactProjectMembershipListResult as ContactsV1ProjectMembershipListResult, } from "./v1.generated.js";
13
+ export declare class ContactsV1Client extends GeneratedContactsV1Client {
14
+ constructor(options: ContactsV1ClientOptions);
15
+ }
16
+ export { ApiError as ContactsV1ApiError };
17
+ export type { Contact as ContactsV1Contact, Company as ContactsV1Company, Tag as ContactsV1Tag, CreateContactInput as ContactsV1CreateContactInput, UpdateContactInput as ContactsV1UpdateContactInput, CreateCompanyInput as ContactsV1CreateCompanyInput, UpdateCompanyInput as ContactsV1UpdateCompanyInput, CreateTagInput as ContactsV1CreateTagInput, UpdateTagInput as ContactsV1UpdateTagInput, ProjectIdsInput as ContactsV1ProjectIdsInput, ContactProjectMembershipSnapshot as ContactsV1ProjectMembershipSnapshot, ContactProjectMembershipMutationInput as ContactsV1ProjectMembershipMutationInput, ContactProjectMembershipMutationResult as ContactsV1ProjectMembershipMutationResult, ContactProjectMembershipListResult as ContactsV1ProjectMembershipListResult, } from "./v1.generated.js";
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sdk/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,gBAAgB,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACrF,YAAY,EACV,uBAAuB,EACvB,OAAO,IAAI,iBAAiB,EAC5B,OAAO,IAAI,iBAAiB,EAC5B,GAAG,IAAI,aAAa,EACpB,kBAAkB,IAAI,4BAA4B,EAClD,kBAAkB,IAAI,4BAA4B,EAClD,kBAAkB,IAAI,4BAA4B,EAClD,kBAAkB,IAAI,4BAA4B,EAClD,cAAc,IAAI,wBAAwB,EAC1C,cAAc,IAAI,wBAAwB,EAC1C,eAAe,IAAI,yBAAyB,EAC5C,gCAAgC,IAAI,mCAAmC,EACvE,qCAAqC,IAAI,wCAAwC,EACjF,sCAAsC,IAAI,yCAAyC,EACnF,kCAAkC,IAAI,qCAAqC,GAC5E,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sdk/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,OAAO,EACL,gBAAgB,IAAI,yBAAyB,EAC7C,QAAQ,EACR,KAAK,uBAAuB,IAAI,gCAAgC,EACjE,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,uBACf,SAAQ,IAAI,CAAC,gCAAgC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACpE,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AA8BD;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,yBAAyB;gBACjD,OAAO,EAAE,uBAAuB;CAS7C;AAED,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,CAAC;AAC1C,YAAY,EACV,OAAO,IAAI,iBAAiB,EAC5B,OAAO,IAAI,iBAAiB,EAC5B,GAAG,IAAI,aAAa,EACpB,kBAAkB,IAAI,4BAA4B,EAClD,kBAAkB,IAAI,4BAA4B,EAClD,kBAAkB,IAAI,4BAA4B,EAClD,kBAAkB,IAAI,4BAA4B,EAClD,cAAc,IAAI,wBAAwB,EAC1C,cAAc,IAAI,wBAAwB,EAC1C,eAAe,IAAI,yBAAyB,EAC5C,gCAAgC,IAAI,mCAAmC,EACvE,qCAAqC,IAAI,wCAAwC,EACjF,sCAAsC,IAAI,yCAAyC,EACnF,kCAAkC,IAAI,qCAAqC,GAC5E,MAAM,mBAAmB,CAAC"}
package/dist/sdk/index.js CHANGED
@@ -244,7 +244,50 @@ class ContactsV1Client {
244
244
  });
245
245
  }
246
246
  }
247
+
248
+ // src/sdk/index.ts
249
+ function validateBaseUrl(raw) {
250
+ let url;
251
+ try {
252
+ url = new URL(raw);
253
+ } catch {
254
+ throw new Error("ContactsV1Client baseUrl must be an absolute HTTPS URL.");
255
+ }
256
+ if (url.protocol !== "https:")
257
+ throw new Error("ContactsV1Client baseUrl must use HTTPS.");
258
+ if (url.username || url.password)
259
+ throw new Error("ContactsV1Client baseUrl must not contain credentials.");
260
+ if (url.search || url.hash)
261
+ throw new Error("ContactsV1Client baseUrl must not contain a query or fragment.");
262
+ const path = url.pathname.replace(/\/+$/, "");
263
+ if (path && path !== "/v1") {
264
+ throw new Error("ContactsV1Client baseUrl must be an authority root or end in /v1.");
265
+ }
266
+ url.pathname = "";
267
+ return url.toString().replace(/\/+$/, "");
268
+ }
269
+ function validateApiKey(apiKey) {
270
+ const key = apiKey.trim();
271
+ if (!key)
272
+ throw new Error("ContactsV1Client requires an API key.");
273
+ if (/[^\t\x20-\x7e]/.test(key)) {
274
+ throw new Error("ContactsV1Client API key contains bytes that are invalid in an HTTP header.");
275
+ }
276
+ return key;
277
+ }
278
+
279
+ class ContactsV1Client2 extends ContactsV1Client {
280
+ constructor(options) {
281
+ const fetchImpl = options.fetch ?? globalThis.fetch;
282
+ super({
283
+ ...options,
284
+ baseUrl: validateBaseUrl(options.baseUrl),
285
+ apiKey: validateApiKey(options.apiKey),
286
+ fetch: (input, init) => fetchImpl(input, { ...init, redirect: "manual" })
287
+ });
288
+ }
289
+ }
247
290
  export {
248
- ContactsV1Client,
291
+ ContactsV1Client2 as ContactsV1Client,
249
292
  ApiError as ContactsV1ApiError
250
293
  };
@@ -1,23 +1,22 @@
1
1
  /**
2
- * Cloud (A1 pure-remote) service wiring for `contacts-serve`.
2
+ * PostgreSQL service wiring for `contacts-serve`.
3
3
  *
4
4
  * This module powers the versioned `/v1` API and its API-key auth. Per Amendment
5
5
  * A1 the serve process reads and writes the shared RDS Postgres DIRECTLY through
6
6
  * the vendored @hasna/contracts storage kit — there is NO local sync/cache in
7
7
  * the service. Everything is lazy: nothing touches Postgres or crypto until the
8
- * first `/v1` / `/ready` request, so the local-first CLI/dashboard SQLite paths
9
- * keep ZERO cloud dependencies.
8
+ * first `/v1` / `/ready` request. Public clients never import this server-only
9
+ * PostgreSQL boundary.
10
10
  */
11
11
  import { ApiKeyStore, type ApiKeyVerifier } from "@hasna/contracts/auth";
12
- import type { PoolQueryClient } from "../generated/storage-kit/query.js";
12
+ import { type PoolQueryClient } from "../generated/storage-kit/query.js";
13
13
  export declare const CONTACTS_APP_SLUG = "contacts";
14
+ export declare function validatePostgresDatabaseUrl(value: string): string;
14
15
  /** Resolve the remote DATABASE_URL from the supported env vars (priority order). */
15
16
  export declare function resolveCloudDatabaseUrl(env?: NodeJS.ProcessEnv): string | undefined;
16
17
  /** Resolve the HMAC signing secret used to verify API keys. */
17
18
  export declare function resolveSigningSecret(env?: NodeJS.ProcessEnv): string | undefined;
18
- /** True when this process is configured to serve the cloud `/v1` API.
19
- * Explicit remote mode remains cloud even when its DSN is missing so readiness
20
- * fails closed instead of presenting the process as a healthy local server. */
19
+ /** True when this server process has its PostgreSQL backend configured. */
21
20
  export declare function isCloudModeEnabled(env?: NodeJS.ProcessEnv): boolean;
22
21
  /** The vendored-kit Postgres pool client backing every `/v1` handler. */
23
22
  export declare function getCloudClient(): PoolQueryClient;
@@ -1 +1 @@
1
- {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/server/cloud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAgB,WAAW,EAAE,KAAK,cAAc,EAAwB,MAAM,uBAAuB,CAAC;AAE7G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAIzE,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAE5C,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAOhG;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAO7F;AAED;;+EAE+E;AAC/E,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAGhF;AAQD,yEAAyE;AACzE,wBAAgB,cAAc,IAAI,eAAe,CA2BhD;AAYD,wBAAgB,cAAc,IAAI,WAAW,CAI5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAejD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUvD;AAED;;;;;;;;;GASG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAYjE;AAED,iEAAiE;AACjE,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAGlD;AAED,4BAA4B;AAC5B,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAOhD"}
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/server/cloud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAgB,WAAW,EAAE,KAAK,cAAc,EAAwB,MAAM,uBAAuB,CAAC;AAE7G,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAI5F,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAU5C,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASjE;AAED,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAGhG;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAE7F;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEhF;AAQD,yEAAyE;AACzE,wBAAgB,cAAc,IAAI,eAAe,CAoBhD;AAYD,wBAAgB,cAAc,IAAI,WAAW,CAI5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAejD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUvD;AAED;;;;;;;;;GASG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAYjE;AAED,iEAAiE;AACjE,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAGlD;AAED,4BAA4B;AAC5B,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAOhD"}
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env bun
2
- export {};
2
+ /** Canonical contacts-serve entrypoint: authenticated `/v1` over PostgreSQL. */
3
+ import "./cloud-index.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA,gFAAgF;AAChF,OAAO,kBAAkB,CAAC"}