@lovelybunch/api 1.0.69-alpha.16 → 1.0.69-alpha.18

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.
@@ -1,10 +1,49 @@
1
1
  import Replicate from 'replicate';
2
2
  import { promises as fs } from 'fs';
3
3
  import path from 'path';
4
- const REPLICATE_API_TOKEN = 'r8_6IsX89og0JuK6Ay8RXADjp8RjnEOpfK3BpNXu';
5
- const replicate = new Replicate({
6
- auth: REPLICATE_API_TOKEN,
7
- });
4
+ import { homedir } from 'os';
5
+ import { existsSync, readFileSync } from 'fs';
6
+ /**
7
+ * Get Replicate API token from global config or environment variable
8
+ */
9
+ function getReplicateApiToken() {
10
+ // First try global config
11
+ try {
12
+ const platform = process.platform;
13
+ let configDir;
14
+ if (platform === 'win32') {
15
+ configDir = path.join(process.env.APPDATA || homedir(), 'coconuts');
16
+ }
17
+ else if (platform === 'darwin') {
18
+ configDir = path.join(homedir(), 'Library', 'Application Support', 'coconuts');
19
+ }
20
+ else {
21
+ configDir = path.join(process.env.XDG_CONFIG_HOME || path.join(homedir(), '.config'), 'coconuts');
22
+ }
23
+ const configPath = path.join(configDir, 'config.json');
24
+ if (existsSync(configPath)) {
25
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
26
+ if (config.apiKeys?.replicate) {
27
+ return config.apiKeys.replicate;
28
+ }
29
+ }
30
+ }
31
+ catch (error) {
32
+ console.warn('Failed to load Replicate token from config:', error);
33
+ }
34
+ // Fallback to environment variable
35
+ return process.env.REPLICATE_API_TOKEN || null;
36
+ }
37
+ // Initialize Replicate client lazily to ensure token is loaded at request time
38
+ function getReplicateClient() {
39
+ const token = getReplicateApiToken();
40
+ if (!token) {
41
+ throw new Error('Replicate API token not configured');
42
+ }
43
+ return new Replicate({
44
+ auth: token,
45
+ });
46
+ }
8
47
  function getResourcesPath() {
9
48
  let basePath;
10
49
  if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
@@ -69,6 +108,17 @@ function getAspectRatio(dimensions) {
69
108
  }
70
109
  export async function POST(c) {
71
110
  try {
111
+ // Check if Replicate API token is configured
112
+ const replicateToken = getReplicateApiToken();
113
+ if (!replicateToken) {
114
+ return c.json({
115
+ success: false,
116
+ error: {
117
+ code: 'MISSING_API_TOKEN',
118
+ message: 'Replicate API token not configured. Please add it in Settings → Integrations.'
119
+ }
120
+ }, 400);
121
+ }
72
122
  const body = await c.req.json();
73
123
  const { prompt, inspiration, dimensions, resolution, model, image_input } = body;
74
124
  if (!prompt) {
@@ -130,7 +180,8 @@ export async function POST(c) {
130
180
  continue;
131
181
  }
132
182
  const fileBuffer = await fs.readFile(filePath);
133
- const uploadedFile = await replicate.files.create(fileBuffer, {
183
+ const replicateClient = getReplicateClient();
184
+ const uploadedFile = await replicateClient.files.create(fileBuffer, {
134
185
  resourceId,
135
186
  originalName: resource.name,
136
187
  });
@@ -160,7 +211,8 @@ export async function POST(c) {
160
211
  }
161
212
  // Run the model (defaulting to nano-banana-pro)
162
213
  const modelId = model === 'Nano Banana Pro' ? 'google/nano-banana-pro' : 'google/nano-banana-pro';
163
- const output = await replicate.run(modelId, { input });
214
+ const replicateClient = getReplicateClient();
215
+ const output = await replicateClient.run(modelId, { input });
164
216
  // Extract URL from output
165
217
  // Replicate output can be: string URL, array of URLs, or FileOutput object with url() method
166
218
  let imageUrl;
@@ -11,6 +11,7 @@ import { getGlobalTerminalManager } from './lib/terminal/global-manager.js';
11
11
  import { getGlobalJobScheduler } from './lib/jobs/global-job-scheduler.js';
12
12
  import { fileURLToPath } from 'url';
13
13
  import { getLogger } from '@lovelybunch/core/logging';
14
+ import { getLogsDir } from '@lovelybunch/core';
14
15
  const __filename = fileURLToPath(import.meta.url);
15
16
  const __dirname = path.dirname(__filename);
16
17
  // Load environment variables from .env file in project root
@@ -30,11 +31,15 @@ function findNutDirectorySync() {
30
31
  }
31
32
  return null;
32
33
  }
33
- // Initialize logger with config from .nut/config.json
34
+ // Initialize logger with config from .nut/config.json or use OS app data directory
34
35
  // This must happen BEFORE importing route handlers (they call getLogger at module level)
35
36
  console.log('🔍 Initializing activity logging...');
36
37
  try {
37
38
  const nutDir = findNutDirectorySync();
39
+ let logsDir = getLogsDir(); // Default to OS app data directory
40
+ let coconutId = 'unknown.coconut';
41
+ let rotateBytes = 128 * 1024 * 1024;
42
+ let loggingEnabled = true; // Default to enabled
38
43
  if (nutDir) {
39
44
  const projectRoot = path.dirname(nutDir);
40
45
  const configPath = path.join(nutDir, 'config.json');
@@ -42,32 +47,42 @@ try {
42
47
  console.log(' Config path:', configPath);
43
48
  const configData = fs.readFileSync(configPath, 'utf-8');
44
49
  const config = JSON.parse(configData);
45
- if (config.logging?.enabled) {
46
- const logsDir = path.resolve(projectRoot, config.logging?.location || '.nut/logs');
47
- const logger = getLogger({
48
- coconutId: config.coconut?.id || 'unknown.coconut',
49
- logsDir: logsDir,
50
- rotateBytes: config.logging?.rotateBytes || 128 * 1024 * 1024
51
- });
52
- console.log('📝 Activity logging ENABLED');
53
- console.log(' Logs directory:', logsDir);
54
- console.log(' Coconut ID:', config.coconut?.id || 'unknown.coconut');
55
- // Test log immediately
56
- logger.log({
57
- kind: 'system.startup',
58
- actor: 'system',
59
- subject: 'server',
60
- tags: ['system', 'startup'],
61
- payload: { message: 'Server starting with logging enabled' }
62
- });
63
- console.log(' ✓ Test event logged');
50
+ // Check if logging is explicitly disabled in config
51
+ if (config.logging?.enabled === false) {
52
+ loggingEnabled = false;
64
53
  }
65
- else {
66
- console.log('📝 Activity logging disabled in config');
54
+ // Allow config to override logs location (relative paths resolve from project root)
55
+ if (config.logging?.location) {
56
+ logsDir = path.resolve(projectRoot, config.logging.location);
67
57
  }
58
+ if (config.coconut?.id) {
59
+ coconutId = config.coconut.id;
60
+ }
61
+ if (config.logging?.rotateBytes) {
62
+ rotateBytes = config.logging.rotateBytes;
63
+ }
64
+ }
65
+ if (loggingEnabled) {
66
+ const logger = getLogger({
67
+ coconutId,
68
+ logsDir,
69
+ rotateBytes
70
+ });
71
+ console.log('📝 Activity logging ENABLED');
72
+ console.log(' Logs directory:', logsDir);
73
+ console.log(' Coconut ID:', coconutId);
74
+ // Test log immediately
75
+ logger.log({
76
+ kind: 'system.startup',
77
+ actor: 'system',
78
+ subject: 'server',
79
+ tags: ['system', 'startup'],
80
+ payload: { message: 'Server starting with logging enabled' }
81
+ });
82
+ console.log(' ✓ Test event logged');
68
83
  }
69
84
  else {
70
- console.log(' .nut directory not found');
85
+ console.log('📝 Activity logging disabled in config');
71
86
  }
72
87
  }
73
88
  catch (error) {
package/dist/server.js CHANGED
@@ -10,6 +10,7 @@ import path from 'path';
10
10
  import { fileURLToPath } from 'url';
11
11
  import fs from 'fs';
12
12
  import { getLogger } from '@lovelybunch/core/logging';
13
+ import { getLogsDir } from '@lovelybunch/core';
13
14
  const __filename = fileURLToPath(import.meta.url);
14
15
  const __dirname = path.dirname(__filename);
15
16
  // Load environment variables from .env file in project root
@@ -29,11 +30,15 @@ function findNutDirectorySync() {
29
30
  }
30
31
  return null;
31
32
  }
32
- // Initialize logger with config from .nut/config.json
33
+ // Initialize logger with config from .nut/config.json or use OS app data directory
33
34
  // This must happen BEFORE importing route handlers (they call getLogger at module level)
34
35
  console.log('🔍 Initializing activity logging...');
35
36
  try {
36
37
  const nutDir = findNutDirectorySync();
38
+ let logsDir = getLogsDir(); // Default to OS app data directory
39
+ let coconutId = 'unknown.coconut';
40
+ let rotateBytes = 128 * 1024 * 1024;
41
+ let loggingEnabled = true; // Default to enabled
37
42
  if (nutDir) {
38
43
  const projectRoot = path.dirname(nutDir);
39
44
  const configPath = path.join(nutDir, 'config.json');
@@ -41,32 +46,42 @@ try {
41
46
  console.log(' Config path:', configPath);
42
47
  const configData = fs.readFileSync(configPath, 'utf-8');
43
48
  const config = JSON.parse(configData);
44
- if (config.logging?.enabled) {
45
- const logsDir = path.resolve(projectRoot, config.logging?.location || '.nut/logs');
46
- const logger = getLogger({
47
- coconutId: config.coconut?.id || 'unknown.coconut',
48
- logsDir: logsDir,
49
- rotateBytes: config.logging?.rotateBytes || 128 * 1024 * 1024
50
- });
51
- console.log('📝 Activity logging ENABLED');
52
- console.log(' Logs directory:', logsDir);
53
- console.log(' Coconut ID:', config.coconut?.id || 'unknown.coconut');
54
- // Test log immediately
55
- logger.log({
56
- kind: 'system.startup',
57
- actor: 'system',
58
- subject: 'server',
59
- tags: ['system', 'startup'],
60
- payload: { message: 'Server starting with logging enabled' }
61
- });
62
- console.log(' ✓ Test event logged');
49
+ // Check if logging is explicitly disabled in config
50
+ if (config.logging?.enabled === false) {
51
+ loggingEnabled = false;
63
52
  }
64
- else {
65
- console.log('📝 Activity logging disabled in config');
53
+ // Allow config to override logs location (relative paths resolve from project root)
54
+ if (config.logging?.location) {
55
+ logsDir = path.resolve(projectRoot, config.logging.location);
66
56
  }
57
+ if (config.coconut?.id) {
58
+ coconutId = config.coconut.id;
59
+ }
60
+ if (config.logging?.rotateBytes) {
61
+ rotateBytes = config.logging.rotateBytes;
62
+ }
63
+ }
64
+ if (loggingEnabled) {
65
+ const logger = getLogger({
66
+ coconutId,
67
+ logsDir,
68
+ rotateBytes
69
+ });
70
+ console.log('📝 Activity logging ENABLED');
71
+ console.log(' Logs directory:', logsDir);
72
+ console.log(' Coconut ID:', coconutId);
73
+ // Test log immediately
74
+ logger.log({
75
+ kind: 'system.startup',
76
+ actor: 'system',
77
+ subject: 'server',
78
+ tags: ['system', 'startup'],
79
+ payload: { message: 'Server starting with logging enabled' }
80
+ });
81
+ console.log(' ✓ Test event logged');
67
82
  }
68
83
  else {
69
- console.log(' .nut directory not found');
84
+ console.log('📝 Activity logging disabled in config');
70
85
  }
71
86
  }
72
87
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovelybunch/api",
3
- "version": "1.0.69-alpha.16",
3
+ "version": "1.0.69-alpha.18",
4
4
  "type": "module",
5
5
  "main": "dist/server-with-static.js",
6
6
  "exports": {
@@ -36,9 +36,9 @@
36
36
  "dependencies": {
37
37
  "@hono/node-server": "^1.13.7",
38
38
  "@hono/node-ws": "^1.0.6",
39
- "@lovelybunch/core": "^1.0.69-alpha.16",
40
- "@lovelybunch/mcp": "^1.0.69-alpha.16",
41
- "@lovelybunch/types": "^1.0.69-alpha.16",
39
+ "@lovelybunch/core": "^1.0.69-alpha.18",
40
+ "@lovelybunch/mcp": "^1.0.69-alpha.18",
41
+ "@lovelybunch/types": "^1.0.69-alpha.18",
42
42
  "arctic": "^1.9.2",
43
43
  "bcrypt": "^5.1.1",
44
44
  "cookie": "^0.6.0",