@aiconnect/confidant 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/README.md +570 -0
  2. package/dist/api-client.d.ts +58 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +101 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +69 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/commands/create.d.ts +3 -0
  11. package/dist/commands/create.d.ts.map +1 -0
  12. package/dist/commands/create.js +51 -0
  13. package/dist/commands/create.js.map +1 -0
  14. package/dist/commands/delete.d.ts +3 -0
  15. package/dist/commands/delete.d.ts.map +1 -0
  16. package/dist/commands/delete.js +29 -0
  17. package/dist/commands/delete.js.map +1 -0
  18. package/dist/commands/get-request.d.ts +3 -0
  19. package/dist/commands/get-request.d.ts.map +1 -0
  20. package/dist/commands/get-request.js +89 -0
  21. package/dist/commands/get-request.js.map +1 -0
  22. package/dist/commands/get.d.ts +3 -0
  23. package/dist/commands/get.d.ts.map +1 -0
  24. package/dist/commands/get.js +29 -0
  25. package/dist/commands/get.js.map +1 -0
  26. package/dist/commands/request.d.ts +3 -0
  27. package/dist/commands/request.d.ts.map +1 -0
  28. package/dist/commands/request.js +289 -0
  29. package/dist/commands/request.js.map +1 -0
  30. package/dist/commands/status.d.ts +3 -0
  31. package/dist/commands/status.d.ts.map +1 -0
  32. package/dist/commands/status.js +40 -0
  33. package/dist/commands/status.js.map +1 -0
  34. package/dist/crypto.d.ts +32 -0
  35. package/dist/crypto.d.ts.map +1 -0
  36. package/dist/crypto.js +79 -0
  37. package/dist/crypto.js.map +1 -0
  38. package/dist/crypto.test.d.ts +5 -0
  39. package/dist/crypto.test.d.ts.map +1 -0
  40. package/dist/crypto.test.js +77 -0
  41. package/dist/crypto.test.js.map +1 -0
  42. package/dist/i18n.d.ts +55 -0
  43. package/dist/i18n.d.ts.map +1 -0
  44. package/dist/i18n.js +63 -0
  45. package/dist/i18n.js.map +1 -0
  46. package/dist/index.d.ts +2 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +53 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/network-detection.d.ts +11 -0
  51. package/dist/network-detection.d.ts.map +1 -0
  52. package/dist/network-detection.js +54 -0
  53. package/dist/network-detection.js.map +1 -0
  54. package/dist/network-detection.test.d.ts +2 -0
  55. package/dist/network-detection.test.d.ts.map +1 -0
  56. package/dist/network-detection.test.js +150 -0
  57. package/dist/network-detection.test.js.map +1 -0
  58. package/dist/rate-limiter.d.ts +61 -0
  59. package/dist/rate-limiter.d.ts.map +1 -0
  60. package/dist/rate-limiter.js +128 -0
  61. package/dist/rate-limiter.js.map +1 -0
  62. package/dist/rate-limiter.test.d.ts +5 -0
  63. package/dist/rate-limiter.test.d.ts.map +1 -0
  64. package/dist/rate-limiter.test.js +130 -0
  65. package/dist/rate-limiter.test.js.map +1 -0
  66. package/dist/registry.d.ts +136 -0
  67. package/dist/registry.d.ts.map +1 -0
  68. package/dist/registry.js +182 -0
  69. package/dist/registry.js.map +1 -0
  70. package/dist/registry.test.d.ts +13 -0
  71. package/dist/registry.test.d.ts.map +1 -0
  72. package/dist/registry.test.js +308 -0
  73. package/dist/registry.test.js.map +1 -0
  74. package/dist/routes.d.ts +4 -0
  75. package/dist/routes.d.ts.map +1 -0
  76. package/dist/routes.js +931 -0
  77. package/dist/routes.js.map +1 -0
  78. package/dist/server.d.ts +27 -0
  79. package/dist/server.d.ts.map +1 -0
  80. package/dist/server.js +79 -0
  81. package/dist/server.js.map +1 -0
  82. package/dist/storage.d.ts +150 -0
  83. package/dist/storage.d.ts.map +1 -0
  84. package/dist/storage.js +298 -0
  85. package/dist/storage.js.map +1 -0
  86. package/dist/storage.test.d.ts +5 -0
  87. package/dist/storage.test.d.ts.map +1 -0
  88. package/dist/storage.test.js +466 -0
  89. package/dist/storage.test.js.map +1 -0
  90. package/dist/types.d.ts +144 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +56 -0
  93. package/dist/types.js.map +1 -0
  94. package/dist/url-helper.d.ts +16 -0
  95. package/dist/url-helper.d.ts.map +1 -0
  96. package/dist/url-helper.js +27 -0
  97. package/dist/url-helper.js.map +1 -0
  98. package/dist/url-helper.test.d.ts +2 -0
  99. package/dist/url-helper.test.d.ts.map +1 -0
  100. package/dist/url-helper.test.js +70 -0
  101. package/dist/url-helper.test.js.map +1 -0
  102. package/package.json +73 -0
  103. package/public/index.html +352 -0
package/dist/types.js ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shared TypeScript Types
3
+ *
4
+ * Common type definitions used throughout the Confidant application.
5
+ */
6
+ /**
7
+ * Error types
8
+ */
9
+ export class SecretNotFoundError extends Error {
10
+ constructor(id) {
11
+ super(`Secret not found: ${id}`);
12
+ this.name = 'SecretNotFoundError';
13
+ }
14
+ }
15
+ export class SecretExpiredError extends Error {
16
+ constructor(id) {
17
+ super(`Secret has expired: ${id}`);
18
+ this.name = 'SecretExpiredError';
19
+ }
20
+ }
21
+ export class MaxAccessCountExceededError extends Error {
22
+ constructor(id) {
23
+ super(`Maximum access count exceeded for secret: ${id}`);
24
+ this.name = 'MaxAccessCountExceededError';
25
+ }
26
+ }
27
+ /**
28
+ * Error types for secret requests
29
+ */
30
+ export class SecretRequestNotFoundError extends Error {
31
+ constructor(id) {
32
+ super(`Secret request not found: ${id}`);
33
+ this.name = 'SecretRequestNotFoundError';
34
+ }
35
+ }
36
+ export class SecretRequestExpiredError extends Error {
37
+ constructor(id) {
38
+ super(`Secret request has expired: ${id}`);
39
+ this.name = 'SecretRequestExpiredError';
40
+ }
41
+ }
42
+ export class SecretRequestAlreadyRetrievedError extends Error {
43
+ constructor(id) {
44
+ super(`Secret request has already been retrieved: ${id}`);
45
+ this.name = 'SecretRequestAlreadyRetrievedError';
46
+ }
47
+ }
48
+ export class SecretRequestAlreadyCompletedError extends Error {
49
+ constructor(id) {
50
+ super(`Secret request has already been completed: ${id}`);
51
+ this.name = 'SecretRequestAlreadyCompletedError';
52
+ }
53
+ }
54
+ export { Registry, storageRegistry, validatorRegistry, transformerRegistry } from './registry.js';
55
+ export { MemoryStorageModule, BasicValidatorModule, UppercaseTransformerModule } from './registry.js';
56
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoDH;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,EAAU;QACpB,KAAK,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,EAAU;QACpB,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IACpD,YAAY,EAAU;QACpB,KAAK,CAAC,6CAA6C,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC5C,CAAC;CACF;AAqED;;GAEG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,EAAU;QACpB,KAAK,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAY,EAAU;QACpB,KAAK,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,kCAAmC,SAAQ,KAAK;IAC3D,YAAY,EAAU;QACpB,KAAK,CAAC,8CAA8C,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,GAAG,oCAAoC,CAAC;IACnD,CAAC;CACF;AAED,MAAM,OAAO,kCAAmC,SAAQ,KAAK;IAC3D,YAAY,EAAU;QACpB,KAAK,CAAC,8CAA8C,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,GAAG,oCAAoC,CAAC;IACnD,CAAC;CACF;AAQD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generate URLs for accessing a secret request
3
+ * Returns both localhost and network URLs for cross-device access
4
+ */
5
+ export declare function generateUrls(apiUrl: string, hash: string, localIp: string | null): {
6
+ localhost: string;
7
+ network: string | null;
8
+ };
9
+ /**
10
+ * Format URLs for display in CLI output
11
+ */
12
+ export declare function formatUrlsForDisplay(urls: {
13
+ localhost: string;
14
+ network: string | null;
15
+ }): string[];
16
+ //# sourceMappingURL=url-helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-helper.d.ts","sourceRoot":"","sources":["../src/url-helper.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAa/C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAClD,MAAM,EAAE,CASV"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Generate URLs for accessing a secret request
3
+ * Returns both localhost and network URLs for cross-device access
4
+ */
5
+ export function generateUrls(apiUrl, hash, localIp) {
6
+ // Parse the API URL to get the protocol and port
7
+ const url = new URL(apiUrl);
8
+ const protocol = url.protocol.replace(':', '');
9
+ const port = url.port || (protocol === 'https' ? '443' : '3000');
10
+ // Generate localhost URL (uses /requests/:hash path)
11
+ const localhost = `${protocol}://localhost:${port}/requests/${hash}`;
12
+ // Generate network URL if local IP is available
13
+ const network = localIp ? `${protocol}://${localIp}:${port}/requests/${hash}` : null;
14
+ return { localhost, network };
15
+ }
16
+ /**
17
+ * Format URLs for display in CLI output
18
+ */
19
+ export function formatUrlsForDisplay(urls) {
20
+ const displayUrls = [];
21
+ if (urls.network) {
22
+ displayUrls.push(`Network URL (for other devices): ${urls.network}`);
23
+ }
24
+ displayUrls.push(`Localhost URL (for this device): ${urls.localhost}`);
25
+ return displayUrls;
26
+ }
27
+ //# sourceMappingURL=url-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-helper.js","sourceRoot":"","sources":["../src/url-helper.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAc,EACd,IAAY,EACZ,OAAsB;IAEtB,iDAAiD;IACjD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAEjE,qDAAqD;IACrD,MAAM,SAAS,GAAG,GAAG,QAAQ,gBAAgB,IAAI,aAAa,IAAI,EAAE,CAAC;IAErE,gDAAgD;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,MAAM,OAAO,IAAI,IAAI,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAErF,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAmD;IAEnD,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,WAAW,CAAC,IAAI,CAAC,oCAAoC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,WAAW,CAAC,IAAI,CAAC,oCAAoC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAEvE,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=url-helper.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-helper.test.d.ts","sourceRoot":"","sources":["../src/url-helper.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateUrls, formatUrlsForDisplay } from './url-helper.js';
3
+ describe('url-helper', () => {
4
+ describe('generateUrls', () => {
5
+ it('should generate localhost URL', () => {
6
+ const result = generateUrls('http://localhost:3000', 'abc123', null);
7
+ expect(result.localhost).toBe('http://localhost:3000/request/abc123');
8
+ expect(result.network).toBeNull();
9
+ });
10
+ it('should generate network URL when local IP is provided', () => {
11
+ const result = generateUrls('http://localhost:3000', 'abc123', '192.168.1.100');
12
+ expect(result.localhost).toBe('http://localhost:3000/request/abc123');
13
+ expect(result.network).toBe('http://192.168.1.100:3000/request/abc123');
14
+ });
15
+ it('should handle custom port', () => {
16
+ const result = generateUrls('http://localhost:8080', 'abc123', '192.168.1.100');
17
+ expect(result.localhost).toBe('http://localhost:8080/request/abc123');
18
+ expect(result.network).toBe('http://192.168.1.100:8080/request/abc123');
19
+ });
20
+ it('should handle HTTPS', () => {
21
+ const result = generateUrls('https://localhost:443', 'abc123', '192.168.1.100');
22
+ expect(result.localhost).toBe('https://localhost:443/request/abc123');
23
+ expect(result.network).toBe('https://192.168.1.100:443/request/abc123');
24
+ });
25
+ it('should handle API URL with path', () => {
26
+ const result = generateUrls('http://localhost:3000/api', 'abc123', '192.168.1.100');
27
+ expect(result.localhost).toBe('http://localhost:3000/request/abc123');
28
+ expect(result.network).toBe('http://192.168.1.100:3000/request/abc123');
29
+ });
30
+ it('should return null network URL when local IP is null', () => {
31
+ const result = generateUrls('http://localhost:3000', 'abc123', null);
32
+ expect(result.localhost).toBe('http://localhost:3000/request/abc123');
33
+ expect(result.network).toBeNull();
34
+ });
35
+ });
36
+ describe('formatUrlsForDisplay', () => {
37
+ it('should format both URLs when network URL is available', () => {
38
+ const urls = {
39
+ localhost: 'http://localhost:3000/request/abc123',
40
+ network: 'http://192.168.1.100:3000/request/abc123'
41
+ };
42
+ const result = formatUrlsForDisplay(urls);
43
+ expect(result).toEqual([
44
+ 'Network URL (for other devices): http://192.168.1.100:3000/request/abc123',
45
+ 'Localhost URL (for this device): http://localhost:3000/request/abc123'
46
+ ]);
47
+ });
48
+ it('should format only localhost URL when network URL is null', () => {
49
+ const urls = {
50
+ localhost: 'http://localhost:3000/request/abc123',
51
+ network: null
52
+ };
53
+ const result = formatUrlsForDisplay(urls);
54
+ expect(result).toEqual([
55
+ 'Localhost URL (for this device): http://localhost:3000/request/abc123'
56
+ ]);
57
+ });
58
+ it('should handle empty network URL', () => {
59
+ const urls = {
60
+ localhost: 'http://localhost:3000/request/abc123',
61
+ network: ''
62
+ };
63
+ const result = formatUrlsForDisplay(urls);
64
+ expect(result).toEqual([
65
+ 'Localhost URL (for this device): http://localhost:3000/request/abc123'
66
+ ]);
67
+ });
68
+ });
69
+ });
70
+ //# sourceMappingURL=url-helper.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-helper.test.js","sourceRoot":"","sources":["../src/url-helper.test.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@aiconnect/confidant",
3
+ "version": "1.0.0",
4
+ "description": "Secure secret handoff system with time-limited access",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "type": "module",
9
+ "bin": {
10
+ "confidant": "./dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "public",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "dev": "tsx watch src/index.ts",
25
+ "build": "tsc",
26
+ "start": "node dist/index.js",
27
+ "test": "vitest",
28
+ "test:ui": "vitest --ui",
29
+ "test:run": "vitest run",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "keywords": [
33
+ "secret",
34
+ "handoff",
35
+ "security",
36
+ "ttl",
37
+ "hono",
38
+ "api",
39
+ "confidant",
40
+ "one-time-secret"
41
+ ],
42
+ "author": "AI Connect",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/johnjohn-aic/confidant.git"
47
+ },
48
+ "homepage": "https://github.com/johnjohn-aic/confidant#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/johnjohn-aic/confidant/issues"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "engines": {
56
+ "node": ">=18.0.0"
57
+ },
58
+ "dependencies": {
59
+ "@hono/node-server": "^1.19.9",
60
+ "chalk": "^5.3.0",
61
+ "commander": "^12.1.0",
62
+ "hono": "^4.0.0",
63
+ "node-fetch": "^3.3.2",
64
+ "zod": "^3.22.0"
65
+ },
66
+ "devDependencies": {
67
+ "@types/node": "^20.19.30",
68
+ "@vitest/ui": "^4.0.18",
69
+ "tsx": "^4.21.0",
70
+ "typescript": "^5.9.3",
71
+ "vitest": "^4.0.18"
72
+ }
73
+ }
@@ -0,0 +1,352 @@
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Confidant - Compartilhar Segredos</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
13
+ }
14
+
15
+ body {
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ min-height: 100vh;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ padding: 20px;
22
+ }
23
+
24
+ .container {
25
+ background: white;
26
+ border-radius: 12px;
27
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
28
+ padding: 40px;
29
+ max-width: 600px;
30
+ width: 100%;
31
+ }
32
+
33
+ h1 {
34
+ color: #1f2937;
35
+ margin-bottom: 8px;
36
+ font-size: 28px;
37
+ font-weight: 600;
38
+ }
39
+
40
+ .form-group {
41
+ margin-bottom: 20px;
42
+ }
43
+
44
+ label {
45
+ display: block;
46
+ margin-bottom: 8px;
47
+ color: #374151;
48
+ font-weight: 500;
49
+ font-size: 14px;
50
+ }
51
+
52
+ input[type="text"],
53
+ input[type="number"] {
54
+ width: 100%;
55
+ padding: 12px 16px;
56
+ border: 2px solid #e2e8f0;
57
+ border-radius: 8px;
58
+ font-size: 16px;
59
+ transition: border-color 0.3s, box-shadow 0.3s;
60
+ }
61
+
62
+ input[type="text"]:focus,
63
+ input[type="number"]:focus {
64
+ outline: none;
65
+ border-color: #667eea;
66
+ box-shadow: 0 0 0 8px rgba(102, 126, 234, 0.2);
67
+ }
68
+
69
+ button {
70
+ width: 100%;
71
+ padding: 14px 24px;
72
+ background: #667eea;
73
+ color: white;
74
+ border: none;
75
+ border-radius: 8px;
76
+ font-size: 16px;
77
+ font-weight: 600;
78
+ cursor: pointer;
79
+ transition: background-color 0.3s, transform 0.1s;
80
+ }
81
+
82
+ button:hover {
83
+ background: #5568d3;
84
+ transform: translateY(-2px);
85
+ }
86
+
87
+ button:active {
88
+ transform: translateY(0);
89
+ }
90
+
91
+ .result {
92
+ margin-top: 24px;
93
+ padding: 20px;
94
+ background: #f0f9ff;
95
+ border-radius: 8px;
96
+ display: none;
97
+ }
98
+
99
+ .result.success {
100
+ display: block;
101
+ background: #10b981;
102
+ color: white;
103
+ padding: 16px 20px;
104
+ border-radius: 8px;
105
+ }
106
+
107
+ .result.error {
108
+ display: block;
109
+ background: #ef4444;
110
+ color: white;
111
+ padding: 16px 20px;
112
+ border-radius: 8px;
113
+ }
114
+
115
+ .result-title {
116
+ font-size: 18px;
117
+ font-weight: 600;
118
+ margin-bottom: 8px;
119
+ }
120
+
121
+ .result-value {
122
+ font-size: 24px;
123
+ font-weight: 700;
124
+ margin-bottom: 8px;
125
+ word-break: break-all;
126
+ }
127
+
128
+ .copy-button {
129
+ background: #667eea;
130
+ color: white;
131
+ border: none;
132
+ padding: 10px 20px;
133
+ border-radius: 6px;
134
+ font-size: 14px;
135
+ cursor: pointer;
136
+ margin-top: 12px;
137
+ transition: background-color 0.3s;
138
+ }
139
+
140
+ .copy-button:hover {
141
+ background: #5568d3;
142
+ }
143
+
144
+ .copy-button:active {
145
+ transform: scale(0.95);
146
+ }
147
+
148
+ .error-message {
149
+ color: #dc2626;
150
+ font-size: 14px;
151
+ margin-top: 8px;
152
+ }
153
+
154
+ @media (max-width: 600px) {
155
+ .container {
156
+ padding: 24px;
157
+ }
158
+
159
+ h1 {
160
+ font-size: 24px;
161
+ }
162
+ }
163
+ </style>
164
+ </head>
165
+ <body>
166
+ <div class="container">
167
+ <h1>Confidant - Compartilhar Segredos</h1>
168
+
169
+ <form id="secretForm">
170
+ <div class="form-group">
171
+ <label for="secret">Segredo (obrigatório)</label>
172
+ <input type="text" id="secret" name="secret" required placeholder="Digite seu segredo aqui...">
173
+ </div>
174
+
175
+ <div class="form-group">
176
+ <label for="ttl">TTL (milissegundos) - Opcional</label>
177
+ <input type="number" id="ttl" name="ttl" min="1" placeholder="3600000 (1 hora)">
178
+ </div>
179
+
180
+ <div class="form-group">
181
+ <label for="maxAccessCount">Número Máximo de Acessos - Opcional</label>
182
+ <input type="number" id="maxAccessCount" name="maxAccessCount" min="1" placeholder="3">
183
+ </div>
184
+
185
+ <button type="submit">Criar Segredo</button>
186
+ </form>
187
+
188
+ <div id="result" class="result">
189
+ <div class="result-title" id="resultTitle"></div>
190
+ <div class="result-value" id="resultValue"></div>
191
+ <button id="copyButton" class="copy-button">Copiar ID</button>
192
+ </div>
193
+
194
+ <div id="errorMessage" class="error-message"></div>
195
+ </div>
196
+
197
+ <script>
198
+ const API_URL = 'http://localhost:3000';
199
+
200
+ document.getElementById('secretForm').addEventListener('submit', async (e) => {
201
+ e.preventDefault();
202
+
203
+ const secret = document.getElementById('secret').value;
204
+ const ttl = document.getElementById('ttl').value ? parseInt(document.getElementById('ttl').value) : undefined;
205
+ const maxAccessCount = document.getElementById('maxAccessCount').value ? parseInt(document.getElementById('maxAccessCount').value) : undefined;
206
+
207
+ if (!secret || secret.trim() === '') {
208
+ showError('Por favor, digite um segredo.');
209
+ return;
210
+ }
211
+
212
+ try {
213
+ const response = await fetch(`${API_URL}/secrets`, {
214
+ method: 'POST',
215
+ headers: {
216
+ 'Content-Type': 'application/json'
217
+ },
218
+ body: JSON.stringify({
219
+ secret: secret,
220
+ ttl: ttl,
221
+ maxAccessCount: maxAccessCount
222
+ })
223
+ });
224
+
225
+ const data = await response.json();
226
+
227
+ if (response.status === 201) {
228
+ showSuccess(data.id);
229
+ } else {
230
+ showError('Erro ao criar segredo. Tente novamente.');
231
+ }
232
+ } catch (error) {
233
+ showError('Erro de conexão. Tente novamente.');
234
+ }
235
+ });
236
+
237
+ function showSuccess(secretId) {
238
+ const resultDiv = document.getElementById('result');
239
+ const resultTitle = document.getElementById('resultTitle');
240
+ const resultValue = document.getElementById('resultValue');
241
+ const copyButton = document.getElementById('copyButton');
242
+ const errorMessage = document.getElementById('errorMessage');
243
+
244
+ resultDiv.style.display = 'block';
245
+ resultDiv.className = 'result success';
246
+
247
+ resultTitle.textContent = 'Segredo Criado com Sucesso!';
248
+ resultValue.textContent = `ID: ${secretId}`;
249
+
250
+ copyButton.style.display = 'block';
251
+ errorMessage.style.display = 'none';
252
+
253
+ copyToClipboard(secretId);
254
+ }
255
+
256
+ function showError(message) {
257
+ const resultDiv = document.getElementById('result');
258
+ const resultTitle = document.getElementById('resultTitle');
259
+ const resultValue = document.getElementById('resultValue');
260
+ const copyButton = document.getElementById('copyButton');
261
+ const errorMessage = document.getElementById('errorMessage');
262
+
263
+ resultDiv.style.display = 'block';
264
+ resultDiv.className = 'result error';
265
+
266
+ resultTitle.textContent = 'Erro';
267
+ resultValue.textContent = '';
268
+
269
+ copyButton.style.display = 'none';
270
+ errorMessage.textContent = message;
271
+ }
272
+
273
+ function copyToClipboard(text) {
274
+ if (navigator.clipboard && navigator.clipboard.writeText) {
275
+ navigator.clipboard.writeText(text)
276
+ .then(() => {
277
+ const copyButton = document.getElementById('copyButton');
278
+ copyButton.textContent = 'Copiado!';
279
+ setTimeout(() => {
280
+ copyButton.textContent = 'Copiar ID';
281
+ }, 2000);
282
+ })
283
+ .catch(err => {
284
+ console.error('Failed to copy: ', err);
285
+ // Fallback: show ID in a selectable text box
286
+ const resultValue = document.getElementById('resultValue');
287
+ resultValue.contentEditable = true;
288
+ resultValue.focus();
289
+ document.execCommand('selectAll');
290
+ });
291
+ } else {
292
+ // Fallback for browsers without Clipboard API
293
+ const resultValue = document.getElementById('resultValue');
294
+ resultValue.contentEditable = true;
295
+ resultValue.focus();
296
+ document.execCommand('selectAll');
297
+
298
+ const copyButton = document.getElementById('copyButton');
299
+ copyButton.textContent = 'Copiar ID';
300
+ setTimeout(() => {
301
+ copyButton.textContent = 'Copiar ID';
302
+ }, 2000);
303
+ }
304
+ }
305
+
306
+ document.getElementById('copyButton').addEventListener('click', () => {
307
+ const resultValue = document.getElementById('resultValue');
308
+ const secretId = resultValue.textContent.replace('ID: ', '');
309
+ copyToClipboard(secretId);
310
+ });
311
+
312
+ function copyToClipboard(text) {
313
+ if (navigator.clipboard && navigator.clipboard.writeText) {
314
+ navigator.clipboard.writeText(text)
315
+ .then(() => {
316
+ const copyButton = document.getElementById('copyButton');
317
+ copyButton.textContent = 'Copiado!';
318
+ setTimeout(() => {
319
+ copyButton.textContent = 'Copiar ID';
320
+ }, 2000);
321
+ })
322
+ .catch(err => {
323
+ console.error('Failed to copy: ', err);
324
+ // Fallback: show the ID in a selectable text box
325
+ const resultValue = document.getElementById('resultValue');
326
+ resultValue.contentEditable = true;
327
+ resultValue.focus();
328
+ document.execCommand('selectAll');
329
+ });
330
+ } else {
331
+ // Fallback for browsers without Clipboard API
332
+ const resultValue = document.getElementById('resultValue');
333
+ resultValue.contentEditable = true;
334
+ resultValue.focus();
335
+ document.execCommand('selectAll');
336
+
337
+ const copyButton = document.getElementById('copyButton');
338
+ copyButton.textContent = 'Copiar ID';
339
+ setTimeout(() => {
340
+ copyButton.textContent = 'Copiar ID';
341
+ }, 2000);
342
+ }
343
+ }
344
+
345
+ document.getElementById('copyButton').addEventListener('click', () => {
346
+ const resultValue = document.getElementById('resultValue');
347
+ const secretId = resultValue.textContent.replace('ID: ', '');
348
+ copyToClipboard(secretId);
349
+ });
350
+ </script>
351
+ </body>
352
+ </html>