@insforge/cli 0.1.20 → 0.1.23
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 +110 -0
- package/dist/index.js +85 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,6 +137,49 @@ insforge metadata
|
|
|
137
137
|
insforge metadata --json
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
#### `insforge logs`
|
|
141
|
+
|
|
142
|
+
Fetch backend container logs.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
insforge logs <source> [options]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Sources:** `insforge.logs`, `postgREST.logs`, `postgres.logs`, `function.logs`
|
|
149
|
+
|
|
150
|
+
**Options:**
|
|
151
|
+
- `--limit <n>`: Number of log entries to return (default: 20)
|
|
152
|
+
|
|
153
|
+
**Examples:**
|
|
154
|
+
```bash
|
|
155
|
+
insforge logs insforge.logs
|
|
156
|
+
insforge logs postgres.logs --limit 50
|
|
157
|
+
insforge logs function.logs --json
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### `insforge docs`
|
|
161
|
+
|
|
162
|
+
Browse InsForge SDK documentation.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
insforge docs [feature] [language]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Features:** `db`, `storage`, `functions`, `auth`, `ai`, `realtime`, `instructions`
|
|
169
|
+
**Languages:** `typescript`, `swift`, `kotlin`, `rest-api`
|
|
170
|
+
|
|
171
|
+
**Examples:**
|
|
172
|
+
```bash
|
|
173
|
+
# List all available docs
|
|
174
|
+
insforge docs
|
|
175
|
+
|
|
176
|
+
# Specific feature/language docs
|
|
177
|
+
insforge docs instructions # Show backend setup instructions
|
|
178
|
+
insforge docs db typescript # Show TypeScript database SDK docs
|
|
179
|
+
insforge docs auth swift # Show Swift auth SDK docs
|
|
180
|
+
insforge docs storage rest-api # Show REST API storage docs
|
|
181
|
+
```
|
|
182
|
+
|
|
140
183
|
---
|
|
141
184
|
|
|
142
185
|
### Database — `insforge db`
|
|
@@ -258,6 +301,15 @@ insforge functions invoke my-function --method GET
|
|
|
258
301
|
insforge functions invoke my-function --data '{"key": "value"}' --json
|
|
259
302
|
```
|
|
260
303
|
|
|
304
|
+
#### `insforge functions delete <slug>`
|
|
305
|
+
|
|
306
|
+
Delete an edge function.
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
insforge functions delete my-function
|
|
310
|
+
insforge functions delete my-function -y # skip confirmation
|
|
311
|
+
```
|
|
312
|
+
|
|
261
313
|
---
|
|
262
314
|
|
|
263
315
|
### Storage — `insforge storage`
|
|
@@ -409,6 +461,64 @@ insforge secrets delete STRIPE_API_KEY
|
|
|
409
461
|
insforge secrets delete STRIPE_API_KEY -y # skip confirmation
|
|
410
462
|
```
|
|
411
463
|
|
|
464
|
+
### Schedules — `insforge schedules`
|
|
465
|
+
|
|
466
|
+
Manage scheduled tasks (cron jobs).
|
|
467
|
+
|
|
468
|
+
#### `insforge schedules list`
|
|
469
|
+
|
|
470
|
+
List all schedules in the current project.
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
insforge schedules list
|
|
474
|
+
insforge schedules list --json
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
#### `insforge schedules create`
|
|
478
|
+
|
|
479
|
+
Create a new scheduled task.
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
insforge schedules create --name "daily-cleanup" --cron "0 0 * * *" --url "https://api.example.com/cleanup" --method POST
|
|
483
|
+
insforge schedules create --name "hourly-sync" --cron "0 * * * *" --url "https://api.example.com/sync" --method GET --headers '{"Authorization": "Bearer xxx"}'
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
#### `insforge schedules get <id>`
|
|
487
|
+
|
|
488
|
+
Get details of a specific schedule.
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
insforge schedules get <id>
|
|
492
|
+
insforge schedules get 123 --json
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
#### `insforge schedules update <id>`
|
|
496
|
+
|
|
497
|
+
Update an existing schedule.
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
insforge schedules update <id> --name "weekly-cleanup" --cron "0 0 * * 0"
|
|
501
|
+
insforge schedules update 123 --active false
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
#### `insforge schedules delete <id>`
|
|
505
|
+
|
|
506
|
+
Delete a schedule.
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
insforge schedules delete <id>
|
|
510
|
+
insforge schedules delete 123 -y
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
#### `insforge schedules logs <id>`
|
|
514
|
+
|
|
515
|
+
Fetch execution logs for a specific schedule.
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
insforge schedules logs <id>
|
|
519
|
+
insforge schedules logs 123 --limit 100
|
|
520
|
+
```
|
|
521
|
+
|
|
412
522
|
---
|
|
413
523
|
|
|
414
524
|
## Project Configuration
|
package/dist/index.js
CHANGED
|
@@ -720,6 +720,16 @@ async function installSkills(json) {
|
|
|
720
720
|
} catch {
|
|
721
721
|
if (!json) clack5.log.warn("Failed to install agent skills. You can run manually: npx skills add insforge/agent-skills -s insforge -s insforge-cli");
|
|
722
722
|
}
|
|
723
|
+
try {
|
|
724
|
+
if (!json) clack5.log.info("Installing find-skills...");
|
|
725
|
+
await execAsync("npx skills add https://github.com/vercel-labs/skills --skill find-skills -y", {
|
|
726
|
+
cwd: process.cwd(),
|
|
727
|
+
timeout: 6e4
|
|
728
|
+
});
|
|
729
|
+
if (!json) clack5.log.success("find-skills installed.");
|
|
730
|
+
} catch {
|
|
731
|
+
if (!json) clack5.log.warn("Failed to install find-skills. You can run manually: npx skills add https://github.com/vercel-labs/skills --skill find-skills");
|
|
732
|
+
}
|
|
723
733
|
try {
|
|
724
734
|
updateGitignore();
|
|
725
735
|
} catch {
|
|
@@ -1433,8 +1443,8 @@ Specify --file <path> or create ${join3("insforge", "functions", slug, "index.ts
|
|
|
1433
1443
|
}
|
|
1434
1444
|
}
|
|
1435
1445
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1446
|
+
if (deployFailed) throw new CLIError("Function deployment failed");
|
|
1447
|
+
await reportCliUsage("cli.functions.deploy", true);
|
|
1438
1448
|
} catch (err) {
|
|
1439
1449
|
await reportCliUsage("cli.functions.deploy", false);
|
|
1440
1450
|
handleError(err, json);
|
|
@@ -1470,20 +1480,14 @@ function registerFunctionsInvokeCommand(functionsCmd2) {
|
|
|
1470
1480
|
if (json) {
|
|
1471
1481
|
outputJson({ status, body: data });
|
|
1472
1482
|
} else {
|
|
1473
|
-
if (status >= 400) {
|
|
1474
|
-
console.error(`HTTP ${status}`);
|
|
1475
|
-
}
|
|
1476
1483
|
console.log(JSON.stringify(data, null, 2));
|
|
1477
1484
|
}
|
|
1478
1485
|
} else {
|
|
1479
1486
|
const text3 = await res.text();
|
|
1480
|
-
if (!json && status >= 400) {
|
|
1481
|
-
console.error(`HTTP ${status}`);
|
|
1482
|
-
}
|
|
1483
1487
|
console.log(text3);
|
|
1484
1488
|
}
|
|
1485
1489
|
if (status >= 400) {
|
|
1486
|
-
|
|
1490
|
+
throw new CLIError(`HTTP ${status}`, 1, "HTTP_ERROR");
|
|
1487
1491
|
}
|
|
1488
1492
|
} catch (err) {
|
|
1489
1493
|
handleError(err, json);
|
|
@@ -1964,7 +1968,7 @@ async function copyDir(src, dest) {
|
|
|
1964
1968
|
}
|
|
1965
1969
|
}
|
|
1966
1970
|
function registerCreateCommand(program2) {
|
|
1967
|
-
program2.command("create").description("Create a new InsForge project").option("--name <name>", "Project name").option("--org-id <id>", "Organization ID").option("--region <region>", "Deployment region (us-east, us-west, eu-central, ap-southeast)").option("--template <template>", "Template to use: react, nextjs, or empty").action(async (opts, cmd) => {
|
|
1971
|
+
program2.command("create").description("Create a new InsForge project").option("--name <name>", "Project name").option("--org-id <id>", "Organization ID").option("--region <region>", "Deployment region (us-east, us-west, eu-central, ap-southeast)").option("--template <template>", "Template to use: react, nextjs, chatbot, or empty").action(async (opts, cmd) => {
|
|
1968
1972
|
const { json, apiUrl } = getRootOpts(cmd);
|
|
1969
1973
|
try {
|
|
1970
1974
|
await requireAuth(apiUrl);
|
|
@@ -2013,6 +2017,7 @@ function registerCreateCommand(program2) {
|
|
|
2013
2017
|
options: [
|
|
2014
2018
|
{ value: "react", label: "Web app template with React" },
|
|
2015
2019
|
{ value: "nextjs", label: "Web app template with Next.js" },
|
|
2020
|
+
{ value: "chatbot", label: "AI Chatbot with Next.js" },
|
|
2016
2021
|
{ value: "empty", label: "Empty project" }
|
|
2017
2022
|
]
|
|
2018
2023
|
});
|
|
@@ -2038,7 +2043,9 @@ function registerCreateCommand(program2) {
|
|
|
2038
2043
|
saveProjectConfig(projectConfig);
|
|
2039
2044
|
s?.stop(`Project "${project.name}" created and linked`);
|
|
2040
2045
|
const hasTemplate = template !== "empty";
|
|
2041
|
-
if (
|
|
2046
|
+
if (template === "chatbot") {
|
|
2047
|
+
await downloadGitHubTemplate("chatbot", projectConfig, json);
|
|
2048
|
+
} else if (hasTemplate) {
|
|
2042
2049
|
await downloadTemplate(template, projectConfig, projectName, json, apiUrl);
|
|
2043
2050
|
}
|
|
2044
2051
|
await installCliGlobally(json);
|
|
@@ -2144,6 +2151,72 @@ async function downloadTemplate(framework, projectConfig, projectName, json, _ap
|
|
|
2144
2151
|
}
|
|
2145
2152
|
}
|
|
2146
2153
|
}
|
|
2154
|
+
async function downloadGitHubTemplate(templateName, projectConfig, json) {
|
|
2155
|
+
const s = !json ? clack10.spinner() : null;
|
|
2156
|
+
s?.start(`Downloading ${templateName} template...`);
|
|
2157
|
+
const tempDir = path2.join(tmpdir(), `insforge-template-${Date.now()}`);
|
|
2158
|
+
try {
|
|
2159
|
+
await fs2.mkdir(tempDir, { recursive: true });
|
|
2160
|
+
await execAsync2(
|
|
2161
|
+
"git clone --depth 1 https://github.com/InsForge/insforge-templates.git .",
|
|
2162
|
+
{ cwd: tempDir, maxBuffer: 10 * 1024 * 1024, timeout: 6e4 }
|
|
2163
|
+
);
|
|
2164
|
+
const templateDir = path2.join(tempDir, templateName);
|
|
2165
|
+
const stat3 = await fs2.stat(templateDir).catch(() => null);
|
|
2166
|
+
if (!stat3?.isDirectory()) {
|
|
2167
|
+
throw new Error(`Template "${templateName}" not found in repository`);
|
|
2168
|
+
}
|
|
2169
|
+
s?.message("Copying template files...");
|
|
2170
|
+
const cwd = process.cwd();
|
|
2171
|
+
await copyDir(templateDir, cwd);
|
|
2172
|
+
const envExamplePath = path2.join(cwd, ".env.example");
|
|
2173
|
+
const envExampleExists = await fs2.stat(envExamplePath).catch(() => null);
|
|
2174
|
+
if (envExampleExists) {
|
|
2175
|
+
const anonKey = await getAnonKey();
|
|
2176
|
+
const envExample = await fs2.readFile(envExamplePath, "utf-8");
|
|
2177
|
+
const envContent = envExample.replace(
|
|
2178
|
+
/^([A-Z_]+=)(.*)$/gm,
|
|
2179
|
+
(_, prefix, _value) => {
|
|
2180
|
+
const key = prefix.slice(0, -1);
|
|
2181
|
+
if (/INSFORGE.*(URL|BASE_URL)$/.test(key)) return `${prefix}${projectConfig.oss_host}`;
|
|
2182
|
+
if (/INSFORGE.*ANON_KEY$/.test(key)) return `${prefix}${anonKey}`;
|
|
2183
|
+
return `${prefix}${_value}`;
|
|
2184
|
+
}
|
|
2185
|
+
);
|
|
2186
|
+
await fs2.writeFile(path2.join(cwd, ".env.local"), envContent);
|
|
2187
|
+
}
|
|
2188
|
+
s?.stop(`${templateName} template downloaded`);
|
|
2189
|
+
const migrationPath = path2.join(cwd, "migrations", "db_int.sql");
|
|
2190
|
+
const migrationExists = await fs2.stat(migrationPath).catch(() => null);
|
|
2191
|
+
if (migrationExists) {
|
|
2192
|
+
const dbSpinner = !json ? clack10.spinner() : null;
|
|
2193
|
+
dbSpinner?.start("Running database migrations...");
|
|
2194
|
+
try {
|
|
2195
|
+
const sql = await fs2.readFile(migrationPath, "utf-8");
|
|
2196
|
+
await ossFetch("/api/database/advance/rawsql/unrestricted", {
|
|
2197
|
+
method: "POST",
|
|
2198
|
+
body: JSON.stringify({ query: sql })
|
|
2199
|
+
});
|
|
2200
|
+
dbSpinner?.stop("Database migrations applied");
|
|
2201
|
+
} catch (err) {
|
|
2202
|
+
dbSpinner?.stop("Database migration failed");
|
|
2203
|
+
if (!json) {
|
|
2204
|
+
clack10.log.warn(`Migration failed: ${err.message}`);
|
|
2205
|
+
clack10.log.info('You can run the migration manually: insforge db query --unrestricted "$(cat migrations/db_int.sql)"');
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
} catch (err) {
|
|
2210
|
+
s?.stop(`${templateName} template download failed`);
|
|
2211
|
+
if (!json) {
|
|
2212
|
+
clack10.log.warn(`Failed to download ${templateName} template: ${err.message}`);
|
|
2213
|
+
clack10.log.info("You can manually clone from: https://github.com/InsForge/insforge-templates");
|
|
2214
|
+
}
|
|
2215
|
+
} finally {
|
|
2216
|
+
await fs2.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2147
2220
|
|
|
2148
2221
|
// src/commands/info.ts
|
|
2149
2222
|
function registerContextCommand(program2) {
|
|
@@ -2800,8 +2873,7 @@ function registerLogsCommand(program2) {
|
|
|
2800
2873
|
await requireAuth();
|
|
2801
2874
|
const resolved = SOURCE_LOOKUP.get(source.toLowerCase());
|
|
2802
2875
|
if (!resolved) {
|
|
2803
|
-
|
|
2804
|
-
process.exit(1);
|
|
2876
|
+
throw new CLIError(`Invalid log source "${source}". Valid sources: ${VALID_SOURCES.join(", ")}`);
|
|
2805
2877
|
}
|
|
2806
2878
|
const limit = parseInt(opts.limit, 10) || 20;
|
|
2807
2879
|
const res = await ossFetch(`/api/logs/${encodeURIComponent(resolved)}?limit=${limit}`);
|