@doubledigit/cli 0.4.1 → 0.5.0
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 +10 -3
- package/dist/commands/actions.d.ts +6 -0
- package/dist/commands/actions.d.ts.map +1 -1
- package/dist/commands/actions.js +59 -0
- package/dist/commands/remotion-hub-init.d.ts +4 -0
- package/dist/commands/remotion-hub-init.d.ts.map +1 -0
- package/dist/commands/remotion-hub-init.js +120 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/actions-client.d.ts +1 -0
- package/dist/lib/actions-client.d.ts.map +1 -1
- package/dist/lib/actions-client.js +1 -0
- package/dist/lib/remotion-hub-init.d.ts +66 -0
- package/dist/lib/remotion-hub-init.d.ts.map +1 -0
- package/dist/lib/remotion-hub-init.js +254 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ pnpm dd doctor
|
|
|
21
21
|
pnpm onboard
|
|
22
22
|
pnpm onboard -- --no-run
|
|
23
23
|
pnpm dd actions remotion-hub
|
|
24
|
+
pnpm dd actions remotion-hub init temp-project
|
|
24
25
|
```
|
|
25
26
|
|
|
26
27
|
If installed globally, the binary is available as `dd`:
|
|
@@ -31,6 +32,7 @@ dd doctor
|
|
|
31
32
|
dd onboard
|
|
32
33
|
dd onboard --no-run
|
|
33
34
|
dd actions remotion-hub
|
|
35
|
+
dd actions remotion-hub init temp-project
|
|
34
36
|
```
|
|
35
37
|
|
|
36
38
|
## Requirements
|
|
@@ -115,12 +117,17 @@ Use `dd actions` to discover or call enabled micro-app actions through the runni
|
|
|
115
117
|
|
|
116
118
|
```bash
|
|
117
119
|
dd actions remotion-hub
|
|
120
|
+
dd actions remotion-hub init temp-project
|
|
118
121
|
dd actions remotion-hub search-components --query "animated chart" --limit 5
|
|
119
122
|
```
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
Remotion Hub `init` is handled locally by the CLI because it creates files on the caller's machine. Other Remotion Hub actions, such as search and registry lookup, call the configured Double Digit app over HTTP.
|
|
122
125
|
|
|
123
|
-
|
|
126
|
+
When no `--registry`, `--url`, or `--app-url` is passed, Remotion Hub init writes a registry URL from exported `DD_APP_URL`, `APP_URL`, `NEXT_PUBLIC_APP_URL`, or `BETTER_AUTH_URL`; then the release-configured hosted app URL; then `http://localhost:3111` for local development builds.
|
|
127
|
+
|
|
128
|
+
For HTTP-backed actions, the command resolves the app URL from exported `DD_APP_URL`, `APP_URL`, or `BETTER_AUTH_URL`; then local env-file `DD_APP_URL`; then the release-configured hosted app URL. It prints JSON responses to stdout. It also reads `.env`, `.env.local`, `apps/main-app/.env`, and `apps/main-app/.env.local`; exported shell values take precedence.
|
|
129
|
+
|
|
130
|
+
The published CLI embeds a hosted default from `DD_ACTIONS_DEFAULT_APP_URL` during the `@doubledigit/cli` package build, falling back to `DD_APP_URL`, `NEXT_PUBLIC_APP_URL`, or `BETTER_AUTH_URL`. Localhost values are not baked into the generated package default, but `DD_APP_URL` remains available as a runtime override for a specific invocation.
|
|
124
131
|
|
|
125
132
|
The hosted Double Digit app is the default for npm users:
|
|
126
133
|
|
|
@@ -136,7 +143,7 @@ Local development or self-hosted environments should override the target explici
|
|
|
136
143
|
DD_APP_URL=http://localhost:3111 dd actions remotion-hub
|
|
137
144
|
```
|
|
138
145
|
|
|
139
|
-
In GitHub Actions or another CI/CD runner, provide `DD_APP_URL` through the runner environment, variables, or secrets when building or publishing the CLI package. Do not rely on a local env file being present in CI.
|
|
146
|
+
In GitHub Actions or another CI/CD runner, provide `DD_ACTIONS_DEFAULT_APP_URL` or `DD_APP_URL` through the runner environment, variables, or secrets when building or publishing the CLI package. Do not rely on a local env file being present in CI.
|
|
140
147
|
|
|
141
148
|
GitHub or Infisical secrets are CI/CD inputs only. A local `npx @doubledigit/cli ...` command sees your shell environment and local env files, not repository secrets.
|
|
142
149
|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export declare function getDefaultActionsAppUrl(): string;
|
|
2
|
+
export declare function getActionPositionals(args: string[]): {
|
|
3
|
+
value: string;
|
|
4
|
+
index: number;
|
|
5
|
+
}[];
|
|
6
|
+
export declare function isRemotionHubInitAction(args: string[]): boolean;
|
|
7
|
+
export declare function buildRemotionHubInitCommandArgs(args: string[]): string[];
|
|
2
8
|
export declare function actions(args: string[]): Promise<void>;
|
|
3
9
|
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/commands/actions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/commands/actions.ts"],"names":[],"mappings":"AAkCA,wBAAgB,uBAAuB,WAKtC;AAgED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE;WACf,MAAM;WAAS,MAAM;IAuBxD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAGrD;AAED,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,YAI7D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B3D"}
|
package/dist/commands/actions.js
CHANGED
|
@@ -5,6 +5,22 @@ import { buildActionRequest, fetchActionRequest, isLocalAppUrl, parseActionsArgs
|
|
|
5
5
|
import { DEFAULT_APP_URL, readEnvFile } from '../lib/onboarding.js';
|
|
6
6
|
import { resolveWorkspacePaths } from '../paths.js';
|
|
7
7
|
import { scanWorkspace } from '../scanner.js';
|
|
8
|
+
import { runRemotionHubInitCommand } from './remotion-hub-init.js';
|
|
9
|
+
const actionValueOptions = new Set([
|
|
10
|
+
'--app-url',
|
|
11
|
+
'--dir',
|
|
12
|
+
'--id-or-slug',
|
|
13
|
+
'--kind',
|
|
14
|
+
'--limit',
|
|
15
|
+
'--namespace',
|
|
16
|
+
'--preview-type',
|
|
17
|
+
'--query',
|
|
18
|
+
'--registry',
|
|
19
|
+
'--slug',
|
|
20
|
+
'--tag',
|
|
21
|
+
'--tags',
|
|
22
|
+
'--url',
|
|
23
|
+
]);
|
|
8
24
|
export function getDefaultActionsAppUrl() {
|
|
9
25
|
return resolveDefaultActionAppUrl({
|
|
10
26
|
generatedUrl: GENERATED_DEFAULT_ACTIONS_APP_URL,
|
|
@@ -33,6 +49,7 @@ Options:
|
|
|
33
49
|
|
|
34
50
|
Examples:
|
|
35
51
|
dd actions remotion-hub
|
|
52
|
+
dd actions remotion-hub init my-video --registry https://double-digit.example
|
|
36
53
|
dd actions remotion-hub search-components --query "animated chart" --limit 5
|
|
37
54
|
dd actions remotion-hub get-component --namespace doubledigit --slug motion-strip
|
|
38
55
|
dd actions remotion-hub get-registry-payload --json '{"namespace":"doubledigit","slug":"motion-strip"}'
|
|
@@ -68,12 +85,54 @@ function tryResolveWorkspacePaths() {
|
|
|
68
85
|
return undefined;
|
|
69
86
|
}
|
|
70
87
|
}
|
|
88
|
+
export function getActionPositionals(args) {
|
|
89
|
+
const positionals = [];
|
|
90
|
+
for (let i = 0; i < args.length; i++) {
|
|
91
|
+
const arg = args[i];
|
|
92
|
+
if (!arg)
|
|
93
|
+
continue;
|
|
94
|
+
if (arg.startsWith('--')) {
|
|
95
|
+
const [flag, inlineValue] = arg.split(/=(.*)/s, 2);
|
|
96
|
+
if (flag === '--json' && inlineValue === undefined) {
|
|
97
|
+
const next = args[i + 1];
|
|
98
|
+
if (next && /^[{[]/.test(next.trim()))
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
else if (inlineValue === undefined && actionValueOptions.has(flag)) {
|
|
102
|
+
const next = args[i + 1];
|
|
103
|
+
if (next && !next.startsWith('--'))
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (arg === '-h')
|
|
109
|
+
continue;
|
|
110
|
+
positionals.push({ value: arg, index: i });
|
|
111
|
+
}
|
|
112
|
+
return positionals;
|
|
113
|
+
}
|
|
114
|
+
export function isRemotionHubInitAction(args) {
|
|
115
|
+
const positionals = getActionPositionals(args);
|
|
116
|
+
return positionals[0]?.value === 'remotion-hub' && positionals[1]?.value === 'init';
|
|
117
|
+
}
|
|
118
|
+
export function buildRemotionHubInitCommandArgs(args) {
|
|
119
|
+
const positionals = getActionPositionals(args);
|
|
120
|
+
const dropIndexes = new Set([positionals[0]?.index, positionals[1]?.index]);
|
|
121
|
+
return args.filter((_, index) => !dropIndexes.has(index));
|
|
122
|
+
}
|
|
71
123
|
export async function actions(args) {
|
|
124
|
+
if (isRemotionHubInitAction(args)) {
|
|
125
|
+
runRemotionHubInitCommand(buildRemotionHubInitCommandArgs(args));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
72
128
|
const parsed = parseActionsArgs(args);
|
|
73
129
|
if (parsed.help || !parsed.microApp) {
|
|
74
130
|
console.log(buildHelp());
|
|
75
131
|
return;
|
|
76
132
|
}
|
|
133
|
+
if (parsed.extraPositionals.length > 0) {
|
|
134
|
+
throw new Error(`Unexpected positional argument: ${parsed.extraPositionals[0]}`);
|
|
135
|
+
}
|
|
77
136
|
const paths = tryResolveWorkspacePaths();
|
|
78
137
|
const appUrl = resolveActionAppUrl({
|
|
79
138
|
explicitUrl: parsed.appUrl,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type RunRemotionHubInitResult } from '../lib/remotion-hub-init.js';
|
|
2
|
+
export declare function buildRemotionHubInitHelp(): string;
|
|
3
|
+
export declare function runRemotionHubInitCommand(args: string[]): RunRemotionHubInitResult | undefined;
|
|
4
|
+
//# sourceMappingURL=remotion-hub-init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotion-hub-init.d.ts","sourceRoot":"","sources":["../../src/commands/remotion-hub-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AA8EhG,wBAAgB,wBAAwB,WAsBvC;AAcD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,wBAAwB,GAAG,SAAS,CA0B9F"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { runRemotionHubInit } from '../lib/remotion-hub-init.js';
|
|
2
|
+
const valueFlags = new Set([
|
|
3
|
+
'app-url',
|
|
4
|
+
'dir',
|
|
5
|
+
'namespace',
|
|
6
|
+
'registry',
|
|
7
|
+
'url',
|
|
8
|
+
]);
|
|
9
|
+
function parseArgs(args) {
|
|
10
|
+
const positional = [];
|
|
11
|
+
const flags = {};
|
|
12
|
+
for (let i = 0; i < args.length; i++) {
|
|
13
|
+
const arg = args[i];
|
|
14
|
+
if (!arg)
|
|
15
|
+
continue;
|
|
16
|
+
if (arg === '-h') {
|
|
17
|
+
flags.h = true;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (!arg.startsWith('--')) {
|
|
21
|
+
positional.push(arg);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const [rawKey, inlineValue] = arg.slice(2).split(/=(.*)/s, 2);
|
|
25
|
+
if (!rawKey)
|
|
26
|
+
continue;
|
|
27
|
+
if (inlineValue !== undefined) {
|
|
28
|
+
flags[rawKey] = inlineValue;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (valueFlags.has(rawKey)) {
|
|
32
|
+
const next = args[i + 1];
|
|
33
|
+
if (!next || next.startsWith('--')) {
|
|
34
|
+
throw new Error(`--${rawKey} requires a value`);
|
|
35
|
+
}
|
|
36
|
+
flags[rawKey] = next;
|
|
37
|
+
i++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (rawKey === 'force'
|
|
41
|
+
|| rawKey === 'help'
|
|
42
|
+
|| rawKey === 'hub-only'
|
|
43
|
+
|| rawKey === 'json'
|
|
44
|
+
|| rawKey === 'skip-remotion-create') {
|
|
45
|
+
flags[rawKey] = true;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Unknown option for Remotion Hub init: --${rawKey}`);
|
|
49
|
+
}
|
|
50
|
+
return { positional, flags };
|
|
51
|
+
}
|
|
52
|
+
function stringFlag(flags, ...names) {
|
|
53
|
+
for (const name of names) {
|
|
54
|
+
const value = flags[name];
|
|
55
|
+
if (typeof value === 'string' && value.trim())
|
|
56
|
+
return value.trim();
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
function booleanFlag(flags, ...names) {
|
|
61
|
+
return names.some((name) => flags[name] === true);
|
|
62
|
+
}
|
|
63
|
+
export function buildRemotionHubInitHelp() {
|
|
64
|
+
return `
|
|
65
|
+
dd actions remotion-hub init - Initialize a local Remotion Hub project
|
|
66
|
+
|
|
67
|
+
Usage:
|
|
68
|
+
dd actions remotion-hub init [project-dir] [options]
|
|
69
|
+
|
|
70
|
+
Options:
|
|
71
|
+
--dir <path> Project directory
|
|
72
|
+
--registry <url> Double Digit app URL or /api/remotion-hub/r endpoint
|
|
73
|
+
--url, --app-url <url> Alias for --registry
|
|
74
|
+
--namespace <name> Registry namespace (default: doubledigit)
|
|
75
|
+
--skip-remotion-create Only add Remotion Hub files; do not run create-video
|
|
76
|
+
--hub-only Alias for --skip-remotion-create
|
|
77
|
+
--force Overwrite existing generated files
|
|
78
|
+
--json Print machine-readable JSON
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
dd actions remotion-hub init
|
|
82
|
+
dd actions remotion-hub init my-video
|
|
83
|
+
dd actions remotion-hub init my-video --registry https://double-digit.example
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
function printInit(result) {
|
|
87
|
+
console.log(`Initialized Remotion Hub in ${result.projectDir}`);
|
|
88
|
+
if (!result.remotionCreate.skipped) {
|
|
89
|
+
console.log(` Remotion project: ${result.remotionCreate.command} ${result.remotionCreate.args.join(' ')}`);
|
|
90
|
+
}
|
|
91
|
+
for (const file of result.created) {
|
|
92
|
+
console.log(` ${file}`);
|
|
93
|
+
}
|
|
94
|
+
console.log('');
|
|
95
|
+
console.log(`Registry: ${result.config.registry}`);
|
|
96
|
+
}
|
|
97
|
+
export function runRemotionHubInitCommand(args) {
|
|
98
|
+
const parsed = parseArgs(args);
|
|
99
|
+
const json = booleanFlag(parsed.flags, 'json');
|
|
100
|
+
if (booleanFlag(parsed.flags, 'help', 'h')) {
|
|
101
|
+
console.log(buildRemotionHubInitHelp());
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
if (parsed.positional.length > 1) {
|
|
105
|
+
throw new Error('Usage: dd actions remotion-hub init [project-dir] [options]');
|
|
106
|
+
}
|
|
107
|
+
const result = runRemotionHubInit({
|
|
108
|
+
projectDir: stringFlag(parsed.flags, 'dir') ?? parsed.positional[0],
|
|
109
|
+
registry: stringFlag(parsed.flags, 'registry', 'url', 'app-url'),
|
|
110
|
+
namespace: stringFlag(parsed.flags, 'namespace'),
|
|
111
|
+
force: booleanFlag(parsed.flags, 'force'),
|
|
112
|
+
skipRemotionCreate: booleanFlag(parsed.flags, 'skip-remotion-create', 'hub-only'),
|
|
113
|
+
quiet: json,
|
|
114
|
+
});
|
|
115
|
+
if (json)
|
|
116
|
+
console.log(JSON.stringify(result, null, 2));
|
|
117
|
+
else
|
|
118
|
+
printInit(result);
|
|
119
|
+
return result;
|
|
120
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* without importing the full extension-management dependency graph first.
|
|
7
7
|
*/
|
|
8
8
|
declare const command: string, args: string[];
|
|
9
|
-
declare const HELP = "\n@doubledigit/cli \u2014 Manage extensions and local setup\n\nCommands:\n doctor Check local prerequisites and project health\n onboard Prepare local development and start the app\n run Start the local app with automatic DB bootstrap\n dev Start DB + app without migrations or seed data\n db <subcommand> Database helpers (status, migrate, create)\n actions <app> [action] Discover and invoke micro-app actions\n create <name> Scaffold a new micro-app from the template\n init <project-name> Scaffold a new Double Digit project\n add|install <source> Install an extension from GitHub or a marketplace\n sync Regenerate micro-apps.ts from dd-apps.config.json\n enable <name> Enable a micro-app (updates config + runs sync)\n disable <name> Disable a micro-app (updates config + runs sync)\n uninstall|remove <name> Completely remove a micro-app\n list List all discovered micro-apps with enabled/disabled status\n info <name> Show detailed info about an installed extension\n outdated Check for outdated marketplace extensions\n reconcile Detect drift between lock file, marketplace, and local files\n marketplace <sub> Manage marketplace registrations (add/list/update/remove)\n browse [marketplace] Browse available extensions in registered marketplaces\n\nOptions:\n --help, -h Show this help message\n\nExamples:\n dd doctor\n dd onboard --yes\n dd onboard # setup + start the dev server\n dd onboard --no-run # setup only\n dd init my-project # scaffold and bootstrap a fresh project\n dd init my-project --run # scaffold + bootstrap + start\n dd init my-project --skip-install --no-git\n dd run\n dd dev\n dd db status\n dd actions remotion-hub search-components --query \"animated chart\"\n dd create invoice-tracker\n dd add gh:owner/repo/extensions/micro-apps/habit-tracker\n dd add habit-tracker@community\n dd info habit-tracker\n dd reconcile\n dd marketplace add digitaldouble/dd-marketplace\n dd browse community\n DD_APPS=tasks,agent-v2 dd sync\n";
|
|
9
|
+
declare const HELP = "\n@doubledigit/cli \u2014 Manage extensions and local setup\n\nCommands:\n doctor Check local prerequisites and project health\n onboard Prepare local development and start the app\n run Start the local app with automatic DB bootstrap\n dev Start DB + app without migrations or seed data\n db <subcommand> Database helpers (status, migrate, create)\n actions <app> [action] Discover and invoke micro-app actions\n create <name> Scaffold a new micro-app from the template\n init <project-name> Scaffold a new Double Digit project\n add|install <source> Install an extension from GitHub or a marketplace\n sync Regenerate micro-apps.ts from dd-apps.config.json\n enable <name> Enable a micro-app (updates config + runs sync)\n disable <name> Disable a micro-app (updates config + runs sync)\n uninstall|remove <name> Completely remove a micro-app\n list List all discovered micro-apps with enabled/disabled status\n info <name> Show detailed info about an installed extension\n outdated Check for outdated marketplace extensions\n reconcile Detect drift between lock file, marketplace, and local files\n marketplace <sub> Manage marketplace registrations (add/list/update/remove)\n browse [marketplace] Browse available extensions in registered marketplaces\n\nOptions:\n --help, -h Show this help message\n\nExamples:\n dd doctor\n dd onboard --yes\n dd onboard # setup + start the dev server\n dd onboard --no-run # setup only\n dd init my-project # scaffold and bootstrap a fresh project\n dd init my-project --run # scaffold + bootstrap + start\n dd init my-project --skip-install --no-git\n dd run\n dd dev\n dd db status\n dd actions remotion-hub init my-video --registry https://double-digit.example\n dd actions remotion-hub search-components --query \"animated chart\"\n dd create invoice-tracker\n dd add gh:owner/repo/extensions/micro-apps/habit-tracker\n dd add habit-tracker@community\n dd info habit-tracker\n dd reconcile\n dd marketplace add digitaldouble/dd-marketplace\n dd browse community\n DD_APPS=tasks,agent-v2 dd sync\n";
|
|
10
10
|
declare function requireArg(value: string | undefined, usage: string): string;
|
|
11
11
|
declare function runAddCommand(rawArgs: string[]): Promise<void>;
|
|
12
12
|
declare function main(): Promise<void>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,QAAA,MAAW,OAAO,UAAK,IAAI,UAAgB,CAAC;AAE5C,QAAA,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,QAAA,MAAW,OAAO,UAAK,IAAI,UAAgB,CAAC;AAE5C,QAAA,MAAM,IAAI,0xEAgDT,CAAC;AAEF,iBAAS,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED,iBAAe,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB7D;AAED,iBAAe,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAsInC"}
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ Examples:
|
|
|
45
45
|
dd run
|
|
46
46
|
dd dev
|
|
47
47
|
dd db status
|
|
48
|
+
dd actions remotion-hub init my-video --registry https://double-digit.example
|
|
48
49
|
dd actions remotion-hub search-components --query "animated chart"
|
|
49
50
|
dd create invoice-tracker
|
|
50
51
|
dd add gh:owner/repo/extensions/micro-apps/habit-tracker
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions-client.d.ts","sourceRoot":"","sources":["../../src/lib/actions-client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,MAAM,WAAW,iCAAiC;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,GAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,EAAE,iCAAiC,UAKnC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,GAAiB,EACjB,OAAY,EACZ,UAAU,GACX,EAAE,0BAA0B,UAS5B;AA2DD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"actions-client.d.ts","sourceRoot":"","sources":["../../src/lib/actions-client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,MAAM,WAAW,iCAAiC;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,GAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,EAAE,iCAAiC,UAKnC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,GAAiB,EACjB,OAAY,EACZ,UAAU,GACX,EAAE,0BAA0B,UAS5B;AA2DD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAuDlE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,UAS7C;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,WAK3C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,GAAG,YAAY,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAoBtI;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAuBjF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
export interface RemotionHubConfig {
|
|
3
|
+
$schema: string;
|
|
4
|
+
registry: string;
|
|
5
|
+
namespace: string;
|
|
6
|
+
paths: {
|
|
7
|
+
scenes: string;
|
|
8
|
+
components: string;
|
|
9
|
+
overlays: string;
|
|
10
|
+
transitions: string;
|
|
11
|
+
assets: string;
|
|
12
|
+
registry: string;
|
|
13
|
+
};
|
|
14
|
+
remotion: {
|
|
15
|
+
entrypoint: string;
|
|
16
|
+
root: string;
|
|
17
|
+
publicDir: string;
|
|
18
|
+
};
|
|
19
|
+
packageManager: 'pnpm' | 'npm' | 'yarn' | 'bun';
|
|
20
|
+
project: {
|
|
21
|
+
language: 'typescript' | 'javascript';
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface RemotionHubLock {
|
|
25
|
+
version: 1;
|
|
26
|
+
installed: Record<string, {
|
|
27
|
+
version: string | null;
|
|
28
|
+
type: string;
|
|
29
|
+
namespace: string;
|
|
30
|
+
slug: string;
|
|
31
|
+
resolved: string;
|
|
32
|
+
files: string[];
|
|
33
|
+
dependencies: string[];
|
|
34
|
+
installedAt: string;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
export interface RunRemotionHubInitOptions {
|
|
38
|
+
projectDir?: string;
|
|
39
|
+
registry?: string;
|
|
40
|
+
namespace?: string;
|
|
41
|
+
force?: boolean;
|
|
42
|
+
skipRemotionCreate?: boolean;
|
|
43
|
+
quiet?: boolean;
|
|
44
|
+
spawnImpl?: typeof spawnSync;
|
|
45
|
+
}
|
|
46
|
+
export interface RunRemotionHubInitResult {
|
|
47
|
+
projectDir: string;
|
|
48
|
+
configPath: string;
|
|
49
|
+
lockPath: string;
|
|
50
|
+
created: string[];
|
|
51
|
+
config: RemotionHubConfig;
|
|
52
|
+
remotionCreate: {
|
|
53
|
+
skipped: boolean;
|
|
54
|
+
command: string;
|
|
55
|
+
args: string[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export interface ResolveRemotionHubRegistryOptions {
|
|
59
|
+
registry?: string;
|
|
60
|
+
env?: Record<string, string | undefined>;
|
|
61
|
+
generatedDefaultRegistry?: string;
|
|
62
|
+
localDefaultRegistry?: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function resolveRemotionHubRegistry({ registry, env, generatedDefaultRegistry, localDefaultRegistry, }?: ResolveRemotionHubRegistryOptions): string;
|
|
65
|
+
export declare function runRemotionHubInit(options?: RunRemotionHubInitOptions): RunRemotionHubInitResult;
|
|
66
|
+
//# sourceMappingURL=remotion-hub-init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotion-hub-init.d.ts","sourceRoot":"","sources":["../../src/lib/remotion-hub-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAyB,MAAM,oBAAoB,CAAC;AAkBtE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,cAAc,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAChD,OAAO,EAAE;QACP,QAAQ,EAAE,YAAY,GAAG,YAAY,CAAC;KACvC,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,cAAc,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;CACH;AAsFD,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACR,GAAiB,EACjB,wBAA4D,EAC5D,oBAAuC,GACxC,GAAE,iCAAsC,UAQxC;AAuJD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,wBAAwB,CA+CpG"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { GENERATED_DEFAULT_ACTIONS_APP_URL } from '../generated/defaults.js';
|
|
5
|
+
import { isLocalAppUrl } from './actions-client.js';
|
|
6
|
+
const CONFIG_FILE = 'remotion-hub.json';
|
|
7
|
+
const LOCK_FILE = 'remotion-hub.lock.json';
|
|
8
|
+
const DEFAULT_REGISTRY = 'http://localhost:3111';
|
|
9
|
+
const DEFAULT_NAMESPACE = 'doubledigit';
|
|
10
|
+
function toJson(value) {
|
|
11
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
12
|
+
}
|
|
13
|
+
function readJsonFile(filePath, fallback) {
|
|
14
|
+
if (!existsSync(filePath))
|
|
15
|
+
return fallback;
|
|
16
|
+
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
17
|
+
}
|
|
18
|
+
function writeJsonFile(filePath, value) {
|
|
19
|
+
writeFileSync(filePath, toJson(value), 'utf8');
|
|
20
|
+
}
|
|
21
|
+
function readUrlValue(value) {
|
|
22
|
+
const trimmed = value?.trim();
|
|
23
|
+
return trimmed || undefined;
|
|
24
|
+
}
|
|
25
|
+
function readHostedGeneratedRegistry(value) {
|
|
26
|
+
const trimmed = readUrlValue(value);
|
|
27
|
+
if (!trimmed)
|
|
28
|
+
return undefined;
|
|
29
|
+
try {
|
|
30
|
+
return isLocalAppUrl(trimmed) ? undefined : trimmed;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function normalizeSlashes(value) {
|
|
37
|
+
return value.split(path.sep).join('/');
|
|
38
|
+
}
|
|
39
|
+
function commandCwd() {
|
|
40
|
+
return process.env.INIT_CWD || process.cwd();
|
|
41
|
+
}
|
|
42
|
+
function resolveProjectDir(projectDir) {
|
|
43
|
+
return path.resolve(commandCwd(), projectDir ?? '.');
|
|
44
|
+
}
|
|
45
|
+
function ensureRelativePath(value, label) {
|
|
46
|
+
const trimmed = value.trim();
|
|
47
|
+
if (!trimmed)
|
|
48
|
+
throw new Error(`${label} is required`);
|
|
49
|
+
if (path.isAbsolute(trimmed))
|
|
50
|
+
throw new Error(`${label} must be a relative path`);
|
|
51
|
+
const normalized = path.posix.normalize(trimmed.replace(/\\/g, '/'));
|
|
52
|
+
if (normalized === '..' || normalized.startsWith('../')) {
|
|
53
|
+
throw new Error(`${label} cannot escape the project directory`);
|
|
54
|
+
}
|
|
55
|
+
return normalized;
|
|
56
|
+
}
|
|
57
|
+
function resolveInsideProject(projectDir, relativePath, label) {
|
|
58
|
+
const safeRelativePath = ensureRelativePath(relativePath, label);
|
|
59
|
+
const resolved = path.resolve(projectDir, safeRelativePath);
|
|
60
|
+
const root = path.resolve(projectDir);
|
|
61
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
|
|
62
|
+
throw new Error(`${label} cannot escape the project directory`);
|
|
63
|
+
}
|
|
64
|
+
return resolved;
|
|
65
|
+
}
|
|
66
|
+
function detectPackageManager(projectDir) {
|
|
67
|
+
if (existsSync(path.join(projectDir, 'pnpm-lock.yaml')))
|
|
68
|
+
return 'pnpm';
|
|
69
|
+
if (existsSync(path.join(projectDir, 'yarn.lock')))
|
|
70
|
+
return 'yarn';
|
|
71
|
+
if (existsSync(path.join(projectDir, 'bun.lockb')) || existsSync(path.join(projectDir, 'bun.lock')))
|
|
72
|
+
return 'bun';
|
|
73
|
+
return 'npm';
|
|
74
|
+
}
|
|
75
|
+
function detectLanguage(projectDir) {
|
|
76
|
+
if (existsSync(path.join(projectDir, 'tsconfig.json')))
|
|
77
|
+
return 'typescript';
|
|
78
|
+
if (existsSync(path.join(projectDir, 'src', 'index.ts'))
|
|
79
|
+
|| existsSync(path.join(projectDir, 'src', 'index.tsx'))
|
|
80
|
+
|| existsSync(path.join(projectDir, 'src', 'Root.tsx'))) {
|
|
81
|
+
return 'typescript';
|
|
82
|
+
}
|
|
83
|
+
return 'javascript';
|
|
84
|
+
}
|
|
85
|
+
function firstExisting(projectDir, candidates, fallback) {
|
|
86
|
+
return candidates.find((candidate) => existsSync(path.join(projectDir, candidate))) ?? fallback;
|
|
87
|
+
}
|
|
88
|
+
export function resolveRemotionHubRegistry({ registry, env = process.env, generatedDefaultRegistry = GENERATED_DEFAULT_ACTIONS_APP_URL, localDefaultRegistry = DEFAULT_REGISTRY, } = {}) {
|
|
89
|
+
return readUrlValue(registry)
|
|
90
|
+
?? readUrlValue(env.DD_APP_URL)
|
|
91
|
+
?? readUrlValue(env.APP_URL)
|
|
92
|
+
?? readUrlValue(env.NEXT_PUBLIC_APP_URL)
|
|
93
|
+
?? readUrlValue(env.BETTER_AUTH_URL)
|
|
94
|
+
?? readHostedGeneratedRegistry(generatedDefaultRegistry)
|
|
95
|
+
?? localDefaultRegistry;
|
|
96
|
+
}
|
|
97
|
+
function defaultConfig(projectDir, options) {
|
|
98
|
+
const language = detectLanguage(projectDir);
|
|
99
|
+
const rootExtension = language === 'typescript' ? 'tsx' : 'jsx';
|
|
100
|
+
const entryExtension = language === 'typescript' ? 'ts' : 'js';
|
|
101
|
+
return {
|
|
102
|
+
$schema: 'https://remotion-hub.dev/schema/remotion-hub.json',
|
|
103
|
+
registry: resolveRemotionHubRegistry({ registry: options.registry }),
|
|
104
|
+
namespace: options.namespace?.trim() || DEFAULT_NAMESPACE,
|
|
105
|
+
paths: {
|
|
106
|
+
scenes: 'src/remotion-hub/scenes',
|
|
107
|
+
components: 'src/remotion-hub/components',
|
|
108
|
+
overlays: 'src/remotion-hub/overlays',
|
|
109
|
+
transitions: 'src/remotion-hub/transitions',
|
|
110
|
+
assets: 'public/remotion-hub/assets',
|
|
111
|
+
registry: `src/remotion-hub/registry.${entryExtension}`,
|
|
112
|
+
},
|
|
113
|
+
remotion: {
|
|
114
|
+
entrypoint: firstExisting(projectDir, ['src/index.ts', 'src/index.tsx', 'src/index.js', 'src/index.jsx'], `src/index.${entryExtension}`),
|
|
115
|
+
root: firstExisting(projectDir, ['src/Root.tsx', 'src/Root.jsx', 'src/root.tsx', 'src/root.jsx'], `src/Root.${rootExtension}`),
|
|
116
|
+
publicDir: 'public',
|
|
117
|
+
},
|
|
118
|
+
packageManager: detectPackageManager(projectDir),
|
|
119
|
+
project: {
|
|
120
|
+
language,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function defaultLock() {
|
|
125
|
+
return {
|
|
126
|
+
version: 1,
|
|
127
|
+
installed: {},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function ensureDir(projectDir, relativePath, created) {
|
|
131
|
+
const target = resolveInsideProject(projectDir, relativePath, relativePath);
|
|
132
|
+
if (!existsSync(target)) {
|
|
133
|
+
mkdirSync(target, { recursive: true });
|
|
134
|
+
created.push(normalizeSlashes(path.relative(projectDir, target)));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function registrySource(config, lock) {
|
|
138
|
+
const installed = Object.entries(lock.installed)
|
|
139
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
140
|
+
.reduce((acc, [name, entry]) => {
|
|
141
|
+
acc[name] = {
|
|
142
|
+
type: entry.type,
|
|
143
|
+
namespace: entry.namespace,
|
|
144
|
+
slug: entry.slug,
|
|
145
|
+
files: entry.files,
|
|
146
|
+
};
|
|
147
|
+
return acc;
|
|
148
|
+
}, {});
|
|
149
|
+
const lines = [
|
|
150
|
+
'// Generated by remotion-hub. Do not edit manually.',
|
|
151
|
+
'',
|
|
152
|
+
`export const remotionHubRegistry = ${JSON.stringify(installed, null, 2)}${config.project.language === 'typescript' ? ' as const' : ''};`,
|
|
153
|
+
'',
|
|
154
|
+
];
|
|
155
|
+
if (config.project.language === 'typescript') {
|
|
156
|
+
lines.push('export type RemotionHubRegistry = typeof remotionHubRegistry;', '');
|
|
157
|
+
}
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
}
|
|
160
|
+
function writeRegistryFile(projectDir, config, lock) {
|
|
161
|
+
const registryPath = resolveInsideProject(projectDir, config.paths.registry, 'paths.registry');
|
|
162
|
+
mkdirSync(path.dirname(registryPath), { recursive: true });
|
|
163
|
+
writeFileSync(registryPath, registrySource(config, lock), 'utf8');
|
|
164
|
+
}
|
|
165
|
+
function hasPackageJson(projectDir) {
|
|
166
|
+
return existsSync(path.join(projectDir, 'package.json'));
|
|
167
|
+
}
|
|
168
|
+
function hasEntries(projectDir) {
|
|
169
|
+
return existsSync(projectDir) && readdirSync(projectDir).length > 0;
|
|
170
|
+
}
|
|
171
|
+
function buildRemotionCreateCommand(projectDir) {
|
|
172
|
+
return {
|
|
173
|
+
command: 'npx',
|
|
174
|
+
args: ['create-video@latest', '--yes', '--blank', projectDir],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function assertRemotionCreateSucceeded(result, command, args) {
|
|
178
|
+
if (result.error) {
|
|
179
|
+
throw new Error(`Remotion project creation failed: ${result.error.message}`);
|
|
180
|
+
}
|
|
181
|
+
if (result.status !== 0) {
|
|
182
|
+
throw new Error(`Remotion project creation failed: ${command} ${args.join(' ')}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function ensureBaseRemotionProject(projectDir, options) {
|
|
186
|
+
const remotionCreate = buildRemotionCreateCommand(projectDir);
|
|
187
|
+
if (options.skipRemotionCreate || hasPackageJson(projectDir)) {
|
|
188
|
+
return {
|
|
189
|
+
...remotionCreate,
|
|
190
|
+
skipped: true,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (hasEntries(projectDir)) {
|
|
194
|
+
throw new Error(`Project directory exists but is not a Remotion project: ${projectDir}. `
|
|
195
|
+
+ 'Remove it, choose an empty path, or run Remotion setup manually before Remotion Hub init.');
|
|
196
|
+
}
|
|
197
|
+
const result = (options.spawnImpl ?? spawnSync)(remotionCreate.command, remotionCreate.args, {
|
|
198
|
+
cwd: process.cwd(),
|
|
199
|
+
stdio: options.quiet ? 'pipe' : 'inherit',
|
|
200
|
+
});
|
|
201
|
+
assertRemotionCreateSucceeded(result, remotionCreate.command, remotionCreate.args);
|
|
202
|
+
return {
|
|
203
|
+
...remotionCreate,
|
|
204
|
+
skipped: false,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function loadConfig(projectDir) {
|
|
208
|
+
const configPath = path.join(projectDir, CONFIG_FILE);
|
|
209
|
+
if (!existsSync(configPath)) {
|
|
210
|
+
throw new Error(`Missing ${CONFIG_FILE}. Run Remotion Hub init first.`);
|
|
211
|
+
}
|
|
212
|
+
return JSON.parse(readFileSync(configPath, 'utf8'));
|
|
213
|
+
}
|
|
214
|
+
export function runRemotionHubInit(options = {}) {
|
|
215
|
+
const projectDir = resolveProjectDir(options.projectDir);
|
|
216
|
+
const configPath = path.join(projectDir, CONFIG_FILE);
|
|
217
|
+
const lockPath = path.join(projectDir, LOCK_FILE);
|
|
218
|
+
const created = [];
|
|
219
|
+
const remotionCreate = ensureBaseRemotionProject(projectDir, options);
|
|
220
|
+
mkdirSync(projectDir, { recursive: true });
|
|
221
|
+
const configExists = existsSync(configPath);
|
|
222
|
+
const lockExists = existsSync(lockPath);
|
|
223
|
+
const config = configExists && !options.force
|
|
224
|
+
? loadConfig(projectDir)
|
|
225
|
+
: defaultConfig(projectDir, options);
|
|
226
|
+
if (!configExists || options.force) {
|
|
227
|
+
writeJsonFile(configPath, config);
|
|
228
|
+
created.push(CONFIG_FILE);
|
|
229
|
+
}
|
|
230
|
+
if (!lockExists || options.force) {
|
|
231
|
+
writeJsonFile(lockPath, defaultLock());
|
|
232
|
+
created.push(LOCK_FILE);
|
|
233
|
+
}
|
|
234
|
+
for (const dir of [
|
|
235
|
+
config.paths.scenes,
|
|
236
|
+
config.paths.components,
|
|
237
|
+
config.paths.overlays,
|
|
238
|
+
config.paths.transitions,
|
|
239
|
+
config.paths.assets,
|
|
240
|
+
]) {
|
|
241
|
+
ensureDir(projectDir, dir, created);
|
|
242
|
+
}
|
|
243
|
+
const lock = readJsonFile(lockPath, defaultLock());
|
|
244
|
+
writeRegistryFile(projectDir, config, lock);
|
|
245
|
+
created.push(config.paths.registry);
|
|
246
|
+
return {
|
|
247
|
+
projectDir,
|
|
248
|
+
configPath,
|
|
249
|
+
lockPath,
|
|
250
|
+
created,
|
|
251
|
+
config,
|
|
252
|
+
remotionCreate,
|
|
253
|
+
};
|
|
254
|
+
}
|