@vess-id/ai-identity 0.10.0 → 0.12.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 (34) hide show
  1. package/README.md +0 -16
  2. package/dist/client.d.ts +0 -14
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/index.d.mts +456 -153
  5. package/dist/index.d.ts +2 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +172 -206
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +158 -205
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/internal-signature/__tests__/canonical.spec.d.ts +2 -0
  12. package/dist/internal-signature/__tests__/canonical.spec.d.ts.map +1 -0
  13. package/dist/internal-signature/__tests__/signer-roundtrip.spec.d.ts +2 -0
  14. package/dist/internal-signature/__tests__/signer-roundtrip.spec.d.ts.map +1 -0
  15. package/dist/internal-signature/__tests__/signer.spec.d.ts +2 -0
  16. package/dist/internal-signature/__tests__/signer.spec.d.ts.map +1 -0
  17. package/dist/internal-signature/canonical.d.ts +80 -0
  18. package/dist/internal-signature/canonical.d.ts.map +1 -0
  19. package/dist/internal-signature/index.d.ts +17 -0
  20. package/dist/internal-signature/index.d.ts.map +1 -0
  21. package/dist/internal-signature/signer.d.ts +76 -0
  22. package/dist/internal-signature/signer.d.ts.map +1 -0
  23. package/dist/registry/action-registry-json.d.ts +114 -0
  24. package/dist/registry/action-registry-json.d.ts.map +1 -1
  25. package/dist/registry/index.d.ts +2 -0
  26. package/dist/registry/index.d.ts.map +1 -1
  27. package/dist/registry/reauth-constants.d.ts +33 -0
  28. package/dist/registry/reauth-constants.d.ts.map +1 -0
  29. package/dist/vp/kb-jwt-builder.d.ts +89 -0
  30. package/dist/vp/kb-jwt-builder.d.ts.map +1 -0
  31. package/dist/vp/vp-manager.d.ts.map +1 -1
  32. package/package.json +20 -26
  33. package/dist/memory/memory-manager.d.ts +0 -77
  34. package/dist/memory/memory-manager.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1508,6 +1508,56 @@ var VCManager = class {
1508
1508
 
1509
1509
  // src/vp/vp-manager.ts
1510
1510
  import { digest as digest2 } from "@sd-jwt/crypto-nodejs";
1511
+
1512
+ // src/vp/kb-jwt-builder.ts
1513
+ var KB_JWT_DEFAULT_LIFETIME_SECONDS = 300;
1514
+ function buildKbJwtPayload(args, deps = {}) {
1515
+ const now = deps.now ?? Date.now;
1516
+ const iatSeconds = Math.floor(now() / 1e3);
1517
+ const kbExpCap = iatSeconds + KB_JWT_DEFAULT_LIFETIME_SECONDS;
1518
+ const vcExp = readVcExpSeconds(args.vcCredential);
1519
+ const expSeconds = vcExp !== void 0 ? Math.min(kbExpCap, vcExp) : kbExpCap;
1520
+ if (expSeconds <= iatSeconds) {
1521
+ throw new Error(
1522
+ `VC has expired: cannot issue KB-JWT (vc.exp=${vcExp}, now=${iatSeconds})`
1523
+ );
1524
+ }
1525
+ return {
1526
+ iss: args.holderDid,
1527
+ aud: normalizeDomain(args.audience),
1528
+ nonce: args.nonce,
1529
+ iat: iatSeconds,
1530
+ exp: expSeconds
1531
+ };
1532
+ }
1533
+ function readVcExpSeconds(sdJwtVc) {
1534
+ try {
1535
+ const jwtPart = sdJwtVc.split("~")[0];
1536
+ const payloadB64 = jwtPart.split(".")[1];
1537
+ if (!payloadB64) return void 0;
1538
+ const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
1539
+ return typeof payload.exp === "number" ? payload.exp : void 0;
1540
+ } catch {
1541
+ return void 0;
1542
+ }
1543
+ }
1544
+ function normalizeDomain(domain) {
1545
+ if (!domain) return domain;
1546
+ let urlStr;
1547
+ if (/^https?:\/\//i.test(domain)) {
1548
+ urlStr = domain;
1549
+ } else {
1550
+ const scheme = /^localhost(:\d+)?$/i.test(domain) ? "http" : "https";
1551
+ urlStr = `${scheme}://${domain}`;
1552
+ }
1553
+ try {
1554
+ return new URL(urlStr).origin;
1555
+ } catch {
1556
+ return domain;
1557
+ }
1558
+ }
1559
+
1560
+ // src/vp/vp-manager.ts
1511
1561
  var VPManager = class {
1512
1562
  keyManager;
1513
1563
  constructor(keyManager) {
@@ -1531,12 +1581,12 @@ var VPManager = class {
1531
1581
  presentableKeys.forEach((key) => {
1532
1582
  presentationFrame[key] = true;
1533
1583
  });
1534
- const kbJwtPayload = {
1535
- iss: options.holderDid,
1536
- aud: options.domain,
1584
+ const kbJwtPayload = buildKbJwtPayload({
1585
+ holderDid: options.holderDid,
1586
+ audience: options.domain,
1537
1587
  nonce: options.challenge,
1538
- iat: Math.floor(Date.now() / 1e3)
1539
- };
1588
+ vcCredential: sdJwtVC
1589
+ });
1540
1590
  const presentation = await sdJwtInstance.present(sdJwtVC, presentationFrame, {
1541
1591
  kb: { payload: kbJwtPayload }
1542
1592
  });
@@ -1986,172 +2036,6 @@ var ToolManager = class {
1986
2036
  }
1987
2037
  };
1988
2038
 
1989
- // src/memory/memory-manager.ts
1990
- var MemoryManager = class {
1991
- vpManager;
1992
- proxyApiUrl;
1993
- constructor(vpManager) {
1994
- this.vpManager = vpManager || new VPManager();
1995
- const config = getConfig();
1996
- this.proxyApiUrl = config.proxyApi?.baseUrl || "http://localhost:3000";
1997
- }
1998
- /**
1999
- * Write a document to memory
2000
- */
2001
- async write(content, options) {
2002
- const domain = new URL(this.proxyApiUrl).hostname;
2003
- const challenge = this.generateChallenge();
2004
- const vpJwt = await this.vpManager.create(options.vcs, {
2005
- holderDid: options.holderDid,
2006
- challenge,
2007
- domain,
2008
- purpose: "write"
2009
- });
2010
- const response = await fetch(`${this.proxyApiUrl}/api/v1/memory/${options.namespace}/doc`, {
2011
- method: "POST",
2012
- headers: {
2013
- "Content-Type": "application/json",
2014
- Authorization: `Bearer ${vpJwt}`
2015
- },
2016
- body: JSON.stringify({
2017
- content,
2018
- metadata: options.metadata,
2019
- challenge
2020
- })
2021
- });
2022
- if (!response.ok) {
2023
- const error = await response.text();
2024
- throw new Error(`Failed to write to memory: ${error}`);
2025
- }
2026
- return response.json();
2027
- }
2028
- /**
2029
- * Query memory with vector search
2030
- */
2031
- async query(query, options) {
2032
- const domain = new URL(this.proxyApiUrl).hostname;
2033
- const challenge = this.generateChallenge();
2034
- const vpJwt = await this.vpManager.create(options.vcs, {
2035
- holderDid: options.holderDid,
2036
- challenge,
2037
- domain,
2038
- purpose: "read"
2039
- });
2040
- const queryParams = {
2041
- query,
2042
- namespace: options.namespace,
2043
- limit: options.limit || 10,
2044
- filter: options.filter
2045
- };
2046
- const namespace = options.namespace || "default";
2047
- const response = await fetch(`${this.proxyApiUrl}/api/v1/memory/${namespace}/query`, {
2048
- method: "POST",
2049
- headers: {
2050
- "Content-Type": "application/json",
2051
- Authorization: `Bearer ${vpJwt}`
2052
- },
2053
- body: JSON.stringify({
2054
- ...queryParams,
2055
- challenge
2056
- })
2057
- });
2058
- if (!response.ok) {
2059
- const error = await response.text();
2060
- throw new Error(`Failed to query memory: ${error}`);
2061
- }
2062
- return response.json();
2063
- }
2064
- /**
2065
- * Delete a document from memory
2066
- */
2067
- async delete(documentId, options) {
2068
- const domain = new URL(this.proxyApiUrl).hostname;
2069
- const challenge = this.generateChallenge();
2070
- const vpJwt = await this.vpManager.create(options.vcs, {
2071
- holderDid: options.holderDid,
2072
- challenge,
2073
- domain,
2074
- purpose: "delete"
2075
- });
2076
- const response = await fetch(
2077
- `${this.proxyApiUrl}/api/v1/memory/${options.namespace}/${documentId}`,
2078
- {
2079
- method: "DELETE",
2080
- headers: {
2081
- Authorization: `Bearer ${vpJwt}`,
2082
- "X-Challenge": challenge
2083
- }
2084
- }
2085
- );
2086
- if (!response.ok) {
2087
- const error = await response.text();
2088
- throw new Error(`Failed to delete from memory: ${error}`);
2089
- }
2090
- }
2091
- /**
2092
- * List documents in a namespace
2093
- */
2094
- async list(options) {
2095
- const domain = new URL(this.proxyApiUrl).hostname;
2096
- const challenge = this.generateChallenge();
2097
- const vpJwt = await this.vpManager.create(options.vcs, {
2098
- holderDid: options.holderDid,
2099
- challenge,
2100
- domain,
2101
- purpose: "read"
2102
- });
2103
- const params = new URLSearchParams({
2104
- limit: (options.limit || 100).toString(),
2105
- offset: (options.offset || 0).toString()
2106
- });
2107
- const response = await fetch(
2108
- `${this.proxyApiUrl}/api/v1/memory/${options.namespace}/list?${params}`,
2109
- {
2110
- headers: {
2111
- Authorization: `Bearer ${vpJwt}`,
2112
- "X-Challenge": challenge
2113
- }
2114
- }
2115
- );
2116
- if (!response.ok) {
2117
- const error = await response.text();
2118
- throw new Error(`Failed to list memory documents: ${error}`);
2119
- }
2120
- return response.json();
2121
- }
2122
- /**
2123
- * Check if VCs authorize memory access
2124
- */
2125
- async checkAuthorization(vcs, action, resource) {
2126
- for (const vcJwt of vcs) {
2127
- try {
2128
- const parts = vcJwt.split(".");
2129
- const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
2130
- const vcResource = payload.credentialSubject?.resource;
2131
- const vcActions = payload.credentialSubject?.actions || [];
2132
- if (this.matchResource(vcResource, resource)) {
2133
- if (vcActions.includes(action)) {
2134
- return true;
2135
- }
2136
- }
2137
- } catch {
2138
- continue;
2139
- }
2140
- }
2141
- return false;
2142
- }
2143
- matchResource(vcResource, requiredResource) {
2144
- if (vcResource.endsWith("/*")) {
2145
- const prefix = vcResource.slice(0, -2);
2146
- return requiredResource.startsWith(prefix);
2147
- }
2148
- return vcResource === requiredResource;
2149
- }
2150
- generateChallenge() {
2151
- return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
2152
- }
2153
- };
2154
-
2155
2039
  // src/grant/grant-manager.ts
2156
2040
  var GrantManager = class {
2157
2041
  constructor(_vpManager) {
@@ -2393,7 +2277,6 @@ var AIdentityClient = class {
2393
2277
  vc;
2394
2278
  vp;
2395
2279
  tool;
2396
- memory;
2397
2280
  grant;
2398
2281
  keyManager;
2399
2282
  currentAgent;
@@ -2407,7 +2290,6 @@ var AIdentityClient = class {
2407
2290
  this.vc = new VCManager(this.keyManager, this.agent, this.user);
2408
2291
  this.vp = new VPManager(this.keyManager);
2409
2292
  this.tool = new ToolManager(this.vp);
2410
- this.memory = new MemoryManager(this.vp);
2411
2293
  this.grant = new GrantManager(this.vp);
2412
2294
  }
2413
2295
  /**
@@ -2491,35 +2373,6 @@ var AIdentityClient = class {
2491
2373
  holderDid
2492
2374
  });
2493
2375
  }
2494
- /**
2495
- * Write to memory with automatic VP creation
2496
- */
2497
- async writeMemory(content, namespace, vcs, metadata) {
2498
- const holderDid = this.currentAgent?.did;
2499
- if (!holderDid) {
2500
- throw new Error("No current agent available");
2501
- }
2502
- return this.memory.write(content, {
2503
- namespace,
2504
- metadata,
2505
- vcs,
2506
- holderDid
2507
- });
2508
- }
2509
- /**
2510
- * Query memory with automatic VP creation
2511
- */
2512
- async queryMemory(query, vcs, options) {
2513
- const holderDid = this.currentAgent?.did;
2514
- if (!holderDid) {
2515
- throw new Error("No current agent available");
2516
- }
2517
- return this.memory.query(query, {
2518
- ...options,
2519
- vcs,
2520
- holderDid
2521
- });
2522
- }
2523
2376
  };
2524
2377
  var defaultClient;
2525
2378
  function getClient(config, password) {
@@ -2786,6 +2639,8 @@ var AIdentityError = class extends Error {
2786
2639
  this.name = this.constructor.name;
2787
2640
  Object.setPrototypeOf(this, new.target.prototype);
2788
2641
  }
2642
+ code;
2643
+ details;
2789
2644
  };
2790
2645
  var VCExpiredError = class extends AIdentityError {
2791
2646
  constructor(message = "Verifiable Credential has expired", details) {
@@ -3946,6 +3801,8 @@ var GatewayError = class extends Error {
3946
3801
  this.responseBody = responseBody;
3947
3802
  this.name = "GatewayError";
3948
3803
  }
3804
+ statusCode;
3805
+ responseBody;
3949
3806
  };
3950
3807
 
3951
3808
  // src/auth/auth-provider.ts
@@ -4425,6 +4282,7 @@ var SimpleRebac = class {
4425
4282
  constructor(allowRelations = ["viewer", "editor", "admin", "owner", "act_as"]) {
4426
4283
  this.allowRelations = allowRelations;
4427
4284
  }
4285
+ allowRelations;
4428
4286
  async check(_sub, relations) {
4429
4287
  return relations.some((r) => this.allowRelations.includes(r));
4430
4288
  }
@@ -4439,6 +4297,7 @@ var DummyVpVerifier = class {
4439
4297
  constructor(vc) {
4440
4298
  this.vc = vc;
4441
4299
  }
4300
+ vc;
4442
4301
  async verifyAndExtractClaims() {
4443
4302
  return this.vc;
4444
4303
  }
@@ -4800,7 +4659,10 @@ var ACTION_REGISTRY = {
4800
4659
  subject: { type: "string", minLength: 1 },
4801
4660
  body: { type: "string", minLength: 1 },
4802
4661
  cc: { type: "string" },
4803
- bcc: { type: "string" }
4662
+ bcc: { type: "string" },
4663
+ threadId: { type: "string" },
4664
+ inReplyTo: { type: "string" },
4665
+ references: { type: "string" }
4804
4666
  },
4805
4667
  required: ["to", "subject", "body"],
4806
4668
  additionalProperties: false
@@ -4830,7 +4692,10 @@ var ACTION_REGISTRY = {
4830
4692
  subject: { type: "string", minLength: 1 },
4831
4693
  body: { type: "string", minLength: 1 },
4832
4694
  cc: { type: "string" },
4833
- bcc: { type: "string" }
4695
+ bcc: { type: "string" },
4696
+ threadId: { type: "string" },
4697
+ inReplyTo: { type: "string" },
4698
+ references: { type: "string" }
4834
4699
  },
4835
4700
  required: ["to", "subject", "body"],
4836
4701
  additionalProperties: false
@@ -5761,6 +5626,17 @@ function normalizeMcpActionName(toolName, actionName) {
5761
5626
  return actionName;
5762
5627
  }
5763
5628
 
5629
+ // src/registry/reauth-constants.ts
5630
+ var REAUTH_REQUIRED_ACTION = "reauth_required";
5631
+ var GATEWAY_ERROR_CODE = {
5632
+ /** Upstream OAuth token is revoked — the user must re-auth at the SaaS provider. */
5633
+ REAUTH_REQUIRED: "REAUTH_REQUIRED",
5634
+ /** Local VC/VP is invalid (expired, malformed, signature mismatch). Try VC reissuance. */
5635
+ CREDENTIAL_INVALID: "CREDENTIAL_INVALID",
5636
+ /** VC allowed a different resource than the request targeted. Try a new approval. */
5637
+ RESOURCE_MISMATCH: "RESOURCE_MISMATCH"
5638
+ };
5639
+
5764
5640
  // src/registry/action-summary.ts
5765
5641
  var ACTION_DISPLAY_CONFIGS = {
5766
5642
  "slack.message.post": {
@@ -6015,6 +5891,70 @@ function getTierLimits(tier) {
6015
5891
  return TIER_LIMITS[resolveUserTier(tier)];
6016
5892
  }
6017
5893
 
5894
+ // src/internal-signature/canonical.ts
5895
+ import { createHash } from "crypto";
5896
+ var SIGNATURE_HEADER = "x-internal-signature";
5897
+ var SIGNATURE_VERSION_PREFIX = "v1=";
5898
+ function sha256Hex(input) {
5899
+ return createHash("sha256").update(input).digest("hex");
5900
+ }
5901
+ function buildCanonicalString(args) {
5902
+ const { method, path: path4, unixSeconds, rawBody } = args;
5903
+ return [method.toUpperCase(), path4, String(unixSeconds), sha256Hex(rawBody)].join("\n");
5904
+ }
5905
+ function parseSignatureHeader(headerValue) {
5906
+ if (typeof headerValue !== "string" || !headerValue.startsWith(SIGNATURE_VERSION_PREFIX)) {
5907
+ return null;
5908
+ }
5909
+ const payload = headerValue.slice(SIGNATURE_VERSION_PREFIX.length);
5910
+ const parts = payload.split(":");
5911
+ if (parts.length !== 3) return null;
5912
+ const [keyId, tsStr, signature] = parts;
5913
+ if (!keyId || !tsStr || !signature) return null;
5914
+ if (!/^[A-Za-z0-9_-]+$/.test(keyId)) return null;
5915
+ if (!/^\d+$/.test(tsStr)) return null;
5916
+ const unixSeconds = Number(tsStr);
5917
+ if (!Number.isFinite(unixSeconds) || unixSeconds < 0) return null;
5918
+ if (!/^[A-Za-z0-9+/]+=*$/.test(signature)) return null;
5919
+ return { keyId, unixSeconds, signature };
5920
+ }
5921
+ function formatSignatureHeader(parsed) {
5922
+ return `${SIGNATURE_VERSION_PREFIX}${parsed.keyId}:${parsed.unixSeconds}:${parsed.signature}`;
5923
+ }
5924
+
5925
+ // src/internal-signature/signer.ts
5926
+ import { createHmac } from "crypto";
5927
+ var MIN_SIGNER_KEY_BYTES = 32;
5928
+ function signRequest(key, args) {
5929
+ assertKeyMaterial(key);
5930
+ const unixSeconds = args.unixSeconds ?? Math.floor(Date.now() / 1e3);
5931
+ const canonical = buildCanonicalString({
5932
+ method: args.method,
5933
+ path: args.path,
5934
+ unixSeconds,
5935
+ rawBody: args.rawBody
5936
+ });
5937
+ const signature = createHmac("sha256", key.secret).update(canonical).digest("base64");
5938
+ const parsed = {
5939
+ keyId: key.keyId,
5940
+ unixSeconds,
5941
+ signature
5942
+ };
5943
+ return formatSignatureHeader(parsed);
5944
+ }
5945
+ function assertKeyMaterial(k) {
5946
+ if (!k.keyId || !/^[A-Za-z0-9_-]+$/.test(k.keyId)) {
5947
+ throw new Error(
5948
+ `internal-signature signer: invalid keyId ${JSON.stringify(k.keyId)} (must match /^[A-Za-z0-9_-]+$/)`
5949
+ );
5950
+ }
5951
+ if (!Buffer.isBuffer(k.secret) || k.secret.length < MIN_SIGNER_KEY_BYTES) {
5952
+ throw new Error(
5953
+ `internal-signature signer: secret too short for keyId=${k.keyId} (${Buffer.isBuffer(k.secret) ? k.secret.length : "not a Buffer"} bytes; minimum ${MIN_SIGNER_KEY_BYTES} required)`
5954
+ );
5955
+ }
5956
+ }
5957
+
6018
5958
  // src/index.ts
6019
5959
  var version = "0.0.1";
6020
5960
  export {
@@ -6040,6 +5980,7 @@ export {
6040
5980
  DummyCreds,
6041
5981
  DummyVpVerifier,
6042
5982
  FilesystemKeyStorage,
5983
+ GATEWAY_ERROR_CODE,
6043
5984
  GatewayClient,
6044
5985
  GatewayError,
6045
5986
  GrantResourceType,
@@ -6048,16 +5989,20 @@ export {
6048
5989
  InvalidVPError,
6049
5990
  InvitationStatus,
6050
5991
  JsonStateStore,
5992
+ KB_JWT_DEFAULT_LIFETIME_SECONDS,
6051
5993
  KeyManager,
6052
5994
  LEGACY_RESOURCE_TYPE_MAP,
5995
+ MIN_SIGNER_KEY_BYTES,
6053
5996
  MemoryKeyStorage,
6054
- MemoryManager,
6055
5997
  NetworkError,
6056
5998
  OAuthProvider,
6057
5999
  PROVIDER_ALIASES,
6000
+ REAUTH_REQUIRED_ACTION,
6058
6001
  RESOURCE_TYPES,
6059
6002
  ReceiptStatus,
6060
6003
  SDJwtClient,
6004
+ SIGNATURE_HEADER,
6005
+ SIGNATURE_VERSION_PREFIX,
6061
6006
  ScopeUnmatchedError,
6062
6007
  SimpleRebac,
6063
6008
  StandardActionCategory,
@@ -6075,7 +6020,9 @@ export {
6075
6020
  VCType,
6076
6021
  VPManager,
6077
6022
  WRITE_ACTION_NAMES,
6023
+ buildCanonicalString,
6078
6024
  buildGrantIdFields,
6025
+ buildKbJwtPayload,
6079
6026
  canonicalizeAction,
6080
6027
  checkPermissionWithVP,
6081
6028
  configure,
@@ -6087,6 +6034,7 @@ export {
6087
6034
  extractProjectKey,
6088
6035
  extractPublicKey,
6089
6036
  extractPublicKeyFromDid,
6037
+ formatSignatureHeader,
6090
6038
  generateActionParamsDisplay,
6091
6039
  generateActionSummary,
6092
6040
  generateKeyPair,
@@ -6113,16 +6061,21 @@ export {
6113
6061
  isWriteAction,
6114
6062
  loadActionRegistryFromFile,
6115
6063
  loadActionRegistryFromObject,
6064
+ normalizeDomain,
6116
6065
  normalizeMcpActionName,
6117
6066
  parseGrantAction,
6118
6067
  parseGrantResourceType,
6068
+ parseSignatureHeader,
6119
6069
  planDelegationForVC,
6120
6070
  publicKeysMatch,
6071
+ readVcExpSeconds,
6121
6072
  resolveActionsFromSelection,
6122
6073
  resolveProvider,
6123
6074
  resolveResourceType,
6124
6075
  resolveUserTier,
6076
+ sha256Hex,
6125
6077
  signJWT,
6078
+ signRequest,
6126
6079
  validateRegistryObject,
6127
6080
  vcStatusToCredentialStatus,
6128
6081
  verifyJWT,