@everystack/cli 0.2.5 → 0.2.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everystack/cli",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "CLI and OTA updates for Expo apps on everystack",
5
5
  "license": "AGPL-3.0-only",
6
6
  "publishConfig": {
@@ -41,8 +41,8 @@
41
41
  "lint": "tsc --noEmit"
42
42
  },
43
43
  "dependencies": {
44
- "@aws-sdk/client-cloudfront-keyvaluestore": "3.1045.0",
45
- "@aws-sdk/signature-v4a": "3.1031.0",
44
+ "@aws-sdk/client-cloudfront-keyvaluestore": "3.1053.0",
45
+ "@aws-sdk/signature-v4a": "3.1048.0",
46
46
  "glob": "13.0.6",
47
47
  "node-forge": "1.4.0",
48
48
  "structured-headers": "1.0.1",
@@ -50,11 +50,11 @@
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@everystack/server": ">=0.1.0",
53
- "@aws-sdk/client-cloudfront": "3.1045.0",
54
- "@aws-sdk/client-cloudwatch-logs": "3.1047.0",
55
- "@aws-sdk/client-lambda": "3.1045.0",
56
- "@aws-sdk/client-s3": "3.1045.0",
57
- "@aws-sdk/s3-request-presigner": "3.1045.0",
53
+ "@aws-sdk/client-cloudfront": "3.1053.0",
54
+ "@aws-sdk/client-cloudwatch-logs": "3.1053.0",
55
+ "@aws-sdk/client-lambda": "3.1053.0",
56
+ "@aws-sdk/client-s3": "3.1053.0",
57
+ "@aws-sdk/s3-request-presigner": "3.1053.0",
58
58
  "drizzle-orm": "0.41.0",
59
59
  "expo-updates": "55.0.21",
60
60
  "react": "19.2.6",
@@ -90,11 +90,11 @@
90
90
  }
91
91
  },
92
92
  "devDependencies": {
93
- "@aws-sdk/client-cloudfront": "3.1045.0",
94
- "@aws-sdk/client-cloudwatch-logs": "3.1047.0",
95
- "@aws-sdk/client-lambda": "3.1045.0",
96
- "@aws-sdk/client-s3": "3.1045.0",
97
- "@aws-sdk/s3-request-presigner": "3.1045.0",
93
+ "@aws-sdk/client-cloudfront": "3.1053.0",
94
+ "@aws-sdk/client-cloudwatch-logs": "3.1053.0",
95
+ "@aws-sdk/client-lambda": "3.1053.0",
96
+ "@aws-sdk/client-s3": "3.1053.0",
97
+ "@aws-sdk/s3-request-presigner": "3.1053.0",
98
98
  "@types/jest": "29.5.14",
99
99
  "@types/node": "22.19.18",
100
100
  "@types/node-forge": "1.3.14",
@@ -85,6 +85,42 @@ export async function logsErrorsCommand(flags: Record<string, string>): Promise<
85
85
  }
86
86
  }
87
87
 
88
+ const VALID_LOG_ORIGINS = ['api', 'media', 'worker'] as const;
89
+
90
+ /**
91
+ * Resolve a Lambda function name from the --origin flag.
92
+ * Defaults to 'api' if no origin is specified.
93
+ */
94
+ function resolveFunctionForOrigin(
95
+ config: { apiFunctionName: string; imageFunctionName?: string; workerFunctionName?: string },
96
+ origin?: string,
97
+ ): string {
98
+ const resolved = origin || 'api';
99
+
100
+ if (!VALID_LOG_ORIGINS.includes(resolved as typeof VALID_LOG_ORIGINS[number])) {
101
+ throw new Error(`Invalid origin "${resolved}". Must be one of: ${VALID_LOG_ORIGINS.join(', ')}`);
102
+ }
103
+
104
+ switch (resolved) {
105
+ case 'media':
106
+ if (!config.imageFunctionName) {
107
+ throw new Error(
108
+ 'No image function found. Add imageFunctionName to sst.config.ts outputs or use --stage for auto-discovery.',
109
+ );
110
+ }
111
+ return config.imageFunctionName;
112
+ case 'worker':
113
+ if (!config.workerFunctionName) {
114
+ throw new Error(
115
+ 'No worker function found. Add workerFunctionName to sst.config.ts outputs or use --stage for auto-discovery.',
116
+ );
117
+ }
118
+ return config.workerFunctionName;
119
+ default:
120
+ return config.apiFunctionName;
121
+ }
122
+ }
123
+
88
124
  export async function logsTailCommand(flags: Record<string, string>): Promise<void> {
89
125
  step('Resolving deployed config...');
90
126
  let config;
@@ -95,7 +131,15 @@ export async function logsTailCommand(flags: Record<string, string>): Promise<vo
95
131
  process.exit(1);
96
132
  }
97
133
 
98
- info(`Region: ${config.region}, Function: ${config.apiFunctionName}`);
134
+ let functionName: string;
135
+ try {
136
+ functionName = resolveFunctionForOrigin(config, flags.origin);
137
+ } catch (err: any) {
138
+ fail(err.message);
139
+ process.exit(1);
140
+ }
141
+
142
+ info(`Region: ${config.region}, Function: ${functionName}`);
99
143
 
100
144
  const filterPattern = flags.filter;
101
145
  const since = flags.since || '5m'; // 5m, 1h, 1d
@@ -110,7 +154,7 @@ export async function logsTailCommand(flags: Record<string, string>): Promise<vo
110
154
  const client = new CloudWatchLogsClient({ region: config.region });
111
155
 
112
156
  // Resolve actual log group from Lambda config (handles SST name changes)
113
- const logGroupName = await resolveLogGroup(config.region, config.apiFunctionName);
157
+ const logGroupName = await resolveLogGroup(config.region, functionName);
114
158
 
115
159
  // Parse since duration to milliseconds
116
160
  const sinceMs = parseDuration(since);
package/src/cli/config.ts CHANGED
@@ -15,6 +15,8 @@ export interface CliConfig {
15
15
  baseUrl: string;
16
16
  region: string;
17
17
  apiFunctionName: string;
18
+ imageFunctionName?: string;
19
+ workerFunctionName?: string;
18
20
  updatesBucket: string;
19
21
  clientBundlesBucket: string;
20
22
  kvsArn?: string;
@@ -26,6 +28,8 @@ interface SstOutputs {
26
28
  apiUrl?: string;
27
29
  imageUrl?: string;
28
30
  apiFunctionName?: string;
31
+ imageFunctionName?: string;
32
+ workerFunctionName?: string;
29
33
  updatesBucket?: string;
30
34
  clientBundlesBucket?: string;
31
35
  kvsArn?: string;
@@ -93,6 +97,8 @@ export async function resolveConfig(stage?: string): Promise<CliConfig> {
93
97
  baseUrl: outputs.routerUrl,
94
98
  region,
95
99
  apiFunctionName: outputs.apiFunctionName,
100
+ imageFunctionName: outputs.imageFunctionName,
101
+ workerFunctionName: outputs.workerFunctionName,
96
102
  updatesBucket: outputs.updatesBucket,
97
103
  clientBundlesBucket: outputs.clientBundlesBucket,
98
104
  kvsArn: outputs.kvsArn,
@@ -14,11 +14,13 @@
14
14
  import fs from 'node:fs/promises';
15
15
  import path from 'node:path';
16
16
 
17
- /** Mirrors DiscoveredConfig from config.ts — defined locally to avoid circular imports. */
17
+ /** Mirrors CliConfig from config.ts — defined locally to avoid circular imports. */
18
18
  interface DiscoveredConfig {
19
19
  baseUrl: string;
20
20
  region: string;
21
21
  apiFunctionName: string;
22
+ imageFunctionName?: string;
23
+ workerFunctionName?: string;
22
24
  updatesBucket: string;
23
25
  clientBundlesBucket: string;
24
26
  kvsArn?: string;
@@ -129,24 +131,23 @@ interface LambdaResult {
129
131
  }
130
132
 
131
133
  /**
132
- * Find the API Lambda function for a stage.
133
- * Optionally extracts CDN_URL from environment variables.
134
+ * Find a Lambda function by SST resource name prefix.
135
+ * Returns the function name if found, undefined if not.
134
136
  */
135
- export async function discoverLambda(
137
+ export async function discoverFunction(
136
138
  region: string,
137
139
  prefix: string,
138
- ): Promise<LambdaResult> {
140
+ resourceName: string,
141
+ ): Promise<string | undefined> {
139
142
  const {
140
143
  LambdaClient,
141
144
  ListFunctionsCommand,
142
- GetFunctionConfigurationCommand,
143
145
  } = await import('@aws-sdk/client-lambda');
144
146
 
145
147
  const client = new LambdaClient({ region });
146
- const needle = `${prefix}ApiFunction-`.toLowerCase();
148
+ const needle = `${prefix}${resourceName}-`.toLowerCase();
147
149
 
148
150
  let marker: string | undefined;
149
- let matchName: string | undefined;
150
151
 
151
152
  do {
152
153
  const res = await client.send(
@@ -155,14 +156,25 @@ export async function discoverLambda(
155
156
  const items = res.Functions || [];
156
157
  for (const fn of items) {
157
158
  if (fn.FunctionName && fn.FunctionName.toLowerCase().startsWith(needle)) {
158
- matchName = fn.FunctionName;
159
- break;
159
+ return fn.FunctionName;
160
160
  }
161
161
  }
162
- if (matchName) break;
163
162
  marker = res.NextMarker;
164
163
  } while (marker);
165
164
 
165
+ return undefined;
166
+ }
167
+
168
+ /**
169
+ * Find the API Lambda function for a stage.
170
+ * Extracts CDN_URL from environment variables for routerUrl.
171
+ */
172
+ export async function discoverLambda(
173
+ region: string,
174
+ prefix: string,
175
+ ): Promise<LambdaResult> {
176
+ const matchName = await discoverFunction(region, prefix, 'ApiFunction');
177
+
166
178
  if (!matchName) {
167
179
  throw new Error(
168
180
  `No API Lambda found for prefix "${prefix}ApiFunction-*". ` +
@@ -171,6 +183,12 @@ export async function discoverLambda(
171
183
  }
172
184
 
173
185
  // Get env vars for routerUrl (CDN_URL)
186
+ const {
187
+ LambdaClient,
188
+ GetFunctionConfigurationCommand,
189
+ } = await import('@aws-sdk/client-lambda');
190
+
191
+ const client = new LambdaClient({ region });
174
192
  const config = await client.send(
175
193
  new GetFunctionConfigurationCommand({ FunctionName: matchName }),
176
194
  );
@@ -236,10 +254,12 @@ export async function discoverConfig(
236
254
  const prefix = `${appName}-${stage}-`;
237
255
 
238
256
  // Run CF function + Lambda + S3 discovery in parallel
239
- const [cfResult, lambdaResult, bucketsResult] = await Promise.all([
257
+ const [cfResult, lambdaResult, bucketsResult, imageFn, workerFn] = await Promise.all([
240
258
  discoverCfFunction(region, prefix),
241
259
  discoverLambda(region, prefix),
242
260
  discoverBuckets(region, prefix),
261
+ discoverFunction(region, prefix, 'ImageFunction').catch(() => undefined),
262
+ discoverFunction(region, prefix, 'WorkerFunction').catch(() => undefined),
243
263
  ]);
244
264
 
245
265
  // Distribution discovery is best-effort (not critical for most CLI operations)
@@ -269,6 +289,8 @@ export async function discoverConfig(
269
289
  baseUrl: lambdaResult.routerUrl || '',
270
290
  region,
271
291
  apiFunctionName: lambdaResult.functionName,
292
+ imageFunctionName: imageFn,
293
+ workerFunctionName: workerFn,
272
294
  updatesBucket: bucketsResult.updatesBucket,
273
295
  clientBundlesBucket: bucketsResult.clientBundlesBucket,
274
296
  kvsArn: cfResult.kvsArn,
@@ -286,6 +308,8 @@ interface CachedOutputs {
286
308
  _cachedAt: number;
287
309
  routerUrl?: string;
288
310
  apiFunctionName?: string;
311
+ imageFunctionName?: string;
312
+ workerFunctionName?: string;
289
313
  updatesBucket?: string;
290
314
  clientBundlesBucket?: string;
291
315
  kvsArn?: string;
@@ -308,6 +332,8 @@ export async function getCachedConfig(stage: string): Promise<DiscoveredConfig |
308
332
  baseUrl: cached.routerUrl || '',
309
333
  region: process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1',
310
334
  apiFunctionName: cached.apiFunctionName,
335
+ imageFunctionName: cached.imageFunctionName,
336
+ workerFunctionName: cached.workerFunctionName,
311
337
  updatesBucket: cached.updatesBucket,
312
338
  clientBundlesBucket: cached.clientBundlesBucket,
313
339
  kvsArn: cached.kvsArn,
@@ -323,6 +349,8 @@ export async function setCachedConfig(stage: string, config: DiscoveredConfig):
323
349
  _cachedAt: Date.now(),
324
350
  routerUrl: config.baseUrl,
325
351
  apiFunctionName: config.apiFunctionName,
352
+ imageFunctionName: config.imageFunctionName,
353
+ workerFunctionName: config.workerFunctionName,
326
354
  updatesBucket: config.updatesBucket,
327
355
  clientBundlesBucket: config.clientBundlesBucket,
328
356
  kvsArn: config.kvsArn,
package/src/cli/index.ts CHANGED
@@ -167,7 +167,7 @@ Usage:
167
167
  everystack diag [url] --hydration Analyze SSR hydration issues (fetches full HTML)
168
168
  everystack analyze:ssr [--app ./app] Scan app code for SSR anti-patterns
169
169
  everystack logs:errors [--stage <name>] [--limit 20] [--level error|fatal] [--source <name>]
170
- everystack logs:tail [--stage <name>] [--filter <pattern>] [--since 5m]
170
+ everystack logs:tail [--stage <name>] [--origin api|media|worker] [--filter <pattern>] [--since 5m]
171
171
  everystack logs:query [--stage <name>] [--level <level>] [--source <name>] [--traceId <id>] [--search <text>]
172
172
  everystack branches list
173
173
  everystack branches create --name <name>