@lovelybunch/api 1.0.7

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 (131) hide show
  1. package/dist/lib/gait-path.d.ts +13 -0
  2. package/dist/lib/gait-path.js +57 -0
  3. package/dist/lib/project-paths.d.ts +13 -0
  4. package/dist/lib/project-paths.js +57 -0
  5. package/dist/lib/storage/file-storage.d.ts +28 -0
  6. package/dist/lib/storage/file-storage.js +224 -0
  7. package/dist/lib/symlinks/symlink-manager.d.ts +66 -0
  8. package/dist/lib/symlinks/symlink-manager.js +444 -0
  9. package/dist/lib/symlinks/types.d.ts +23 -0
  10. package/dist/lib/symlinks/types.js +4 -0
  11. package/dist/lib/terminal/context-helper.d.ts +11 -0
  12. package/dist/lib/terminal/context-helper.js +164 -0
  13. package/dist/lib/terminal/global-manager.d.ts +2 -0
  14. package/dist/lib/terminal/global-manager.js +15 -0
  15. package/dist/lib/terminal/shell-utils.d.ts +33 -0
  16. package/dist/lib/terminal/shell-utils.js +176 -0
  17. package/dist/lib/terminal/terminal-manager.d.ts +26 -0
  18. package/dist/lib/terminal/terminal-manager.js +276 -0
  19. package/dist/lib/user-preferences.d.ts +48 -0
  20. package/dist/lib/user-preferences.js +87 -0
  21. package/dist/lib/utils.d.ts +2 -0
  22. package/dist/lib/utils.js +5 -0
  23. package/dist/routes/api/symlink-status/route.d.ts +1 -0
  24. package/dist/routes/api/symlink-status/route.js +37 -0
  25. package/dist/routes/api/symlinks/[id]/route.d.ts +19 -0
  26. package/dist/routes/api/symlinks/[id]/route.js +95 -0
  27. package/dist/routes/api/symlinks/[id]/toggle/route.d.ts +11 -0
  28. package/dist/routes/api/symlinks/[id]/toggle/route.js +32 -0
  29. package/dist/routes/api/symlinks/debug/route.d.ts +1 -0
  30. package/dist/routes/api/symlinks/debug/route.js +35 -0
  31. package/dist/routes/api/symlinks/route.d.ts +9 -0
  32. package/dist/routes/api/symlinks/route.js +72 -0
  33. package/dist/routes/api/toggle-symlink/route.d.ts +2 -0
  34. package/dist/routes/api/toggle-symlink/route.js +94 -0
  35. package/dist/routes/api/v1/agents/[id]/index.d.ts +1 -0
  36. package/dist/routes/api/v1/agents/[id]/index.js +1 -0
  37. package/dist/routes/api/v1/agents/[id]/route.d.ts +3 -0
  38. package/dist/routes/api/v1/agents/[id]/route.js +163 -0
  39. package/dist/routes/api/v1/agents/index.d.ts +1 -0
  40. package/dist/routes/api/v1/agents/index.js +1 -0
  41. package/dist/routes/api/v1/agents/route.d.ts +3 -0
  42. package/dist/routes/api/v1/agents/route.js +133 -0
  43. package/dist/routes/api/v1/ai/index.d.ts +3 -0
  44. package/dist/routes/api/v1/ai/index.js +5 -0
  45. package/dist/routes/api/v1/ai/route.d.ts +8 -0
  46. package/dist/routes/api/v1/ai/route.js +86 -0
  47. package/dist/routes/api/v1/chats/[id]/index.d.ts +3 -0
  48. package/dist/routes/api/v1/chats/[id]/index.js +6 -0
  49. package/dist/routes/api/v1/chats/[id]/route.d.ts +12 -0
  50. package/dist/routes/api/v1/chats/[id]/route.js +31 -0
  51. package/dist/routes/api/v1/chats/index.d.ts +3 -0
  52. package/dist/routes/api/v1/chats/index.js +6 -0
  53. package/dist/routes/api/v1/chats/route.d.ts +32 -0
  54. package/dist/routes/api/v1/chats/route.js +67 -0
  55. package/dist/routes/api/v1/config/index.d.ts +3 -0
  56. package/dist/routes/api/v1/config/index.js +5 -0
  57. package/dist/routes/api/v1/config/route.d.ts +9 -0
  58. package/dist/routes/api/v1/config/route.js +29 -0
  59. package/dist/routes/api/v1/context/[...path]/route.d.ts +16 -0
  60. package/dist/routes/api/v1/context/[...path]/route.js +107 -0
  61. package/dist/routes/api/v1/context/architecture/route.d.ts +3 -0
  62. package/dist/routes/api/v1/context/architecture/route.js +198 -0
  63. package/dist/routes/api/v1/context/index.d.ts +3 -0
  64. package/dist/routes/api/v1/context/index.js +9 -0
  65. package/dist/routes/api/v1/context/knowledge/[filename]/index.d.ts +1 -0
  66. package/dist/routes/api/v1/context/knowledge/[filename]/index.js +1 -0
  67. package/dist/routes/api/v1/context/knowledge/[filename]/route.d.ts +3 -0
  68. package/dist/routes/api/v1/context/knowledge/[filename]/route.js +165 -0
  69. package/dist/routes/api/v1/context/knowledge/index.d.ts +1 -0
  70. package/dist/routes/api/v1/context/knowledge/index.js +1 -0
  71. package/dist/routes/api/v1/context/knowledge/route.d.ts +3 -0
  72. package/dist/routes/api/v1/context/knowledge/route.js +121 -0
  73. package/dist/routes/api/v1/context/project/route.d.ts +3 -0
  74. package/dist/routes/api/v1/context/project/route.js +153 -0
  75. package/dist/routes/api/v1/proposals/[id]/route.d.ts +337 -0
  76. package/dist/routes/api/v1/proposals/[id]/route.js +99 -0
  77. package/dist/routes/api/v1/proposals/index.d.ts +3 -0
  78. package/dist/routes/api/v1/proposals/index.js +10 -0
  79. package/dist/routes/api/v1/proposals/route.d.ts +315 -0
  80. package/dist/routes/api/v1/proposals/route.js +103 -0
  81. package/dist/routes/api/v1/resources/[id]/index.d.ts +3 -0
  82. package/dist/routes/api/v1/resources/[id]/index.js +7 -0
  83. package/dist/routes/api/v1/resources/[id]/route.d.ts +46 -0
  84. package/dist/routes/api/v1/resources/[id]/route.js +143 -0
  85. package/dist/routes/api/v1/resources/[id]/thumbnail/index.d.ts +3 -0
  86. package/dist/routes/api/v1/resources/[id]/thumbnail/index.js +5 -0
  87. package/dist/routes/api/v1/resources/[id]/thumbnail/route.d.ts +2 -0
  88. package/dist/routes/api/v1/resources/[id]/thumbnail/route.js +50 -0
  89. package/dist/routes/api/v1/resources/index.d.ts +3 -0
  90. package/dist/routes/api/v1/resources/index.js +6 -0
  91. package/dist/routes/api/v1/resources/route.d.ts +51 -0
  92. package/dist/routes/api/v1/resources/route.js +147 -0
  93. package/dist/routes/api/v1/search/route.d.ts +3 -0
  94. package/dist/routes/api/v1/search/route.js +39 -0
  95. package/dist/routes/api/v1/terminal/[proposalId]/create/index.d.ts +3 -0
  96. package/dist/routes/api/v1/terminal/[proposalId]/create/index.js +5 -0
  97. package/dist/routes/api/v1/terminal/[proposalId]/create/route.d.ts +10 -0
  98. package/dist/routes/api/v1/terminal/[proposalId]/create/route.js +27 -0
  99. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.d.ts +3 -0
  100. package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.js +5 -0
  101. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.d.ts +10 -0
  102. package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.js +21 -0
  103. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.d.ts +3 -0
  104. package/dist/routes/api/v1/terminal/[proposalId]/resize/index.js +5 -0
  105. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.d.ts +10 -0
  106. package/dist/routes/api/v1/terminal/[proposalId]/resize/route.js +21 -0
  107. package/dist/routes/api/v1/terminal/sessions/index.d.ts +3 -0
  108. package/dist/routes/api/v1/terminal/sessions/index.js +5 -0
  109. package/dist/routes/api/v1/terminal/sessions/route.d.ts +6 -0
  110. package/dist/routes/api/v1/terminal/sessions/route.js +29 -0
  111. package/dist/routes/api/v1/user/index.d.ts +3 -0
  112. package/dist/routes/api/v1/user/index.js +5 -0
  113. package/dist/routes/api/v1/user/preferences/route.d.ts +11 -0
  114. package/dist/routes/api/v1/user/preferences/route.js +31 -0
  115. package/dist/routes/api/v1/user/profile/route.d.ts +11 -0
  116. package/dist/routes/api/v1/user/profile/route.js +31 -0
  117. package/dist/routes/api/v1/user/settings/index.d.ts +1 -0
  118. package/dist/routes/api/v1/user/settings/index.js +1 -0
  119. package/dist/routes/api/v1/user/settings/route.d.ts +3 -0
  120. package/dist/routes/api/v1/user/settings/route.js +51 -0
  121. package/dist/server-with-static.d.ts +4 -0
  122. package/dist/server-with-static.js +144 -0
  123. package/dist/server.d.ts +1 -0
  124. package/dist/server.js +91 -0
  125. package/package.json +42 -0
  126. package/static/assets/index-BvTnrm0O.js +576 -0
  127. package/static/assets/index-Cm5dZHTl.css +33 -0
  128. package/static/assets/index-ORkAkJNi.js +576 -0
  129. package/static/assets/index-_Keadpms.js +576 -0
  130. package/static/index.html +17 -0
  131. package/static/vite.svg +1 -0
@@ -0,0 +1,315 @@
1
+ import { Context } from 'hono';
2
+ export declare function GET(c: Context): Promise<(Response & import("hono").TypedResponse<{
3
+ success: true;
4
+ data: {
5
+ id: string;
6
+ intent: string;
7
+ content?: string;
8
+ author: {
9
+ type: import("@lovelybunch/types").AuthorType;
10
+ id: string;
11
+ name: string;
12
+ email?: string;
13
+ };
14
+ productSpecRef?: string;
15
+ planSteps: {
16
+ id: string;
17
+ description: string;
18
+ command?: string;
19
+ expectedOutcome?: string;
20
+ status: "pending" | "in-progress" | "completed" | "failed";
21
+ output?: string;
22
+ error?: string;
23
+ executedAt?: string;
24
+ }[];
25
+ evidence: {
26
+ type: "test" | "benchmark" | "screenshot" | "log" | "other";
27
+ description: string;
28
+ data: any;
29
+ timestamp: string;
30
+ }[];
31
+ policies: {
32
+ id: string;
33
+ name: string;
34
+ description: string;
35
+ status: "pending" | "passed" | "failed" | "skipped";
36
+ message?: string;
37
+ checkedAt?: string;
38
+ }[];
39
+ featureFlags: {
40
+ id: string;
41
+ version: string;
42
+ name: string;
43
+ description: string;
44
+ type: import("@lovelybunch/types").FeatureFlagType;
45
+ defaultValue: any;
46
+ scopes: string[];
47
+ targets: {
48
+ audience: string;
49
+ value: any;
50
+ percentage?: number;
51
+ }[];
52
+ killSwitch: boolean;
53
+ dependencies: string[];
54
+ createdAt: string;
55
+ updatedAt: string;
56
+ }[];
57
+ experiments: {
58
+ id: string;
59
+ name: string;
60
+ hypothesis: string;
61
+ variants: {
62
+ id: string;
63
+ name: string;
64
+ description: string;
65
+ allocation: number;
66
+ config: {
67
+ [x: string]: any;
68
+ };
69
+ }[];
70
+ allocation: {
71
+ method: "random" | "deterministic" | "weighted";
72
+ seed?: string;
73
+ totalAllocation: number;
74
+ };
75
+ successMetrics: string[];
76
+ guardrailMetrics: {
77
+ name: string;
78
+ threshold: number;
79
+ comparison: "greater" | "less" | "equal";
80
+ action: "alert" | "pause" | "stop";
81
+ }[];
82
+ stopRules: {
83
+ metric: string;
84
+ condition: string;
85
+ action: "stop" | "pause";
86
+ }[];
87
+ analysisConfig: {
88
+ confidenceLevel: number;
89
+ minimumSampleSize: number;
90
+ testType: "two-tailed" | "one-tailed";
91
+ };
92
+ status: import("@lovelybunch/types").ExperimentStatus;
93
+ startedAt?: string;
94
+ endedAt?: string;
95
+ }[];
96
+ telemetryContracts: {
97
+ eventName: string;
98
+ version: string;
99
+ schema: {
100
+ [x: string]: any;
101
+ };
102
+ piiFields: {
103
+ field: string;
104
+ classification: "none" | "quasi" | "sensitive" | "highly-sensitive";
105
+ handling: "clear" | "hash" | "encrypt" | "remove";
106
+ }[];
107
+ samplingRate: number;
108
+ retentionPolicy: {
109
+ duration: number;
110
+ archiveAfter?: number;
111
+ deleteAfter: number;
112
+ };
113
+ approvals: {
114
+ approver: string;
115
+ approvedAt: string;
116
+ comment?: string;
117
+ }[];
118
+ }[];
119
+ releasePlan: {
120
+ strategy: "immediate" | "gradual" | "scheduled" | "gated";
121
+ stages?: {
122
+ name: string;
123
+ percentage: number;
124
+ duration?: number;
125
+ criteria?: string[];
126
+ }[];
127
+ schedule?: string;
128
+ rollbackPlan?: string;
129
+ };
130
+ status: import("@lovelybunch/types").CPStatus;
131
+ metadata: {
132
+ createdAt: string;
133
+ updatedAt: string;
134
+ reviewers: string[];
135
+ aiInteractions: {
136
+ id: string;
137
+ timestamp: string;
138
+ model: string;
139
+ prompt: string;
140
+ response: string;
141
+ tokens: {
142
+ prompt: number;
143
+ completion: number;
144
+ total: number;
145
+ };
146
+ cost?: number;
147
+ }[];
148
+ tags?: string[];
149
+ priority?: "low" | "medium" | "high" | "critical";
150
+ };
151
+ }[];
152
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
153
+ success: false;
154
+ error: {
155
+ code: string;
156
+ message: any;
157
+ };
158
+ }, 500, "json">)>;
159
+ export declare function POST(c: Context): Promise<(Response & import("hono").TypedResponse<{
160
+ success: true;
161
+ data: {
162
+ id: string;
163
+ intent: string;
164
+ content?: string;
165
+ author: {
166
+ type: import("@lovelybunch/types").AuthorType;
167
+ id: string;
168
+ name: string;
169
+ email?: string;
170
+ };
171
+ productSpecRef?: string;
172
+ planSteps: {
173
+ id: string;
174
+ description: string;
175
+ command?: string;
176
+ expectedOutcome?: string;
177
+ status: "pending" | "in-progress" | "completed" | "failed";
178
+ output?: string;
179
+ error?: string;
180
+ executedAt?: string;
181
+ }[];
182
+ evidence: {
183
+ type: "test" | "benchmark" | "screenshot" | "log" | "other";
184
+ description: string;
185
+ data: any;
186
+ timestamp: string;
187
+ }[];
188
+ policies: {
189
+ id: string;
190
+ name: string;
191
+ description: string;
192
+ status: "pending" | "passed" | "failed" | "skipped";
193
+ message?: string;
194
+ checkedAt?: string;
195
+ }[];
196
+ featureFlags: {
197
+ id: string;
198
+ version: string;
199
+ name: string;
200
+ description: string;
201
+ type: import("@lovelybunch/types").FeatureFlagType;
202
+ defaultValue: any;
203
+ scopes: string[];
204
+ targets: {
205
+ audience: string;
206
+ value: any;
207
+ percentage?: number;
208
+ }[];
209
+ killSwitch: boolean;
210
+ dependencies: string[];
211
+ createdAt: string;
212
+ updatedAt: string;
213
+ }[];
214
+ experiments: {
215
+ id: string;
216
+ name: string;
217
+ hypothesis: string;
218
+ variants: {
219
+ id: string;
220
+ name: string;
221
+ description: string;
222
+ allocation: number;
223
+ config: {
224
+ [x: string]: any;
225
+ };
226
+ }[];
227
+ allocation: {
228
+ method: "random" | "deterministic" | "weighted";
229
+ seed?: string;
230
+ totalAllocation: number;
231
+ };
232
+ successMetrics: string[];
233
+ guardrailMetrics: {
234
+ name: string;
235
+ threshold: number;
236
+ comparison: "greater" | "less" | "equal";
237
+ action: "alert" | "pause" | "stop";
238
+ }[];
239
+ stopRules: {
240
+ metric: string;
241
+ condition: string;
242
+ action: "stop" | "pause";
243
+ }[];
244
+ analysisConfig: {
245
+ confidenceLevel: number;
246
+ minimumSampleSize: number;
247
+ testType: "two-tailed" | "one-tailed";
248
+ };
249
+ status: import("@lovelybunch/types").ExperimentStatus;
250
+ startedAt?: string;
251
+ endedAt?: string;
252
+ }[];
253
+ telemetryContracts: {
254
+ eventName: string;
255
+ version: string;
256
+ schema: {
257
+ [x: string]: any;
258
+ };
259
+ piiFields: {
260
+ field: string;
261
+ classification: "none" | "quasi" | "sensitive" | "highly-sensitive";
262
+ handling: "clear" | "hash" | "encrypt" | "remove";
263
+ }[];
264
+ samplingRate: number;
265
+ retentionPolicy: {
266
+ duration: number;
267
+ archiveAfter?: number;
268
+ deleteAfter: number;
269
+ };
270
+ approvals: {
271
+ approver: string;
272
+ approvedAt: string;
273
+ comment?: string;
274
+ }[];
275
+ }[];
276
+ releasePlan: {
277
+ strategy: "immediate" | "gradual" | "scheduled" | "gated";
278
+ stages?: {
279
+ name: string;
280
+ percentage: number;
281
+ duration?: number;
282
+ criteria?: string[];
283
+ }[];
284
+ schedule?: string;
285
+ rollbackPlan?: string;
286
+ };
287
+ status: import("@lovelybunch/types").CPStatus;
288
+ metadata: {
289
+ createdAt: string;
290
+ updatedAt: string;
291
+ reviewers: string[];
292
+ aiInteractions: {
293
+ id: string;
294
+ timestamp: string;
295
+ model: string;
296
+ prompt: string;
297
+ response: string;
298
+ tokens: {
299
+ prompt: number;
300
+ completion: number;
301
+ total: number;
302
+ };
303
+ cost?: number;
304
+ }[];
305
+ tags?: string[];
306
+ priority?: "low" | "medium" | "high" | "critical";
307
+ };
308
+ };
309
+ }, 201, "json">) | (Response & import("hono").TypedResponse<{
310
+ success: false;
311
+ error: {
312
+ code: string;
313
+ message: any;
314
+ };
315
+ }, 500, "json">)>;
@@ -0,0 +1,103 @@
1
+ import { FileStorageAdapter } from '../../../../lib/storage/file-storage.js';
2
+ import { getAuthorInfo } from '../../../../lib/user-preferences.js';
3
+ import Fuse from 'fuse.js';
4
+ const storage = new FileStorageAdapter();
5
+ export async function GET(c) {
6
+ try {
7
+ const url = new URL(c.req.url);
8
+ const searchParams = url.searchParams;
9
+ const status = searchParams.get('status');
10
+ const author = searchParams.get('author');
11
+ const priority = searchParams.get('priority');
12
+ const tags = searchParams.get('tags')?.split(',');
13
+ const searchQuery = searchParams.get('q'); // Add search query parameter
14
+ let proposals = await storage.listCPs({
15
+ status,
16
+ author: author || undefined,
17
+ priority: priority || undefined,
18
+ tags
19
+ });
20
+ // Apply search filter if provided
21
+ if (searchQuery?.trim()) {
22
+ const fuse = new Fuse(proposals, {
23
+ keys: [
24
+ { name: 'intent', weight: 0.4 },
25
+ { name: 'id', weight: 0.3 },
26
+ { name: 'author.name', weight: 0.2 },
27
+ { name: 'metadata.tags', weight: 0.1 }
28
+ ],
29
+ threshold: 0.3,
30
+ includeScore: true
31
+ });
32
+ const searchResults = fuse.search(searchQuery);
33
+ proposals = searchResults.map(result => result.item);
34
+ }
35
+ return c.json({
36
+ success: true,
37
+ data: proposals
38
+ });
39
+ }
40
+ catch (error) {
41
+ console.error('Error listing proposals:', error);
42
+ return c.json({
43
+ success: false,
44
+ error: {
45
+ code: 'LIST_PROPOSALS_ERROR',
46
+ message: error.message
47
+ }
48
+ }, 500);
49
+ }
50
+ }
51
+ export async function POST(c) {
52
+ try {
53
+ const body = await c.req.json();
54
+ // Get author info from saved preferences if not provided
55
+ const authorInfo = await getAuthorInfo();
56
+ // Create a new proposal with required fields
57
+ const now = new Date();
58
+ const proposal = {
59
+ id: body.id || `cp-${Date.now()}`,
60
+ intent: body.intent,
61
+ content: body.content,
62
+ author: body.author || {
63
+ id: 'current-user',
64
+ name: authorInfo.name,
65
+ email: authorInfo.email,
66
+ role: 'engineer',
67
+ type: 'human'
68
+ },
69
+ planSteps: body.planSteps || [],
70
+ evidence: body.evidence || [],
71
+ policies: body.policies || [],
72
+ featureFlags: body.featureFlags || [],
73
+ experiments: body.experiments || [],
74
+ telemetryContracts: body.telemetryContracts || [],
75
+ releasePlan: body.releasePlan || { strategy: 'immediate' },
76
+ status: body.status || 'draft',
77
+ metadata: {
78
+ createdAt: now,
79
+ updatedAt: now,
80
+ reviewers: body.metadata?.reviewers || [],
81
+ aiInteractions: body.metadata?.aiInteractions || [],
82
+ tags: body.metadata?.tags || [],
83
+ priority: body.metadata?.priority || 'medium'
84
+ },
85
+ productSpecRef: body.productSpecRef
86
+ };
87
+ await storage.createCP(proposal);
88
+ return c.json({
89
+ success: true,
90
+ data: proposal
91
+ }, 201);
92
+ }
93
+ catch (error) {
94
+ console.error('Error creating proposal:', error);
95
+ return c.json({
96
+ success: false,
97
+ error: {
98
+ code: 'CREATE_PROPOSAL_ERROR',
99
+ message: error.message
100
+ }
101
+ }, 500);
102
+ }
103
+ }
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default app;
@@ -0,0 +1,7 @@
1
+ import { Hono } from 'hono';
2
+ import { GET, PUT, DELETE } from './route.js';
3
+ const app = new Hono();
4
+ app.get('/', GET);
5
+ app.put('/', PUT);
6
+ app.delete('/', DELETE);
7
+ export default app;
@@ -0,0 +1,46 @@
1
+ import { Context } from 'hono';
2
+ export declare function GET(c: Context): Promise<Response>;
3
+ export declare function PUT(c: Context): Promise<(Response & import("hono").TypedResponse<{
4
+ success: false;
5
+ error: {
6
+ code: string;
7
+ message: string;
8
+ };
9
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
10
+ success: true;
11
+ data: {
12
+ id: string;
13
+ name: string;
14
+ type: string;
15
+ size: number;
16
+ uploadedAt: string;
17
+ metadata: {
18
+ tags?: string[];
19
+ description?: string;
20
+ };
21
+ path: string;
22
+ thumbnailPath?: string;
23
+ };
24
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
25
+ success: false;
26
+ error: {
27
+ code: string;
28
+ message: any;
29
+ };
30
+ }, 500, "json">)>;
31
+ export declare function DELETE(c: Context): Promise<(Response & import("hono").TypedResponse<{
32
+ success: false;
33
+ error: {
34
+ code: string;
35
+ message: string;
36
+ };
37
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
38
+ success: true;
39
+ message: string;
40
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
41
+ success: false;
42
+ error: {
43
+ code: string;
44
+ message: any;
45
+ };
46
+ }, 500, "json">)>;
@@ -0,0 +1,143 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ const RESOURCES_DIR = '.gait/resources';
4
+ const FILES_DIR = path.join(RESOURCES_DIR, 'files');
5
+ const METADATA_DIR = path.join(RESOURCES_DIR, 'metadata');
6
+ async function getResourceMetadata(id) {
7
+ try {
8
+ const metadataPath = path.join(METADATA_DIR, `${id}.json`);
9
+ const content = await fs.readFile(metadataPath, 'utf-8');
10
+ return JSON.parse(content);
11
+ }
12
+ catch (error) {
13
+ if (error.code === 'ENOENT')
14
+ return null;
15
+ throw error;
16
+ }
17
+ }
18
+ async function saveResourceMetadata(resource) {
19
+ const metadataPath = path.join(METADATA_DIR, `${resource.id}.json`);
20
+ await fs.writeFile(metadataPath, JSON.stringify(resource, null, 2), 'utf-8');
21
+ }
22
+ export async function GET(c) {
23
+ try {
24
+ const id = c.req.param('id');
25
+ const resource = await getResourceMetadata(id);
26
+ if (!resource) {
27
+ return c.json({
28
+ success: false,
29
+ error: {
30
+ code: 'RESOURCE_NOT_FOUND',
31
+ message: 'Resource not found'
32
+ }
33
+ }, 404);
34
+ }
35
+ const url = new URL(c.req.url);
36
+ const download = url.searchParams.get('download');
37
+ if (download === 'true') {
38
+ // Return the actual file
39
+ const filePath = path.join(FILES_DIR, resource.path);
40
+ const fileBuffer = await fs.readFile(filePath);
41
+ return new Response(fileBuffer, {
42
+ headers: {
43
+ 'Content-Type': resource.type,
44
+ 'Content-Disposition': `attachment; filename="${resource.name}"`,
45
+ 'Content-Length': resource.size.toString()
46
+ }
47
+ });
48
+ }
49
+ // Return resource metadata
50
+ return c.json({
51
+ success: true,
52
+ data: resource
53
+ });
54
+ }
55
+ catch (error) {
56
+ console.error('Error getting resource:', error);
57
+ return c.json({
58
+ success: false,
59
+ error: {
60
+ code: 'GET_RESOURCE_ERROR',
61
+ message: error.message
62
+ }
63
+ }, 500);
64
+ }
65
+ }
66
+ export async function PUT(c) {
67
+ try {
68
+ const id = c.req.param('id');
69
+ const resource = await getResourceMetadata(id);
70
+ if (!resource) {
71
+ return c.json({
72
+ success: false,
73
+ error: {
74
+ code: 'RESOURCE_NOT_FOUND',
75
+ message: 'Resource not found'
76
+ }
77
+ }, 404);
78
+ }
79
+ const updates = await c.req.json();
80
+ const updatedResource = {
81
+ ...resource,
82
+ metadata: {
83
+ ...resource.metadata,
84
+ ...updates.metadata
85
+ }
86
+ };
87
+ await saveResourceMetadata(updatedResource);
88
+ return c.json({
89
+ success: true,
90
+ data: updatedResource
91
+ });
92
+ }
93
+ catch (error) {
94
+ console.error('Error updating resource:', error);
95
+ return c.json({
96
+ success: false,
97
+ error: {
98
+ code: 'UPDATE_RESOURCE_ERROR',
99
+ message: error.message
100
+ }
101
+ }, 500);
102
+ }
103
+ }
104
+ export async function DELETE(c) {
105
+ try {
106
+ const id = c.req.param('id');
107
+ const resource = await getResourceMetadata(id);
108
+ if (!resource) {
109
+ return c.json({
110
+ success: false,
111
+ error: {
112
+ code: 'RESOURCE_NOT_FOUND',
113
+ message: 'Resource not found'
114
+ }
115
+ }, 404);
116
+ }
117
+ // Delete the file
118
+ const filePath = path.join(FILES_DIR, resource.path);
119
+ await fs.unlink(filePath).catch(() => { }); // Ignore if file doesn't exist
120
+ // Delete thumbnail if exists
121
+ if (resource.thumbnailPath) {
122
+ const thumbnailPath = path.join(RESOURCES_DIR, 'thumbnails', resource.thumbnailPath);
123
+ await fs.unlink(thumbnailPath).catch(() => { }); // Ignore if thumbnail doesn't exist
124
+ }
125
+ // Delete metadata
126
+ const metadataPath = path.join(METADATA_DIR, `${resource.id}.json`);
127
+ await fs.unlink(metadataPath);
128
+ return c.json({
129
+ success: true,
130
+ message: 'Resource deleted successfully'
131
+ });
132
+ }
133
+ catch (error) {
134
+ console.error('Error deleting resource:', error);
135
+ return c.json({
136
+ success: false,
137
+ error: {
138
+ code: 'DELETE_RESOURCE_ERROR',
139
+ message: error.message
140
+ }
141
+ }, 500);
142
+ }
143
+ }
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default app;
@@ -0,0 +1,5 @@
1
+ import { Hono } from 'hono';
2
+ import { GET } from './route.js';
3
+ const app = new Hono();
4
+ app.get('/', GET);
5
+ export default app;
@@ -0,0 +1,2 @@
1
+ import { Context } from 'hono';
2
+ export declare function GET(c: Context): Promise<Response>;
@@ -0,0 +1,50 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ const RESOURCES_DIR = '.gait/resources';
4
+ const METADATA_DIR = path.join(RESOURCES_DIR, 'metadata');
5
+ const THUMBNAILS_DIR = path.join(RESOURCES_DIR, 'thumbnails');
6
+ async function getResourceMetadata(id) {
7
+ try {
8
+ const metadataPath = path.join(METADATA_DIR, `${id}.json`);
9
+ const content = await fs.readFile(metadataPath, 'utf-8');
10
+ return JSON.parse(content);
11
+ }
12
+ catch (error) {
13
+ if (error.code === 'ENOENT')
14
+ return null;
15
+ throw error;
16
+ }
17
+ }
18
+ export async function GET(c) {
19
+ try {
20
+ const id = c.req.param('id');
21
+ const resource = await getResourceMetadata(id);
22
+ if (!resource || !resource.thumbnailPath) {
23
+ return c.json({
24
+ success: false,
25
+ error: {
26
+ code: 'THUMBNAIL_NOT_FOUND',
27
+ message: 'Thumbnail not found'
28
+ }
29
+ }, 404);
30
+ }
31
+ const thumbnailPath = path.join(THUMBNAILS_DIR, resource.thumbnailPath);
32
+ const thumbnailBuffer = await fs.readFile(thumbnailPath);
33
+ return new Response(thumbnailBuffer, {
34
+ headers: {
35
+ 'Content-Type': 'image/jpeg',
36
+ 'Cache-Control': 'public, max-age=31536000'
37
+ }
38
+ });
39
+ }
40
+ catch (error) {
41
+ console.error('Error serving thumbnail:', error);
42
+ return c.json({
43
+ success: false,
44
+ error: {
45
+ code: 'SERVE_THUMBNAIL_ERROR',
46
+ message: error.message
47
+ }
48
+ }, 500);
49
+ }
50
+ }
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ declare const app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default app;