@lifestreamdynamics/vault-sdk 1.0.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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1121 -0
  3. package/dist/client.d.ts +143 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +286 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/errors.d.ts +28 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +49 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/handle-error.d.ts +8 -0
  12. package/dist/handle-error.d.ts.map +1 -0
  13. package/dist/handle-error.js +35 -0
  14. package/dist/handle-error.js.map +1 -0
  15. package/dist/index.d.ts +32 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +26 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/lib/audit-logger.d.ts +29 -0
  20. package/dist/lib/audit-logger.d.ts.map +1 -0
  21. package/dist/lib/audit-logger.js +99 -0
  22. package/dist/lib/audit-logger.js.map +1 -0
  23. package/dist/lib/encryption.d.ts +34 -0
  24. package/dist/lib/encryption.d.ts.map +1 -0
  25. package/dist/lib/encryption.js +87 -0
  26. package/dist/lib/encryption.js.map +1 -0
  27. package/dist/lib/signature.d.ts +47 -0
  28. package/dist/lib/signature.d.ts.map +1 -0
  29. package/dist/lib/signature.js +71 -0
  30. package/dist/lib/signature.js.map +1 -0
  31. package/dist/lib/token-manager.d.ts +80 -0
  32. package/dist/lib/token-manager.d.ts.map +1 -0
  33. package/dist/lib/token-manager.js +116 -0
  34. package/dist/lib/token-manager.js.map +1 -0
  35. package/dist/resources/admin.d.ts +280 -0
  36. package/dist/resources/admin.d.ts.map +1 -0
  37. package/dist/resources/admin.js +236 -0
  38. package/dist/resources/admin.js.map +1 -0
  39. package/dist/resources/ai.d.ts +184 -0
  40. package/dist/resources/ai.d.ts.map +1 -0
  41. package/dist/resources/ai.js +179 -0
  42. package/dist/resources/ai.js.map +1 -0
  43. package/dist/resources/api-keys.d.ts +172 -0
  44. package/dist/resources/api-keys.d.ts.map +1 -0
  45. package/dist/resources/api-keys.js +166 -0
  46. package/dist/resources/api-keys.js.map +1 -0
  47. package/dist/resources/connectors.d.ts +263 -0
  48. package/dist/resources/connectors.d.ts.map +1 -0
  49. package/dist/resources/connectors.js +226 -0
  50. package/dist/resources/connectors.js.map +1 -0
  51. package/dist/resources/documents.d.ts +334 -0
  52. package/dist/resources/documents.d.ts.map +1 -0
  53. package/dist/resources/documents.js +377 -0
  54. package/dist/resources/documents.js.map +1 -0
  55. package/dist/resources/hooks.d.ts +195 -0
  56. package/dist/resources/hooks.d.ts.map +1 -0
  57. package/dist/resources/hooks.js +166 -0
  58. package/dist/resources/hooks.js.map +1 -0
  59. package/dist/resources/publish.d.ts +165 -0
  60. package/dist/resources/publish.d.ts.map +1 -0
  61. package/dist/resources/publish.js +150 -0
  62. package/dist/resources/publish.js.map +1 -0
  63. package/dist/resources/search.d.ts +94 -0
  64. package/dist/resources/search.d.ts.map +1 -0
  65. package/dist/resources/search.js +76 -0
  66. package/dist/resources/search.js.map +1 -0
  67. package/dist/resources/shares.d.ts +130 -0
  68. package/dist/resources/shares.d.ts.map +1 -0
  69. package/dist/resources/shares.js +115 -0
  70. package/dist/resources/shares.js.map +1 -0
  71. package/dist/resources/subscription.d.ts +172 -0
  72. package/dist/resources/subscription.d.ts.map +1 -0
  73. package/dist/resources/subscription.js +166 -0
  74. package/dist/resources/subscription.js.map +1 -0
  75. package/dist/resources/teams.d.ts +356 -0
  76. package/dist/resources/teams.d.ts.map +1 -0
  77. package/dist/resources/teams.js +395 -0
  78. package/dist/resources/teams.js.map +1 -0
  79. package/dist/resources/user.d.ts +92 -0
  80. package/dist/resources/user.d.ts.map +1 -0
  81. package/dist/resources/user.js +64 -0
  82. package/dist/resources/user.js.map +1 -0
  83. package/dist/resources/vaults.d.ts +144 -0
  84. package/dist/resources/vaults.d.ts.map +1 -0
  85. package/dist/resources/vaults.js +158 -0
  86. package/dist/resources/vaults.js.map +1 -0
  87. package/dist/resources/webhooks.d.ts +187 -0
  88. package/dist/resources/webhooks.d.ts.map +1 -0
  89. package/dist/resources/webhooks.js +171 -0
  90. package/dist/resources/webhooks.js.map +1 -0
  91. package/dist/types/api.d.ts +17 -0
  92. package/dist/types/api.d.ts.map +1 -0
  93. package/dist/types/api.js +2 -0
  94. package/dist/types/api.js.map +1 -0
  95. package/dist/types/index.d.ts +3 -0
  96. package/dist/types/index.d.ts.map +1 -0
  97. package/dist/types/index.js +2 -0
  98. package/dist/types/index.js.map +1 -0
  99. package/dist/types/resources.d.ts +5 -0
  100. package/dist/types/resources.d.ts.map +1 -0
  101. package/dist/types/resources.js +2 -0
  102. package/dist/types/resources.js.map +1 -0
  103. package/package.json +58 -0
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ export { LifestreamVaultClient } from './client.js';
2
+ export { VaultsResource } from './resources/vaults.js';
3
+ export { DocumentsResource } from './resources/documents.js';
4
+ export { SearchResource } from './resources/search.js';
5
+ export { AiResource } from './resources/ai.js';
6
+ export { ApiKeysResource } from './resources/api-keys.js';
7
+ export { UserResource } from './resources/user.js';
8
+ export { SubscriptionResource } from './resources/subscription.js';
9
+ export { TeamsResource } from './resources/teams.js';
10
+ export { SharesResource } from './resources/shares.js';
11
+ export { PublishResource } from './resources/publish.js';
12
+ export { ConnectorsResource } from './resources/connectors.js';
13
+ export { HooksResource } from './resources/hooks.js';
14
+ export { WebhooksResource } from './resources/webhooks.js';
15
+ export { AdminResource } from './resources/admin.js';
16
+ // Request signing
17
+ export { signRequest, buildSignaturePayload, signPayload, generateNonce, SIGNATURE_HEADER, SIGNATURE_TIMESTAMP_HEADER, SIGNATURE_NONCE_HEADER, MAX_TIMESTAMP_AGE_MS, } from './lib/signature.js';
18
+ // Audit logging
19
+ export { AuditLogger } from './lib/audit-logger.js';
20
+ // Encryption
21
+ export { generateVaultKey, encrypt as encryptContent, decrypt as decryptContent, isEncryptedEnvelope, } from './lib/encryption.js';
22
+ // Token management
23
+ export { TokenManager, decodeJwtPayload, isTokenExpired, } from './lib/token-manager.js';
24
+ // Error classes
25
+ export { SDKError, ValidationError, AuthenticationError, AuthorizationError, NotFoundError, ConflictError, RateLimitError, NetworkError, } from './errors.js';
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAsB,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAY/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAerD,kBAAkB;AAClB,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,gBAAgB;AAChB,OAAO,EAAE,WAAW,EAA4C,MAAM,uBAAuB,CAAC;AAE9F,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,OAAO,IAAI,cAAc,EACzB,OAAO,IAAI,cAAc,EACzB,mBAAmB,GAEpB,MAAM,qBAAqB,CAAC;AAE7B,mBAAmB;AACnB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,cAAc,GAKf,MAAM,wBAAwB,CAAC;AAEhC,gBAAgB;AAChB,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,aAAa,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface AuditEntry {
2
+ timestamp: string;
3
+ method: string;
4
+ path: string;
5
+ status: number;
6
+ durationMs: number;
7
+ }
8
+ export interface AuditLoggerOptions {
9
+ logPath?: string;
10
+ maxSize?: number;
11
+ maxFiles?: number;
12
+ }
13
+ export declare class AuditLogger {
14
+ private readonly logPath;
15
+ private readonly maxSize;
16
+ private readonly maxFiles;
17
+ constructor(options?: AuditLoggerOptions);
18
+ getLogPath(): string;
19
+ log(entry: AuditEntry): void;
20
+ private rotateIfNeeded;
21
+ readEntries(options?: {
22
+ tail?: number;
23
+ status?: number;
24
+ since?: string;
25
+ until?: string;
26
+ }): AuditEntry[];
27
+ exportCsv(entries: AuditEntry[]): string;
28
+ }
29
+ //# sourceMappingURL=audit-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-logger.d.ts","sourceRoot":"","sources":["../../src/lib/audit-logger.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,GAAE,kBAAuB;IAM5C,UAAU,IAAI,MAAM;IAIpB,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAY5B,OAAO,CAAC,cAAc;IA+BtB,WAAW,CAAC,OAAO,GAAE;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KACX,GAAG,UAAU,EAAE;IAiCrB,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM;CAOzC"}
@@ -0,0 +1,99 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ const DEFAULT_LOG_DIR = path.join(os.homedir(), '.lsvault');
5
+ const DEFAULT_LOG_FILE = 'audit.log';
6
+ const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB
7
+ const MAX_ROTATED_FILES = 5;
8
+ export class AuditLogger {
9
+ logPath;
10
+ maxSize;
11
+ maxFiles;
12
+ constructor(options = {}) {
13
+ this.logPath = options.logPath || path.join(DEFAULT_LOG_DIR, DEFAULT_LOG_FILE);
14
+ this.maxSize = options.maxSize || MAX_LOG_SIZE;
15
+ this.maxFiles = options.maxFiles || MAX_ROTATED_FILES;
16
+ }
17
+ getLogPath() {
18
+ return this.logPath;
19
+ }
20
+ log(entry) {
21
+ const dir = path.dirname(this.logPath);
22
+ if (!fs.existsSync(dir)) {
23
+ fs.mkdirSync(dir, { recursive: true });
24
+ }
25
+ this.rotateIfNeeded();
26
+ const line = JSON.stringify(entry) + '\n';
27
+ fs.appendFileSync(this.logPath, line, 'utf-8');
28
+ }
29
+ rotateIfNeeded() {
30
+ if (!fs.existsSync(this.logPath))
31
+ return;
32
+ let stat;
33
+ try {
34
+ stat = fs.statSync(this.logPath);
35
+ }
36
+ catch {
37
+ return;
38
+ }
39
+ if (stat.size < this.maxSize)
40
+ return;
41
+ // Delete oldest rotated file if it exists
42
+ const oldest = `${this.logPath}.${this.maxFiles}`;
43
+ if (fs.existsSync(oldest)) {
44
+ fs.unlinkSync(oldest);
45
+ }
46
+ // Shift existing rotated files: .4 -> .5, .3 -> .4, etc.
47
+ for (let i = this.maxFiles - 1; i >= 1; i--) {
48
+ const src = `${this.logPath}.${i}`;
49
+ const dest = `${this.logPath}.${i + 1}`;
50
+ if (fs.existsSync(src)) {
51
+ fs.renameSync(src, dest);
52
+ }
53
+ }
54
+ // Rotate current log to .1
55
+ fs.renameSync(this.logPath, `${this.logPath}.1`);
56
+ }
57
+ readEntries(options = {}) {
58
+ if (!fs.existsSync(this.logPath))
59
+ return [];
60
+ const content = fs.readFileSync(this.logPath, 'utf-8');
61
+ const lines = content.split('\n').filter(Boolean);
62
+ let entries = [];
63
+ for (const line of lines) {
64
+ try {
65
+ entries.push(JSON.parse(line));
66
+ }
67
+ catch {
68
+ // Skip malformed lines
69
+ }
70
+ }
71
+ if (options.status !== undefined) {
72
+ entries = entries.filter(e => e.status === options.status);
73
+ }
74
+ if (options.since) {
75
+ const sinceDate = new Date(options.since);
76
+ entries = entries.filter(e => new Date(e.timestamp) >= sinceDate);
77
+ }
78
+ if (options.until) {
79
+ const untilDate = new Date(options.until);
80
+ entries = entries.filter(e => new Date(e.timestamp) <= untilDate);
81
+ }
82
+ if (options.tail !== undefined) {
83
+ entries = entries.slice(-options.tail);
84
+ }
85
+ return entries;
86
+ }
87
+ exportCsv(entries) {
88
+ const header = 'timestamp,method,path,status,durationMs';
89
+ const rows = entries.map(e => `${e.timestamp},${e.method},${csvEscape(e.path)},${e.status},${e.durationMs}`);
90
+ return [header, ...rows].join('\n') + '\n';
91
+ }
92
+ }
93
+ function csvEscape(value) {
94
+ if (value.includes(',') || value.includes('"') || value.includes('\n')) {
95
+ return `"${value.replace(/"/g, '""')}"`;
96
+ }
97
+ return value;
98
+ }
99
+ //# sourceMappingURL=audit-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-logger.js","sourceRoot":"","sources":["../../src/lib/audit-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /** Envelope format for encrypted document content. */
2
+ export interface EncryptedEnvelope {
3
+ version: 1;
4
+ algorithm: 'aes-256-gcm';
5
+ iv: string;
6
+ authTag: string;
7
+ ciphertext: string;
8
+ }
9
+ /**
10
+ * Generate a random 256-bit encryption key.
11
+ * Returns the key as a hex string (64 characters).
12
+ */
13
+ export declare function generateVaultKey(): string;
14
+ /**
15
+ * Encrypt plaintext content using AES-256-GCM.
16
+ *
17
+ * @param plaintext - The plaintext string to encrypt
18
+ * @param keyHex - The 256-bit key as a hex string
19
+ * @returns The encrypted envelope as a JSON string
20
+ */
21
+ export declare function encrypt(plaintext: string, keyHex: string): string;
22
+ /**
23
+ * Decrypt content from an encrypted envelope using AES-256-GCM.
24
+ *
25
+ * @param envelopeJson - The encrypted envelope as a JSON string
26
+ * @param keyHex - The 256-bit key as a hex string
27
+ * @returns The decrypted plaintext string
28
+ */
29
+ export declare function decrypt(envelopeJson: string, keyHex: string): string;
30
+ /**
31
+ * Check if a string is an encrypted envelope (basic structure check).
32
+ */
33
+ export declare function isEncryptedEnvelope(content: string): boolean;
34
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/lib/encryption.ts"],"names":[],"mappings":"AAOA,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,aAAa,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAwBjE;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA4BpE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAa5D"}
@@ -0,0 +1,87 @@
1
+ import crypto from 'node:crypto';
2
+ const ALGORITHM = 'aes-256-gcm';
3
+ const KEY_LENGTH = 32; // 256 bits
4
+ const IV_LENGTH = 12; // 96 bits (recommended for GCM)
5
+ const AUTH_TAG_LENGTH = 16; // 128 bits
6
+ /**
7
+ * Generate a random 256-bit encryption key.
8
+ * Returns the key as a hex string (64 characters).
9
+ */
10
+ export function generateVaultKey() {
11
+ return crypto.randomBytes(KEY_LENGTH).toString('hex');
12
+ }
13
+ /**
14
+ * Encrypt plaintext content using AES-256-GCM.
15
+ *
16
+ * @param plaintext - The plaintext string to encrypt
17
+ * @param keyHex - The 256-bit key as a hex string
18
+ * @returns The encrypted envelope as a JSON string
19
+ */
20
+ export function encrypt(plaintext, keyHex) {
21
+ const key = Buffer.from(keyHex, 'hex');
22
+ if (key.length !== KEY_LENGTH) {
23
+ throw new Error(`Invalid key length: expected ${KEY_LENGTH} bytes, got ${key.length}`);
24
+ }
25
+ const iv = crypto.randomBytes(IV_LENGTH);
26
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
27
+ const encrypted = Buffer.concat([
28
+ cipher.update(plaintext, 'utf8'),
29
+ cipher.final(),
30
+ ]);
31
+ const authTag = cipher.getAuthTag();
32
+ const envelope = {
33
+ version: 1,
34
+ algorithm: ALGORITHM,
35
+ iv: iv.toString('hex'),
36
+ authTag: authTag.toString('hex'),
37
+ ciphertext: encrypted.toString('hex'),
38
+ };
39
+ return JSON.stringify(envelope);
40
+ }
41
+ /**
42
+ * Decrypt content from an encrypted envelope using AES-256-GCM.
43
+ *
44
+ * @param envelopeJson - The encrypted envelope as a JSON string
45
+ * @param keyHex - The 256-bit key as a hex string
46
+ * @returns The decrypted plaintext string
47
+ */
48
+ export function decrypt(envelopeJson, keyHex) {
49
+ const key = Buffer.from(keyHex, 'hex');
50
+ if (key.length !== KEY_LENGTH) {
51
+ throw new Error(`Invalid key length: expected ${KEY_LENGTH} bytes, got ${key.length}`);
52
+ }
53
+ const envelope = JSON.parse(envelopeJson);
54
+ if (envelope.version !== 1) {
55
+ throw new Error(`Unsupported encryption envelope version: ${envelope.version}`);
56
+ }
57
+ if (envelope.algorithm !== ALGORITHM) {
58
+ throw new Error(`Unsupported encryption algorithm: ${envelope.algorithm}`);
59
+ }
60
+ const iv = Buffer.from(envelope.iv, 'hex');
61
+ const authTag = Buffer.from(envelope.authTag, 'hex');
62
+ const ciphertext = Buffer.from(envelope.ciphertext, 'hex');
63
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
64
+ decipher.setAuthTag(authTag);
65
+ const decrypted = Buffer.concat([
66
+ decipher.update(ciphertext),
67
+ decipher.final(),
68
+ ]);
69
+ return decrypted.toString('utf8');
70
+ }
71
+ /**
72
+ * Check if a string is an encrypted envelope (basic structure check).
73
+ */
74
+ export function isEncryptedEnvelope(content) {
75
+ try {
76
+ const parsed = JSON.parse(content);
77
+ return (parsed.version === 1
78
+ && parsed.algorithm === ALGORITHM
79
+ && typeof parsed.iv === 'string'
80
+ && typeof parsed.authTag === 'string'
81
+ && typeof parsed.ciphertext === 'string');
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ }
87
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/lib/encryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Headers used for HMAC request signing.
3
+ */
4
+ export declare const SIGNATURE_HEADER = "x-signature";
5
+ export declare const SIGNATURE_TIMESTAMP_HEADER = "x-signature-timestamp";
6
+ export declare const SIGNATURE_NONCE_HEADER = "x-signature-nonce";
7
+ /**
8
+ * Maximum age (in milliseconds) for a signed request timestamp.
9
+ * Requests older than this are rejected to prevent replay attacks.
10
+ */
11
+ export declare const MAX_TIMESTAMP_AGE_MS: number;
12
+ /**
13
+ * Constructs the canonical payload string for HMAC signing.
14
+ *
15
+ * Format: METHOD\nPATH\nTIMESTAMP\nNONCE\nBODY_HASH
16
+ *
17
+ * @param method - HTTP method (uppercase)
18
+ * @param path - Request path (no query string)
19
+ * @param timestamp - ISO-8601 timestamp
20
+ * @param nonce - 16-byte hex nonce
21
+ * @param body - Request body string (empty string if no body)
22
+ * @returns The canonical payload string
23
+ */
24
+ export declare function buildSignaturePayload(method: string, path: string, timestamp: string, nonce: string, body: string): string;
25
+ /**
26
+ * Generates an HMAC-SHA256 signature for a request.
27
+ *
28
+ * @param secret - The API key used as the HMAC secret
29
+ * @param payload - The canonical payload string
30
+ * @returns Hex-encoded HMAC signature
31
+ */
32
+ export declare function signPayload(secret: string, payload: string): string;
33
+ /**
34
+ * Generates a cryptographically secure 16-byte hex nonce.
35
+ */
36
+ export declare function generateNonce(): string;
37
+ /**
38
+ * Signs a request and returns the headers to attach.
39
+ *
40
+ * @param apiKey - The full API key (used as HMAC secret)
41
+ * @param method - HTTP method
42
+ * @param path - Request path (without query string)
43
+ * @param body - Request body string (empty string for no body)
44
+ * @returns Object containing the three signature headers
45
+ */
46
+ export declare function signRequest(apiKey: string, method: string, path: string, body?: string): Record<string, string>;
47
+ //# sourceMappingURL=signature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/lib/signature.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAC9C,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAClE,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAAgB,CAAC;AAElD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAW,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWxB"}
@@ -0,0 +1,71 @@
1
+ import crypto from 'node:crypto';
2
+ /**
3
+ * Headers used for HMAC request signing.
4
+ */
5
+ export const SIGNATURE_HEADER = 'x-signature';
6
+ export const SIGNATURE_TIMESTAMP_HEADER = 'x-signature-timestamp';
7
+ export const SIGNATURE_NONCE_HEADER = 'x-signature-nonce';
8
+ /**
9
+ * Maximum age (in milliseconds) for a signed request timestamp.
10
+ * Requests older than this are rejected to prevent replay attacks.
11
+ */
12
+ export const MAX_TIMESTAMP_AGE_MS = 5 * 60 * 1000; // 5 minutes
13
+ /**
14
+ * Constructs the canonical payload string for HMAC signing.
15
+ *
16
+ * Format: METHOD\nPATH\nTIMESTAMP\nNONCE\nBODY_HASH
17
+ *
18
+ * @param method - HTTP method (uppercase)
19
+ * @param path - Request path (no query string)
20
+ * @param timestamp - ISO-8601 timestamp
21
+ * @param nonce - 16-byte hex nonce
22
+ * @param body - Request body string (empty string if no body)
23
+ * @returns The canonical payload string
24
+ */
25
+ export function buildSignaturePayload(method, path, timestamp, nonce, body) {
26
+ const bodyHash = crypto
27
+ .createHash('sha256')
28
+ .update(body)
29
+ .digest('hex');
30
+ return `${method.toUpperCase()}\n${path}\n${timestamp}\n${nonce}\n${bodyHash}`;
31
+ }
32
+ /**
33
+ * Generates an HMAC-SHA256 signature for a request.
34
+ *
35
+ * @param secret - The API key used as the HMAC secret
36
+ * @param payload - The canonical payload string
37
+ * @returns Hex-encoded HMAC signature
38
+ */
39
+ export function signPayload(secret, payload) {
40
+ return crypto
41
+ .createHmac('sha256', secret)
42
+ .update(payload)
43
+ .digest('hex');
44
+ }
45
+ /**
46
+ * Generates a cryptographically secure 16-byte hex nonce.
47
+ */
48
+ export function generateNonce() {
49
+ return crypto.randomBytes(16).toString('hex');
50
+ }
51
+ /**
52
+ * Signs a request and returns the headers to attach.
53
+ *
54
+ * @param apiKey - The full API key (used as HMAC secret)
55
+ * @param method - HTTP method
56
+ * @param path - Request path (without query string)
57
+ * @param body - Request body string (empty string for no body)
58
+ * @returns Object containing the three signature headers
59
+ */
60
+ export function signRequest(apiKey, method, path, body = '') {
61
+ const timestamp = new Date().toISOString();
62
+ const nonce = generateNonce();
63
+ const payload = buildSignaturePayload(method, path, timestamp, nonce, body);
64
+ const signature = signPayload(apiKey, payload);
65
+ return {
66
+ [SIGNATURE_HEADER]: signature,
67
+ [SIGNATURE_TIMESTAMP_HEADER]: timestamp,
68
+ [SIGNATURE_NONCE_HEADER]: nonce,
69
+ };
70
+ }
71
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/lib/signature.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAC9C,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAClE,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAE1D;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAc,EACd,IAAY,EACZ,SAAiB,EACjB,KAAa,EACb,IAAY;IAEZ,MAAM,QAAQ,GAAG,MAAM;SACpB,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,IAAI,CAAC;SACZ,MAAM,CAAC,KAAK,CAAC,CAAC;IACjB,OAAO,GAAG,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,KAAK,SAAS,KAAK,KAAK,KAAK,QAAQ,EAAE,CAAC;AACjF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,OAAe;IACzD,OAAO,MAAM;SACV,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,OAAO,CAAC;SACf,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CACzB,MAAc,EACd,MAAc,EACd,IAAY,EACZ,OAAe,EAAE;IAEjB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC5E,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/C,OAAO;QACL,CAAC,gBAAgB,CAAC,EAAE,SAAS;QAC7B,CAAC,0BAA0B,CAAC,EAAE,SAAS;QACvC,CAAC,sBAAsB,CAAC,EAAE,KAAK;KAChC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,80 @@
1
+ import type { KyInstance } from 'ky';
2
+ /** Decoded JWT payload with standard claims. */
3
+ export interface JwtPayload {
4
+ exp: number;
5
+ iat?: number;
6
+ sub?: string;
7
+ email?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ /** Authentication tokens returned from login/refresh. */
11
+ export interface AuthTokens {
12
+ accessToken: string;
13
+ user: {
14
+ id: string;
15
+ email: string;
16
+ name?: string;
17
+ role: string;
18
+ [key: string]: unknown;
19
+ };
20
+ }
21
+ /** Callback invoked when tokens are refreshed. */
22
+ export type OnTokenRefresh = (tokens: AuthTokens) => void;
23
+ /** Options for configuring the TokenManager. */
24
+ export interface TokenManagerOptions {
25
+ /** How many milliseconds before expiry to trigger a proactive refresh. Default: 60000 (1 min). */
26
+ refreshBufferMs?: number;
27
+ /** Called after a successful token refresh. */
28
+ onTokenRefresh?: OnTokenRefresh;
29
+ }
30
+ /**
31
+ * Decode a JWT payload without verification.
32
+ * Only decodes the payload section (second segment) from base64url.
33
+ */
34
+ export declare function decodeJwtPayload(token: string): JwtPayload | null;
35
+ /**
36
+ * Check if a JWT token is expired or will expire within the given buffer.
37
+ *
38
+ * @param token - The JWT access token
39
+ * @param bufferMs - Milliseconds before actual expiry to consider it "expired"
40
+ * @returns true if the token is expired or will expire within bufferMs
41
+ */
42
+ export declare function isTokenExpired(token: string, bufferMs?: number): boolean;
43
+ /**
44
+ * Manages JWT access token lifecycle with automatic refresh.
45
+ *
46
+ * Handles:
47
+ * - Proactive refresh before token expiry (beforeRequest hook)
48
+ * - Reactive refresh on 401 responses (afterResponse hook)
49
+ * - Infinite retry prevention via X-Retry-After-Refresh header
50
+ * - Deduplication of concurrent refresh requests
51
+ */
52
+ export declare class TokenManager {
53
+ private accessToken;
54
+ private refreshToken;
55
+ private refreshPromise;
56
+ private readonly refreshBufferMs;
57
+ private readonly onTokenRefresh?;
58
+ constructor(accessToken: string, refreshToken: string | null, options?: TokenManagerOptions);
59
+ /** Get the current access token. */
60
+ getAccessToken(): string;
61
+ /** Get the current refresh token. */
62
+ getRefreshToken(): string | null;
63
+ /** Update the access token (e.g., after external login). */
64
+ setAccessToken(token: string): void;
65
+ /** Update the refresh token. */
66
+ setRefreshToken(token: string | null): void;
67
+ /** Check whether the current access token needs refreshing. */
68
+ needsRefresh(): boolean;
69
+ /**
70
+ * Perform a token refresh using the API's /auth/refresh endpoint.
71
+ * Deduplicates concurrent calls so only one HTTP request is made.
72
+ *
73
+ * @param http - The ky instance to use for the refresh request (should NOT have auth hooks)
74
+ * @returns The new access token
75
+ * @throws If refresh fails (no refresh token, network error, etc.)
76
+ */
77
+ refresh(http: KyInstance): Promise<string>;
78
+ private performRefresh;
79
+ }
80
+ //# sourceMappingURL=token-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/lib/token-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAErC,gDAAgD;AAChD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,yDAAyD;AACzD,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,kDAAkD;AAClD,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;AAE1D,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAoBjE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAe,GAAG,OAAO,CAMhF;AAED;;;;;;;;GAQG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAiB;gBAG/C,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,OAAO,GAAE,mBAAwB;IAQnC,oCAAoC;IACpC,cAAc,IAAI,MAAM;IAIxB,qCAAqC;IACrC,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,4DAA4D;IAC5D,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC,gCAAgC;IAChC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI3C,+DAA+D;IAC/D,YAAY,IAAI,OAAO;IAIvB;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;YAmBlC,cAAc;CAa7B"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Decode a JWT payload without verification.
3
+ * Only decodes the payload section (second segment) from base64url.
4
+ */
5
+ export function decodeJwtPayload(token) {
6
+ try {
7
+ const parts = token.split('.');
8
+ if (parts.length !== 3)
9
+ return null;
10
+ const payload = parts[1];
11
+ // Base64url to base64
12
+ const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
13
+ // Pad if needed
14
+ const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
15
+ // Decode - works in both Node.js and browser
16
+ const decoded = typeof atob === 'function'
17
+ ? atob(padded)
18
+ : Buffer.from(padded, 'base64').toString('utf-8');
19
+ return JSON.parse(decoded);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ /**
26
+ * Check if a JWT token is expired or will expire within the given buffer.
27
+ *
28
+ * @param token - The JWT access token
29
+ * @param bufferMs - Milliseconds before actual expiry to consider it "expired"
30
+ * @returns true if the token is expired or will expire within bufferMs
31
+ */
32
+ export function isTokenExpired(token, bufferMs = 60_000) {
33
+ const payload = decodeJwtPayload(token);
34
+ if (!payload || !payload.exp)
35
+ return true;
36
+ const expiresAtMs = payload.exp * 1000;
37
+ return Date.now() > expiresAtMs - bufferMs;
38
+ }
39
+ /**
40
+ * Manages JWT access token lifecycle with automatic refresh.
41
+ *
42
+ * Handles:
43
+ * - Proactive refresh before token expiry (beforeRequest hook)
44
+ * - Reactive refresh on 401 responses (afterResponse hook)
45
+ * - Infinite retry prevention via X-Retry-After-Refresh header
46
+ * - Deduplication of concurrent refresh requests
47
+ */
48
+ export class TokenManager {
49
+ accessToken;
50
+ refreshToken;
51
+ refreshPromise = null;
52
+ refreshBufferMs;
53
+ onTokenRefresh;
54
+ constructor(accessToken, refreshToken, options = {}) {
55
+ this.accessToken = accessToken;
56
+ this.refreshToken = refreshToken;
57
+ this.refreshBufferMs = options.refreshBufferMs ?? 60_000;
58
+ this.onTokenRefresh = options.onTokenRefresh;
59
+ }
60
+ /** Get the current access token. */
61
+ getAccessToken() {
62
+ return this.accessToken;
63
+ }
64
+ /** Get the current refresh token. */
65
+ getRefreshToken() {
66
+ return this.refreshToken;
67
+ }
68
+ /** Update the access token (e.g., after external login). */
69
+ setAccessToken(token) {
70
+ this.accessToken = token;
71
+ }
72
+ /** Update the refresh token. */
73
+ setRefreshToken(token) {
74
+ this.refreshToken = token;
75
+ }
76
+ /** Check whether the current access token needs refreshing. */
77
+ needsRefresh() {
78
+ return isTokenExpired(this.accessToken, this.refreshBufferMs);
79
+ }
80
+ /**
81
+ * Perform a token refresh using the API's /auth/refresh endpoint.
82
+ * Deduplicates concurrent calls so only one HTTP request is made.
83
+ *
84
+ * @param http - The ky instance to use for the refresh request (should NOT have auth hooks)
85
+ * @returns The new access token
86
+ * @throws If refresh fails (no refresh token, network error, etc.)
87
+ */
88
+ async refresh(http) {
89
+ if (!this.refreshToken) {
90
+ throw new Error('No refresh token available');
91
+ }
92
+ // Deduplicate concurrent refresh requests
93
+ if (this.refreshPromise) {
94
+ return this.refreshPromise;
95
+ }
96
+ this.refreshPromise = this.performRefresh(http);
97
+ try {
98
+ return await this.refreshPromise;
99
+ }
100
+ finally {
101
+ this.refreshPromise = null;
102
+ }
103
+ }
104
+ async performRefresh(http) {
105
+ const response = await http.post('auth/refresh', {
106
+ headers: {
107
+ 'X-Requested-With': 'LifestreamVaultSDK',
108
+ 'Cookie': `lsv_refresh=${this.refreshToken}`,
109
+ },
110
+ }).json();
111
+ this.accessToken = response.accessToken;
112
+ this.onTokenRefresh?.(response);
113
+ return this.accessToken;
114
+ }
115
+ }
116
+ //# sourceMappingURL=token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/lib/token-manager.ts"],"names":[],"mappings":"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"}