@funnelsgrove/cli 0.1.8 → 0.1.10
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/README.md +7 -6
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +53 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,24 +7,25 @@ npm install -g @funnelsgrove/cli
|
|
|
7
7
|
fgrove login
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Sync a funnel into its own local folder:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
fgrove
|
|
14
|
-
|
|
13
|
+
fgrove sync down --funnel claimbee-ios --dir ./claimbee-ios
|
|
14
|
+
cd ./claimbee-ios
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Common workflow:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
fgrove
|
|
21
|
-
cd ./claimbee-ios
|
|
20
|
+
fgrove status
|
|
22
21
|
fgrove docs
|
|
23
22
|
fgrove sync up --message 'Update funnel copy'
|
|
24
23
|
fgrove publish --env preview
|
|
25
24
|
```
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
Inside a synced folder, `fgrove` reads `.funnelsgrove-sync.json` first, so you do not need to run `fgrove use` when switching between local funnel directories. Use `fgrove use` only when you want a global fallback context for commands outside a synced folder.
|
|
27
|
+
|
|
28
|
+
Use `fgrove env pull` from a synced folder to refresh only the ignored local `.env` file after project settings change, without replacing source files.
|
|
28
29
|
|
|
29
30
|
GitHub sync workflow:
|
|
30
31
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { type ActiveContext } from './authStore.js';
|
|
3
|
+
import { type SyncManifest } from './localSync.js';
|
|
4
|
+
type SyncTargetIdInput = {
|
|
5
|
+
explicitWorkspaceId?: string;
|
|
6
|
+
explicitFunnelId?: string;
|
|
7
|
+
manifest?: Pick<SyncManifest, 'workspaceId' | 'funnelId'> | null;
|
|
8
|
+
active?: Pick<ActiveContext, 'workspaceId' | 'funnelId'> | null;
|
|
9
|
+
defaultWorkspaceId?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveSyncTargetIds(input: SyncTargetIdInput): {
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
funnelId?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function isCliEntrypoint(invokedPath: string | undefined, modulePath: string, realpath?: (filePath: string) => string): boolean;
|
|
2
16
|
export {};
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { cp, mkdir } from 'node:fs/promises';
|
|
4
4
|
import { createInterface } from 'node:readline/promises';
|
|
5
5
|
import path from 'node:path';
|
|
@@ -37,6 +37,30 @@ const DEFAULT_API_URL = 'https://api.funnelsgrove.com/trpc';
|
|
|
37
37
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
38
38
|
const PUBLISH_POLL_INTERVAL_MS = 2_000;
|
|
39
39
|
const PUBLISH_WAIT_TIMEOUT_MS = 30 * 60_000;
|
|
40
|
+
export function resolveSyncTargetIds(input) {
|
|
41
|
+
const workspaceId = input.explicitWorkspaceId ||
|
|
42
|
+
input.manifest?.workspaceId ||
|
|
43
|
+
input.active?.workspaceId ||
|
|
44
|
+
input.defaultWorkspaceId;
|
|
45
|
+
if (!workspaceId) {
|
|
46
|
+
throw new Error('No workspace found for this account.');
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
workspaceId,
|
|
50
|
+
funnelId: input.explicitFunnelId || input.manifest?.funnelId || input.active?.funnelId,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function isCliEntrypoint(invokedPath, modulePath, realpath = realpathSync) {
|
|
54
|
+
if (!invokedPath) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return realpath(path.resolve(invokedPath)) === realpath(modulePath);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return path.resolve(invokedPath) === path.resolve(modulePath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
40
64
|
const getApiUrl = () => {
|
|
41
65
|
const options = program.opts();
|
|
42
66
|
return options.apiUrl || process.env.FUNNELSGROVE_API_URL || DEFAULT_API_URL;
|
|
@@ -218,18 +242,24 @@ const resolveSyncTarget = async (input) => {
|
|
|
218
242
|
const sourceDir = path.resolve(process.cwd(), input.dir || '.');
|
|
219
243
|
const manifest = await readSyncManifest(sourceDir);
|
|
220
244
|
const active = await loadActiveContext(getConfigPath());
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
245
|
+
const explicitWorkspaceId = input.workspace ? await resolveWorkspaceId(input.token, input.workspace) : undefined;
|
|
246
|
+
const fallbackWorkspaceId = explicitWorkspaceId || manifest?.workspaceId || active?.workspaceId || await resolveWorkspaceId(input.token);
|
|
247
|
+
const explicitFunnelId = input.funnel
|
|
248
|
+
? await resolveFunnelId(input.token, fallbackWorkspaceId, input.funnel)
|
|
249
|
+
: undefined;
|
|
250
|
+
const resolved = resolveSyncTargetIds({
|
|
251
|
+
explicitWorkspaceId,
|
|
252
|
+
explicitFunnelId,
|
|
253
|
+
manifest,
|
|
254
|
+
active,
|
|
255
|
+
defaultWorkspaceId: fallbackWorkspaceId,
|
|
256
|
+
});
|
|
257
|
+
if (!resolved.funnelId) {
|
|
258
|
+
throw new Error('No synced funnel found. Run from a synced funnel directory, pass `--funnel`, or set a fallback with `fgrove use --funnel <id-or-slug>`.');
|
|
229
259
|
}
|
|
230
260
|
return {
|
|
231
|
-
workspaceId,
|
|
232
|
-
funnelId,
|
|
261
|
+
workspaceId: resolved.workspaceId,
|
|
262
|
+
funnelId: resolved.funnelId,
|
|
233
263
|
sourceDir,
|
|
234
264
|
manifest,
|
|
235
265
|
};
|
|
@@ -277,8 +307,8 @@ program
|
|
|
277
307
|
.option('--config <path>', 'Auth config path', process.env.FUNNELSGROVE_CONFIG || getDefaultAuthConfigPath());
|
|
278
308
|
addExamples(program, [
|
|
279
309
|
'fgrove login',
|
|
280
|
-
'fgrove
|
|
281
|
-
'
|
|
310
|
+
'fgrove sync down --funnel claimbee-ios --dir ./claimbee-ios',
|
|
311
|
+
'cd ./claimbee-ios && fgrove status',
|
|
282
312
|
'fgrove publish --env preview',
|
|
283
313
|
]);
|
|
284
314
|
addExamples(program
|
|
@@ -372,9 +402,9 @@ addExamples(program
|
|
|
372
402
|
console.log(`user\t${me.user.email || me.user.id}`);
|
|
373
403
|
console.log(`api\t${getApiUrl()}`);
|
|
374
404
|
console.log(`config\t${getConfigPath()}`);
|
|
375
|
-
console.log(`workspace\t${active?.workspaceName || active?.workspaceSlug || active?.workspaceId || me.workspace?.name || 'Not set'}`);
|
|
376
|
-
console.log(`project\t${active?.projectName || active?.projectSlug || active?.projectId || 'Not set'}`);
|
|
377
|
-
console.log(`funnel\t${active?.funnelName || active?.funnelSlug || active?.funnelId || 'Not set'}`);
|
|
405
|
+
console.log(`workspace\t${manifest?.workspaceId || active?.workspaceName || active?.workspaceSlug || active?.workspaceId || me.workspace?.name || 'Not set'}`);
|
|
406
|
+
console.log(`project\t${manifest ? 'Not set' : active?.projectName || active?.projectSlug || active?.projectId || 'Not set'}`);
|
|
407
|
+
console.log(`funnel\t${manifest?.funnelId || active?.funnelName || active?.funnelSlug || active?.funnelId || 'Not set'}`);
|
|
378
408
|
if (manifest) {
|
|
379
409
|
console.log(`localWorkspace\t${manifest.workspaceId}`);
|
|
380
410
|
console.log(`localFunnel\t${manifest.funnelId}`);
|
|
@@ -441,7 +471,7 @@ addExamples(funnelsCommand
|
|
|
441
471
|
console.log(`${result.funnel.id}\t${result.funnel.name}\t${result.funnel.slug}`);
|
|
442
472
|
});
|
|
443
473
|
const syncCommand = addExamples(program.command('sync').description('Sync funnel source'), [
|
|
444
|
-
'fgrove sync down --dir ./claimbee-ios',
|
|
474
|
+
'fgrove sync down --funnel claimbee-ios --dir ./claimbee-ios',
|
|
445
475
|
'fgrove sync up --message "Update copy"',
|
|
446
476
|
]);
|
|
447
477
|
addExamples(syncCommand
|
|
@@ -450,7 +480,6 @@ addExamples(syncCommand
|
|
|
450
480
|
.option('--workspace <id-or-slug-or-name>', 'Workspace id, slug, or name')
|
|
451
481
|
.option('--funnel <id-or-slug>', 'Funnel id or slug')
|
|
452
482
|
.requiredOption('--dir <path>', 'Local target directory'), [
|
|
453
|
-
'fgrove sync down --dir ./claimbee-ios',
|
|
454
483
|
'fgrove sync down --funnel claimbee-ios --dir ./claimbee-ios',
|
|
455
484
|
])
|
|
456
485
|
.action(async (options) => {
|
|
@@ -827,7 +856,9 @@ addExamples(program
|
|
|
827
856
|
console.log(' npm install');
|
|
828
857
|
console.log(' npm run dev');
|
|
829
858
|
});
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
859
|
+
if (isCliEntrypoint(process.argv[1], fileURLToPath(import.meta.url))) {
|
|
860
|
+
program.parseAsync().catch((error) => {
|
|
861
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
862
|
+
process.exitCode = 1;
|
|
863
|
+
});
|
|
864
|
+
}
|