@hasna/microservices 0.0.9 → 0.0.11

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 (100) hide show
  1. package/bin/index.js +236 -36
  2. package/bin/mcp.js +153 -4
  3. package/dist/index.js +120 -3
  4. package/microservices/microservice-analytics/package.json +27 -0
  5. package/microservices/microservice-analytics/src/cli/index.ts +373 -0
  6. package/microservices/microservice-analytics/src/db/analytics.ts +564 -0
  7. package/microservices/microservice-analytics/src/db/database.ts +93 -0
  8. package/microservices/microservice-analytics/src/db/migrations.ts +50 -0
  9. package/microservices/microservice-analytics/src/index.ts +37 -0
  10. package/microservices/microservice-analytics/src/mcp/index.ts +334 -0
  11. package/microservices/microservice-assets/package.json +27 -0
  12. package/microservices/microservice-assets/src/cli/index.ts +375 -0
  13. package/microservices/microservice-assets/src/db/assets.ts +370 -0
  14. package/microservices/microservice-assets/src/db/database.ts +93 -0
  15. package/microservices/microservice-assets/src/db/migrations.ts +51 -0
  16. package/microservices/microservice-assets/src/index.ts +32 -0
  17. package/microservices/microservice-assets/src/mcp/index.ts +346 -0
  18. package/microservices/microservice-compliance/package.json +27 -0
  19. package/microservices/microservice-compliance/src/cli/index.ts +467 -0
  20. package/microservices/microservice-compliance/src/db/compliance.ts +633 -0
  21. package/microservices/microservice-compliance/src/db/database.ts +93 -0
  22. package/microservices/microservice-compliance/src/db/migrations.ts +63 -0
  23. package/microservices/microservice-compliance/src/index.ts +46 -0
  24. package/microservices/microservice-compliance/src/mcp/index.ts +438 -0
  25. package/microservices/microservice-habits/package.json +27 -0
  26. package/microservices/microservice-habits/src/cli/index.ts +315 -0
  27. package/microservices/microservice-habits/src/db/database.ts +93 -0
  28. package/microservices/microservice-habits/src/db/habits.ts +451 -0
  29. package/microservices/microservice-habits/src/db/migrations.ts +46 -0
  30. package/microservices/microservice-habits/src/index.ts +31 -0
  31. package/microservices/microservice-habits/src/mcp/index.ts +313 -0
  32. package/microservices/microservice-health/package.json +27 -0
  33. package/microservices/microservice-health/src/cli/index.ts +484 -0
  34. package/microservices/microservice-health/src/db/database.ts +93 -0
  35. package/microservices/microservice-health/src/db/health.ts +708 -0
  36. package/microservices/microservice-health/src/db/migrations.ts +70 -0
  37. package/microservices/microservice-health/src/index.ts +63 -0
  38. package/microservices/microservice-health/src/mcp/index.ts +437 -0
  39. package/microservices/microservice-leads/package.json +27 -0
  40. package/microservices/microservice-leads/src/cli/index.ts +596 -0
  41. package/microservices/microservice-leads/src/db/database.ts +93 -0
  42. package/microservices/microservice-leads/src/db/leads.ts +520 -0
  43. package/microservices/microservice-leads/src/db/lists.ts +151 -0
  44. package/microservices/microservice-leads/src/db/migrations.ts +93 -0
  45. package/microservices/microservice-leads/src/index.ts +65 -0
  46. package/microservices/microservice-leads/src/lib/enrichment.ts +202 -0
  47. package/microservices/microservice-leads/src/lib/scoring.ts +134 -0
  48. package/microservices/microservice-leads/src/mcp/index.ts +533 -0
  49. package/microservices/microservice-notifications/package.json +27 -0
  50. package/microservices/microservice-notifications/src/cli/index.ts +349 -0
  51. package/microservices/microservice-notifications/src/db/database.ts +93 -0
  52. package/microservices/microservice-notifications/src/db/migrations.ts +62 -0
  53. package/microservices/microservice-notifications/src/db/notifications.ts +509 -0
  54. package/microservices/microservice-notifications/src/index.ts +41 -0
  55. package/microservices/microservice-notifications/src/mcp/index.ts +422 -0
  56. package/microservices/microservice-products/package.json +27 -0
  57. package/microservices/microservice-products/src/cli/index.ts +416 -0
  58. package/microservices/microservice-products/src/db/categories.ts +154 -0
  59. package/microservices/microservice-products/src/db/database.ts +93 -0
  60. package/microservices/microservice-products/src/db/migrations.ts +58 -0
  61. package/microservices/microservice-products/src/db/pricing-tiers.ts +66 -0
  62. package/microservices/microservice-products/src/db/products.ts +452 -0
  63. package/microservices/microservice-products/src/index.ts +53 -0
  64. package/microservices/microservice-products/src/mcp/index.ts +453 -0
  65. package/microservices/microservice-projects/package.json +27 -0
  66. package/microservices/microservice-projects/src/cli/index.ts +480 -0
  67. package/microservices/microservice-projects/src/db/database.ts +93 -0
  68. package/microservices/microservice-projects/src/db/migrations.ts +65 -0
  69. package/microservices/microservice-projects/src/db/projects.ts +715 -0
  70. package/microservices/microservice-projects/src/index.ts +57 -0
  71. package/microservices/microservice-projects/src/mcp/index.ts +501 -0
  72. package/microservices/microservice-proposals/package.json +27 -0
  73. package/microservices/microservice-proposals/src/cli/index.ts +400 -0
  74. package/microservices/microservice-proposals/src/db/database.ts +93 -0
  75. package/microservices/microservice-proposals/src/db/migrations.ts +52 -0
  76. package/microservices/microservice-proposals/src/db/proposals.ts +532 -0
  77. package/microservices/microservice-proposals/src/index.ts +37 -0
  78. package/microservices/microservice-proposals/src/mcp/index.ts +375 -0
  79. package/microservices/microservice-reading/package.json +27 -0
  80. package/microservices/microservice-reading/src/cli/index.ts +464 -0
  81. package/microservices/microservice-reading/src/db/database.ts +93 -0
  82. package/microservices/microservice-reading/src/db/migrations.ts +59 -0
  83. package/microservices/microservice-reading/src/db/reading.ts +524 -0
  84. package/microservices/microservice-reading/src/index.ts +51 -0
  85. package/microservices/microservice-reading/src/mcp/index.ts +368 -0
  86. package/microservices/microservice-travel/package.json +27 -0
  87. package/microservices/microservice-travel/src/cli/index.ts +505 -0
  88. package/microservices/microservice-travel/src/db/database.ts +93 -0
  89. package/microservices/microservice-travel/src/db/migrations.ts +77 -0
  90. package/microservices/microservice-travel/src/db/travel.ts +802 -0
  91. package/microservices/microservice-travel/src/index.ts +60 -0
  92. package/microservices/microservice-travel/src/mcp/index.ts +495 -0
  93. package/microservices/microservice-wiki/package.json +27 -0
  94. package/microservices/microservice-wiki/src/cli/index.ts +345 -0
  95. package/microservices/microservice-wiki/src/db/database.ts +93 -0
  96. package/microservices/microservice-wiki/src/db/migrations.ts +55 -0
  97. package/microservices/microservice-wiki/src/db/wiki.ts +395 -0
  98. package/microservices/microservice-wiki/src/index.ts +32 -0
  99. package/microservices/microservice-wiki/src/mcp/index.ts +344 -0
  100. package/package.json +1 -1
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Asset and Collection CRUD operations
3
+ */
4
+
5
+ import { getDatabase } from "./database.js";
6
+
7
+ // --- Asset types ---
8
+
9
+ export interface Asset {
10
+ id: string;
11
+ name: string;
12
+ description: string | null;
13
+ type: string | null;
14
+ file_path: string | null;
15
+ file_size: number | null;
16
+ mime_type: string | null;
17
+ dimensions: string | null;
18
+ tags: string[];
19
+ category: string | null;
20
+ metadata: Record<string, unknown>;
21
+ uploaded_by: string | null;
22
+ created_at: string;
23
+ updated_at: string;
24
+ }
25
+
26
+ interface AssetRow {
27
+ id: string;
28
+ name: string;
29
+ description: string | null;
30
+ type: string | null;
31
+ file_path: string | null;
32
+ file_size: number | null;
33
+ mime_type: string | null;
34
+ dimensions: string | null;
35
+ tags: string;
36
+ category: string | null;
37
+ metadata: string;
38
+ uploaded_by: string | null;
39
+ created_at: string;
40
+ updated_at: string;
41
+ }
42
+
43
+ function rowToAsset(row: AssetRow): Asset {
44
+ return {
45
+ ...row,
46
+ tags: JSON.parse(row.tags || "[]"),
47
+ metadata: JSON.parse(row.metadata || "{}"),
48
+ };
49
+ }
50
+
51
+ export interface CreateAssetInput {
52
+ name: string;
53
+ description?: string;
54
+ type?: string;
55
+ file_path?: string;
56
+ file_size?: number;
57
+ mime_type?: string;
58
+ dimensions?: string;
59
+ tags?: string[];
60
+ category?: string;
61
+ metadata?: Record<string, unknown>;
62
+ uploaded_by?: string;
63
+ }
64
+
65
+ export function createAsset(input: CreateAssetInput): Asset {
66
+ const db = getDatabase();
67
+ const id = crypto.randomUUID();
68
+ const tags = JSON.stringify(input.tags || []);
69
+ const metadata = JSON.stringify(input.metadata || {});
70
+
71
+ db.prepare(
72
+ `INSERT INTO assets (id, name, description, type, file_path, file_size, mime_type, dimensions, tags, category, metadata, uploaded_by)
73
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
74
+ ).run(
75
+ id,
76
+ input.name,
77
+ input.description || null,
78
+ input.type || null,
79
+ input.file_path || null,
80
+ input.file_size ?? null,
81
+ input.mime_type || null,
82
+ input.dimensions || null,
83
+ tags,
84
+ input.category || null,
85
+ metadata,
86
+ input.uploaded_by || null
87
+ );
88
+
89
+ return getAsset(id)!;
90
+ }
91
+
92
+ export function getAsset(id: string): Asset | null {
93
+ const db = getDatabase();
94
+ const row = db.prepare("SELECT * FROM assets WHERE id = ?").get(id) as AssetRow | null;
95
+ return row ? rowToAsset(row) : null;
96
+ }
97
+
98
+ export interface ListAssetsOptions {
99
+ search?: string;
100
+ type?: string;
101
+ category?: string;
102
+ tag?: string;
103
+ uploaded_by?: string;
104
+ limit?: number;
105
+ offset?: number;
106
+ }
107
+
108
+ export function listAssets(options: ListAssetsOptions = {}): Asset[] {
109
+ const db = getDatabase();
110
+ const conditions: string[] = [];
111
+ const params: unknown[] = [];
112
+
113
+ if (options.search) {
114
+ conditions.push("(name LIKE ? OR description LIKE ? OR tags LIKE ?)");
115
+ const q = `%${options.search}%`;
116
+ params.push(q, q, q);
117
+ }
118
+
119
+ if (options.type) {
120
+ conditions.push("type = ?");
121
+ params.push(options.type);
122
+ }
123
+
124
+ if (options.category) {
125
+ conditions.push("category = ?");
126
+ params.push(options.category);
127
+ }
128
+
129
+ if (options.tag) {
130
+ conditions.push("tags LIKE ?");
131
+ params.push(`%${options.tag}%`);
132
+ }
133
+
134
+ if (options.uploaded_by) {
135
+ conditions.push("uploaded_by = ?");
136
+ params.push(options.uploaded_by);
137
+ }
138
+
139
+ let sql = "SELECT * FROM assets";
140
+ if (conditions.length > 0) {
141
+ sql += " WHERE " + conditions.join(" AND ");
142
+ }
143
+ sql += " ORDER BY created_at DESC";
144
+
145
+ if (options.limit) {
146
+ sql += " LIMIT ?";
147
+ params.push(options.limit);
148
+ }
149
+ if (options.offset) {
150
+ sql += " OFFSET ?";
151
+ params.push(options.offset);
152
+ }
153
+
154
+ const rows = db.prepare(sql).all(...params) as AssetRow[];
155
+ return rows.map(rowToAsset);
156
+ }
157
+
158
+ export interface UpdateAssetInput {
159
+ name?: string;
160
+ description?: string;
161
+ type?: string;
162
+ file_path?: string;
163
+ file_size?: number;
164
+ mime_type?: string;
165
+ dimensions?: string;
166
+ tags?: string[];
167
+ category?: string;
168
+ metadata?: Record<string, unknown>;
169
+ uploaded_by?: string;
170
+ }
171
+
172
+ export function updateAsset(id: string, input: UpdateAssetInput): Asset | null {
173
+ const db = getDatabase();
174
+ const existing = getAsset(id);
175
+ if (!existing) return null;
176
+
177
+ const sets: string[] = [];
178
+ const params: unknown[] = [];
179
+
180
+ if (input.name !== undefined) {
181
+ sets.push("name = ?");
182
+ params.push(input.name);
183
+ }
184
+ if (input.description !== undefined) {
185
+ sets.push("description = ?");
186
+ params.push(input.description);
187
+ }
188
+ if (input.type !== undefined) {
189
+ sets.push("type = ?");
190
+ params.push(input.type);
191
+ }
192
+ if (input.file_path !== undefined) {
193
+ sets.push("file_path = ?");
194
+ params.push(input.file_path);
195
+ }
196
+ if (input.file_size !== undefined) {
197
+ sets.push("file_size = ?");
198
+ params.push(input.file_size);
199
+ }
200
+ if (input.mime_type !== undefined) {
201
+ sets.push("mime_type = ?");
202
+ params.push(input.mime_type);
203
+ }
204
+ if (input.dimensions !== undefined) {
205
+ sets.push("dimensions = ?");
206
+ params.push(input.dimensions);
207
+ }
208
+ if (input.tags !== undefined) {
209
+ sets.push("tags = ?");
210
+ params.push(JSON.stringify(input.tags));
211
+ }
212
+ if (input.category !== undefined) {
213
+ sets.push("category = ?");
214
+ params.push(input.category);
215
+ }
216
+ if (input.metadata !== undefined) {
217
+ sets.push("metadata = ?");
218
+ params.push(JSON.stringify(input.metadata));
219
+ }
220
+ if (input.uploaded_by !== undefined) {
221
+ sets.push("uploaded_by = ?");
222
+ params.push(input.uploaded_by);
223
+ }
224
+
225
+ if (sets.length === 0) return existing;
226
+
227
+ sets.push("updated_at = datetime('now')");
228
+ params.push(id);
229
+
230
+ db.prepare(
231
+ `UPDATE assets SET ${sets.join(", ")} WHERE id = ?`
232
+ ).run(...params);
233
+
234
+ return getAsset(id);
235
+ }
236
+
237
+ export function deleteAsset(id: string): boolean {
238
+ const db = getDatabase();
239
+ const result = db.prepare("DELETE FROM assets WHERE id = ?").run(id);
240
+ return result.changes > 0;
241
+ }
242
+
243
+ export function searchAssets(query: string): Asset[] {
244
+ return listAssets({ search: query });
245
+ }
246
+
247
+ export function listByType(type: string): Asset[] {
248
+ return listAssets({ type });
249
+ }
250
+
251
+ export function listByTag(tag: string): Asset[] {
252
+ return listAssets({ tag });
253
+ }
254
+
255
+ export function listByCategory(category: string): Asset[] {
256
+ return listAssets({ category });
257
+ }
258
+
259
+ export interface AssetStats {
260
+ total_assets: number;
261
+ total_size: number;
262
+ by_type: Record<string, number>;
263
+ by_category: Record<string, number>;
264
+ }
265
+
266
+ export function getAssetStats(): AssetStats {
267
+ const db = getDatabase();
268
+
269
+ const totalRow = db.prepare("SELECT COUNT(*) as count FROM assets").get() as { count: number };
270
+ const sizeRow = db.prepare("SELECT COALESCE(SUM(file_size), 0) as total FROM assets").get() as { total: number };
271
+
272
+ const typeRows = db.prepare(
273
+ "SELECT type, COUNT(*) as count FROM assets WHERE type IS NOT NULL GROUP BY type"
274
+ ).all() as { type: string; count: number }[];
275
+
276
+ const categoryRows = db.prepare(
277
+ "SELECT category, COUNT(*) as count FROM assets WHERE category IS NOT NULL GROUP BY category"
278
+ ).all() as { category: string; count: number }[];
279
+
280
+ const by_type: Record<string, number> = {};
281
+ for (const row of typeRows) {
282
+ by_type[row.type] = row.count;
283
+ }
284
+
285
+ const by_category: Record<string, number> = {};
286
+ for (const row of categoryRows) {
287
+ by_category[row.category] = row.count;
288
+ }
289
+
290
+ return {
291
+ total_assets: totalRow.count,
292
+ total_size: sizeRow.total,
293
+ by_type,
294
+ by_category,
295
+ };
296
+ }
297
+
298
+ // --- Collection types ---
299
+
300
+ export interface Collection {
301
+ id: string;
302
+ name: string;
303
+ description: string | null;
304
+ created_at: string;
305
+ }
306
+
307
+ export interface CreateCollectionInput {
308
+ name: string;
309
+ description?: string;
310
+ }
311
+
312
+ export function createCollection(input: CreateCollectionInput): Collection {
313
+ const db = getDatabase();
314
+ const id = crypto.randomUUID();
315
+
316
+ db.prepare(
317
+ `INSERT INTO collections (id, name, description) VALUES (?, ?, ?)`
318
+ ).run(id, input.name, input.description || null);
319
+
320
+ return getCollection(id)!;
321
+ }
322
+
323
+ export function getCollection(id: string): Collection | null {
324
+ const db = getDatabase();
325
+ return db.prepare("SELECT * FROM collections WHERE id = ?").get(id) as Collection | null;
326
+ }
327
+
328
+ export function listCollections(): Collection[] {
329
+ const db = getDatabase();
330
+ return db.prepare("SELECT * FROM collections ORDER BY name").all() as Collection[];
331
+ }
332
+
333
+ export function deleteCollection(id: string): boolean {
334
+ const db = getDatabase();
335
+ const result = db.prepare("DELETE FROM collections WHERE id = ?").run(id);
336
+ return result.changes > 0;
337
+ }
338
+
339
+ // --- Collection-Asset operations ---
340
+
341
+ export function addToCollection(collectionId: string, assetId: string): boolean {
342
+ const db = getDatabase();
343
+ try {
344
+ db.prepare(
345
+ "INSERT OR IGNORE INTO collection_assets (collection_id, asset_id) VALUES (?, ?)"
346
+ ).run(collectionId, assetId);
347
+ return true;
348
+ } catch {
349
+ return false;
350
+ }
351
+ }
352
+
353
+ export function removeFromCollection(collectionId: string, assetId: string): boolean {
354
+ const db = getDatabase();
355
+ const result = db.prepare(
356
+ "DELETE FROM collection_assets WHERE collection_id = ? AND asset_id = ?"
357
+ ).run(collectionId, assetId);
358
+ return result.changes > 0;
359
+ }
360
+
361
+ export function getCollectionAssets(collectionId: string): Asset[] {
362
+ const db = getDatabase();
363
+ const rows = db.prepare(
364
+ `SELECT a.* FROM assets a
365
+ INNER JOIN collection_assets ca ON ca.asset_id = a.id
366
+ WHERE ca.collection_id = ?
367
+ ORDER BY ca.added_at DESC`
368
+ ).all(collectionId) as AssetRow[];
369
+ return rows.map(rowToAsset);
370
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Database connection for microservice-assets
3
+ */
4
+
5
+ import { Database } from "bun:sqlite";
6
+ import { existsSync, mkdirSync } from "node:fs";
7
+ import { dirname, join, resolve } from "node:path";
8
+ import { MIGRATIONS } from "./migrations.js";
9
+
10
+ let _db: Database | null = null;
11
+
12
+ function getDbPath(): string {
13
+ // Environment variable override
14
+ if (process.env["MICROSERVICES_DIR"]) {
15
+ return join(process.env["MICROSERVICES_DIR"], "microservice-assets", "data.db");
16
+ }
17
+
18
+ // Check for .microservices in current or parent directories
19
+ let dir = resolve(process.cwd());
20
+ while (true) {
21
+ const candidate = join(dir, ".microservices", "microservice-assets", "data.db");
22
+ const msDir = join(dir, ".microservices");
23
+ if (existsSync(msDir)) return candidate;
24
+ const parent = dirname(dir);
25
+ if (parent === dir) break;
26
+ dir = parent;
27
+ }
28
+
29
+ // Global fallback
30
+ const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
31
+ return join(home, ".microservices", "microservice-assets", "data.db");
32
+ }
33
+
34
+ function ensureDir(filePath: string): void {
35
+ const dir = dirname(resolve(filePath));
36
+ if (!existsSync(dir)) {
37
+ mkdirSync(dir, { recursive: true });
38
+ }
39
+ }
40
+
41
+ export function getDatabase(): Database {
42
+ if (_db) return _db;
43
+
44
+ const dbPath = getDbPath();
45
+ ensureDir(dbPath);
46
+
47
+ _db = new Database(dbPath);
48
+ _db.exec("PRAGMA journal_mode = WAL");
49
+ _db.exec("PRAGMA foreign_keys = ON");
50
+
51
+ // Create migrations table
52
+ _db.exec(`
53
+ CREATE TABLE IF NOT EXISTS _migrations (
54
+ id INTEGER PRIMARY KEY,
55
+ name TEXT NOT NULL,
56
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
57
+ )
58
+ `);
59
+
60
+ // Apply pending migrations
61
+ const applied = _db
62
+ .query("SELECT id FROM _migrations ORDER BY id")
63
+ .all() as { id: number }[];
64
+ const appliedIds = new Set(applied.map((r) => r.id));
65
+
66
+ for (const migration of MIGRATIONS) {
67
+ if (appliedIds.has(migration.id)) continue;
68
+
69
+ _db.exec("BEGIN");
70
+ try {
71
+ _db.exec(migration.sql);
72
+ _db.prepare("INSERT INTO _migrations (id, name) VALUES (?, ?)").run(
73
+ migration.id,
74
+ migration.name
75
+ );
76
+ _db.exec("COMMIT");
77
+ } catch (error) {
78
+ _db.exec("ROLLBACK");
79
+ throw new Error(
80
+ `Migration ${migration.id} (${migration.name}) failed: ${error instanceof Error ? error.message : String(error)}`
81
+ );
82
+ }
83
+ }
84
+
85
+ return _db;
86
+ }
87
+
88
+ export function closeDatabase(): void {
89
+ if (_db) {
90
+ _db.close();
91
+ _db = null;
92
+ }
93
+ }
@@ -0,0 +1,51 @@
1
+ export interface MigrationEntry {
2
+ id: number;
3
+ name: string;
4
+ sql: string;
5
+ }
6
+
7
+ export const MIGRATIONS: MigrationEntry[] = [
8
+ {
9
+ id: 1,
10
+ name: "initial_schema",
11
+ sql: `
12
+ CREATE TABLE IF NOT EXISTS assets (
13
+ id TEXT PRIMARY KEY,
14
+ name TEXT NOT NULL,
15
+ description TEXT,
16
+ type TEXT CHECK(type IN ('image','video','document','audio','template','logo','font','other')),
17
+ file_path TEXT,
18
+ file_size INTEGER,
19
+ mime_type TEXT,
20
+ dimensions TEXT,
21
+ tags TEXT DEFAULT '[]',
22
+ category TEXT,
23
+ metadata TEXT DEFAULT '{}',
24
+ uploaded_by TEXT,
25
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
26
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
27
+ );
28
+
29
+ CREATE TABLE IF NOT EXISTS collections (
30
+ id TEXT PRIMARY KEY,
31
+ name TEXT NOT NULL,
32
+ description TEXT,
33
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
34
+ );
35
+
36
+ CREATE TABLE IF NOT EXISTS collection_assets (
37
+ collection_id TEXT NOT NULL REFERENCES collections(id) ON DELETE CASCADE,
38
+ asset_id TEXT NOT NULL REFERENCES assets(id) ON DELETE CASCADE,
39
+ added_at TEXT NOT NULL DEFAULT (datetime('now')),
40
+ PRIMARY KEY (collection_id, asset_id)
41
+ );
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_assets_name ON assets(name);
44
+ CREATE INDEX IF NOT EXISTS idx_assets_type ON assets(type);
45
+ CREATE INDEX IF NOT EXISTS idx_assets_category ON assets(category);
46
+ CREATE INDEX IF NOT EXISTS idx_assets_uploaded_by ON assets(uploaded_by);
47
+ CREATE INDEX IF NOT EXISTS idx_collections_name ON collections(name);
48
+ CREATE INDEX IF NOT EXISTS idx_collection_assets_asset ON collection_assets(asset_id);
49
+ `,
50
+ },
51
+ ];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * microservice-assets — Digital asset management microservice
3
+ */
4
+
5
+ export {
6
+ createAsset,
7
+ getAsset,
8
+ listAssets,
9
+ updateAsset,
10
+ deleteAsset,
11
+ searchAssets,
12
+ listByType,
13
+ listByTag,
14
+ listByCategory,
15
+ getAssetStats,
16
+ createCollection,
17
+ getCollection,
18
+ listCollections,
19
+ deleteCollection,
20
+ addToCollection,
21
+ removeFromCollection,
22
+ getCollectionAssets,
23
+ type Asset,
24
+ type CreateAssetInput,
25
+ type UpdateAssetInput,
26
+ type ListAssetsOptions,
27
+ type AssetStats,
28
+ type Collection,
29
+ type CreateCollectionInput,
30
+ } from "./db/assets.js";
31
+
32
+ export { getDatabase, closeDatabase } from "./db/database.js";