@seliseblocks/cli-os 0.2.11 → 0.2.12
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/AI_USAGE_GUIDE.md +551 -560
- package/README.md +171 -173
- package/dist/commands/auth/refresh.js +21 -2
- package/dist/commands/mfa/generate.js +7 -4
- package/dist/commands/mfa/method-set.js +13 -4
- package/dist/commands/mfa/totp-enable.d.ts +3 -3
- package/dist/commands/mfa/totp-enable.js +4 -4
- package/dist/commands/mfa/verify.js +4 -2
- package/dist/commands/projects/create.js +110 -16
- package/dist/index.js +696 -703
- package/package.json +2 -2
- package/dist/commands/sdk/client.d.ts +0 -1
- package/dist/commands/sdk/client.js +0 -99
- package/dist/commands/skill/add.d.ts +0 -1
- package/dist/commands/skill/add.js +0 -19
- package/dist/commands/skill/list.d.ts +0 -1
- package/dist/commands/skill/list.js +0 -15
- package/dist/commands/skill/show.d.ts +0 -1
- package/dist/commands/skill/show.js +0 -15
- package/dist/lib/skills.d.ts +0 -17
- package/dist/lib/skills.js +0 -69
- package/dist/skills/blocks-data-gateway-configuration/SKILL.md +0 -204
- package/dist/skills/blocks-data-gateway-crud/SKILL.md +0 -223
- package/dist/skills/blocks-data-storage/SKILL.md +0 -253
- package/dist/skills/blocks-data-storage/flows/object-management.md +0 -124
- package/dist/skills/blocks-frontend-local-https/SKILL.md +0 -100
- package/dist/skills/blocks-iam-access-control/SKILL.md +0 -49
- package/dist/skills/blocks-iam-access-control/flows/feature-gating.md +0 -38
- package/dist/skills/blocks-iam-access-control/flows/manage-roles-permissions.md +0 -110
- package/dist/skills/blocks-iam-account/SKILL.md +0 -169
- package/dist/skills/blocks-iam-mfa/SKILL.md +0 -124
- package/dist/skills/blocks-iam-organizations/SKILL.md +0 -43
- package/dist/skills/blocks-iam-organizations/flows/admin-mutations.md +0 -89
- package/dist/skills/blocks-iam-organizations/flows/read-and-switch.md +0 -57
- package/dist/skills/blocks-iam-sso-oidc-configuration/SKILL.md +0 -105
- package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +0 -80
- package/dist/skills/blocks-iam-users/SKILL.md +0 -131
- package/dist/skills/blocks-localization-configuration/SKILL.md +0 -149
- package/dist/skills/blocks-localization-implementation/SKILL.md +0 -63
- package/dist/skills/blocks-mail/SKILL.md +0 -95
- package/dist/skills/blocks-notification/SKILL.md +0 -69
- package/dist/skills/blocks-notifier/SKILL.md +0 -107
- package/dist/skills/blocks-onboarding/SKILL.md +0 -77
- package/dist/skills/blocks-release-deployment/SKILL.md +0 -81
- package/dist/skills/blocks-secrets/SKILL.md +0 -81
- package/dist/skills/blocks-storage-configuration/SKILL.md +0 -93
- package/dist/skills/lint.mjs +0 -168
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seliseblocks/cli-os",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
4
4
|
"description": "CLI for SELISE Blocks project setup and configuration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
31
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
32
|
-
"build": "npm run clean && tsc -p tsconfig.json
|
|
32
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
33
33
|
"dev": "tsx src/index.ts",
|
|
34
34
|
"lint": "tsc -p tsconfig.json --noEmit",
|
|
35
35
|
"test": "npm run build && node --test test/*.test.mjs",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function sdkClient(argv: string[]): Promise<void>;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { blocksRequest } from "../../lib/api.js";
|
|
2
|
-
import { stringFlag } from "../../lib/args.js";
|
|
3
|
-
import { defaults } from "../../lib/config.js";
|
|
4
|
-
import { findProjectByTenantId } from "../../lib/project-info.js";
|
|
5
|
-
import { writeOutput } from "../../lib/output.js";
|
|
6
|
-
import { requestContext } from "../../lib/request-context.js";
|
|
7
|
-
import { parseCommand, selectedProject } from "../../lib/workspace.js";
|
|
8
|
-
// Read-only: "I want to use the Blocks SDK in my app -- show me the client."
|
|
9
|
-
// Resolves this project's createBlocksClient() config and prints it, same
|
|
10
|
-
// values 'new web' scaffolds with. Never writes a file and never mutates
|
|
11
|
-
// anything -- if you want the SDK wired into a new app, use 'new web'.
|
|
12
|
-
export async function sdkClient(argv) {
|
|
13
|
-
const { flags } = parseCommand(argv);
|
|
14
|
-
const tenantId = stringFlag(flags, "x-blocks-key") || (await selectedProject(flags));
|
|
15
|
-
const apiUrl = stringFlag(flags, "blocks-api-url", { defaultValue: defaults().apiUrl });
|
|
16
|
-
const oidcUrl = stringFlag(flags, "oidc-url", { defaultValue: defaults().oidcUrl });
|
|
17
|
-
let appDomain = stringFlag(flags, "app-domain");
|
|
18
|
-
let oidcClientId = stringFlag(flags, "client-id");
|
|
19
|
-
const notes = [];
|
|
20
|
-
if (!appDomain || !oidcClientId) {
|
|
21
|
-
const { project } = await findProjectByTenantId(tenantId, flags);
|
|
22
|
-
if (!appDomain) {
|
|
23
|
-
const domains = (project.applications ?? [])
|
|
24
|
-
.map((application) => application.domain)
|
|
25
|
-
.filter((domain) => Boolean(domain));
|
|
26
|
-
if (domains.length === 1) {
|
|
27
|
-
appDomain = domains[0];
|
|
28
|
-
}
|
|
29
|
-
else if (domains.length > 1) {
|
|
30
|
-
notes.push(`Multiple domains registered for this project (${domains.join(", ")}) -- pass --app-domain to pick one.`);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
notes.push("This project has no domains registered in Blocks -- pass --app-domain explicitly.");
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (!oidcClientId) {
|
|
37
|
-
const clients = await listOidcClients(tenantId, flags);
|
|
38
|
-
if (clients.length === 1) {
|
|
39
|
-
oidcClientId = clients[0].id;
|
|
40
|
-
}
|
|
41
|
-
else if (clients.length > 1) {
|
|
42
|
-
notes.push(`Multiple OIDC clients found (${clients.map((client) => `${client.label} [${client.id}]`).join(", ")}) -- pass --client-id to pick one.`);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
notes.push("No OIDC client registered for this project -- create one ('auth:oidc-clients:save') and pass --client-id.");
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (flags.json) {
|
|
50
|
-
writeOutput({ apiUrl, appDomain: appDomain || undefined, notes, oidcClientId: oidcClientId || undefined, oidcUrl, xBlocksKey: tenantId }, flags);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
console.log("import { createBlocksClient } from \"@seliseblocks/client\";");
|
|
54
|
-
console.log("");
|
|
55
|
-
console.log("export const blocksClient = createBlocksClient({");
|
|
56
|
-
console.log(` apiUrl: "${apiUrl}",`);
|
|
57
|
-
if (appDomain)
|
|
58
|
-
console.log(` appDomain: "${appDomain}",`);
|
|
59
|
-
console.log(" oidc: {");
|
|
60
|
-
console.log(` clientId: "${oidcClientId || "<register a public OIDC client, see auth:oidc-clients:save>"}",`);
|
|
61
|
-
console.log(" scope: \"openid profile\",");
|
|
62
|
-
console.log(` url: "${oidcUrl}"`);
|
|
63
|
-
console.log(" },");
|
|
64
|
-
console.log(` xBlocksKey: "${tenantId}"`);
|
|
65
|
-
console.log("});");
|
|
66
|
-
for (const note of notes)
|
|
67
|
-
console.log(`\n${note}`);
|
|
68
|
-
}
|
|
69
|
-
async function listOidcClients(tenantId, flags) {
|
|
70
|
-
const raw = await blocksRequest("/iam/v4/oidc-clients", {
|
|
71
|
-
impersonatedProjectAuth: true,
|
|
72
|
-
projectTenantId: tenantId,
|
|
73
|
-
...requestContext(flags)
|
|
74
|
-
});
|
|
75
|
-
const clients = [];
|
|
76
|
-
for (const item of normalizeList(raw)) {
|
|
77
|
-
if (typeof item !== "object" || item === null)
|
|
78
|
-
continue;
|
|
79
|
-
const record = item;
|
|
80
|
-
const id = record.itemId ?? record.clientId ?? record.id;
|
|
81
|
-
if (typeof id !== "string" || !id)
|
|
82
|
-
continue;
|
|
83
|
-
const label = typeof record.clientDisplayName === "string" && record.clientDisplayName ? record.clientDisplayName : id;
|
|
84
|
-
clients.push({ id, label });
|
|
85
|
-
}
|
|
86
|
-
return clients;
|
|
87
|
-
}
|
|
88
|
-
function normalizeList(raw) {
|
|
89
|
-
if (Array.isArray(raw))
|
|
90
|
-
return raw;
|
|
91
|
-
if (raw && typeof raw === "object") {
|
|
92
|
-
for (const key of ["data", "items", "results"]) {
|
|
93
|
-
const value = raw[key];
|
|
94
|
-
if (Array.isArray(value))
|
|
95
|
-
return value;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return [];
|
|
99
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function skillAdd(argv: string[]): Promise<void>;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { cp } from "node:fs/promises";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { stringFlag } from "../../lib/args.js";
|
|
4
|
-
import { readSkill } from "../../lib/skills.js";
|
|
5
|
-
import { parseCommand } from "../../lib/workspace.js";
|
|
6
|
-
export async function skillAdd(argv) {
|
|
7
|
-
const { args, flags } = parseCommand(argv);
|
|
8
|
-
const name = args[0];
|
|
9
|
-
if (!name)
|
|
10
|
-
throw new Error("Missing skill name. Run 'blocks skill list' to see available skills.");
|
|
11
|
-
const skill = await readSkill(name);
|
|
12
|
-
const sourceDir = dirname(skill.path);
|
|
13
|
-
const targetDir = stringFlag(flags, "dir", { defaultValue: "blocks-skills" });
|
|
14
|
-
const targetPath = join(process.cwd(), targetDir, name);
|
|
15
|
-
// Copy the whole skill directory, not just SKILL.md -- some skills also ship
|
|
16
|
-
// supporting files (e.g. flows/*.md) that SKILL.md links to.
|
|
17
|
-
await cp(sourceDir, targetPath, { recursive: true });
|
|
18
|
-
console.log(`Added ${targetPath}`);
|
|
19
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function skillList(argv: string[]): Promise<void>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { listSkills, SKILLS_REPO_URL } from "../../lib/skills.js";
|
|
2
|
-
import { writeOutput } from "../../lib/output.js";
|
|
3
|
-
import { parseCommand } from "../../lib/workspace.js";
|
|
4
|
-
export async function skillList(argv) {
|
|
5
|
-
const { flags } = parseCommand(argv);
|
|
6
|
-
const skills = await listSkills();
|
|
7
|
-
if (flags.json) {
|
|
8
|
-
writeOutput(skills, flags);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
for (const skill of skills) {
|
|
12
|
-
console.log(`${skill.name} ${skill.description}`);
|
|
13
|
-
}
|
|
14
|
-
console.log(`\nFull catalog (may be ahead of this bundled list): ${SKILLS_REPO_URL}`);
|
|
15
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function skillShow(argv: string[]): Promise<void>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { readSkill } from "../../lib/skills.js";
|
|
2
|
-
import { writeOutput } from "../../lib/output.js";
|
|
3
|
-
import { parseCommand } from "../../lib/workspace.js";
|
|
4
|
-
export async function skillShow(argv) {
|
|
5
|
-
const { args, flags } = parseCommand(argv);
|
|
6
|
-
const name = args[0];
|
|
7
|
-
if (!name)
|
|
8
|
-
throw new Error("Missing skill name. Run 'blocks skill list' to see available skills.");
|
|
9
|
-
const skill = await readSkill(name);
|
|
10
|
-
if (flags.json) {
|
|
11
|
-
writeOutput(skill, flags);
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
console.log(skill.content);
|
|
15
|
-
}
|
package/dist/lib/skills.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export type SkillSummary = {
|
|
2
|
-
description: string;
|
|
3
|
-
name: string;
|
|
4
|
-
path: string;
|
|
5
|
-
};
|
|
6
|
-
export type SkillDetail = SkillSummary & {
|
|
7
|
-
content: string;
|
|
8
|
-
};
|
|
9
|
-
export declare const SKILLS_REPO_URL = "https://github.com/SELISEdigitalplatforms/blocks-cli/tree/main/blocks-skills";
|
|
10
|
-
export declare function resolveSkillsDir(): string;
|
|
11
|
-
export declare function parseFrontmatter(raw: string): {
|
|
12
|
-
body: string;
|
|
13
|
-
description?: string;
|
|
14
|
-
name?: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function listSkills(): Promise<SkillSummary[]>;
|
|
17
|
-
export declare function readSkill(name: string): Promise<SkillDetail>;
|
package/dist/lib/skills.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
// Canonical public catalog -- the source of truth when the locally bundled
|
|
6
|
-
// skills are missing a name, or out of date relative to what's published.
|
|
7
|
-
export const SKILLS_REPO_URL = "https://github.com/SELISEdigitalplatforms/blocks-cli/tree/main/blocks-skills";
|
|
8
|
-
// Resolves where blocks-skills/*/SKILL.md content lives, in priority order:
|
|
9
|
-
// 1. Bundled into this package at build time (see scripts/copy-skills.mjs) --
|
|
10
|
-
// what a published npm install actually ships.
|
|
11
|
-
// 2. The monorepo root's blocks-skills/ folder -- covers 'npm run dev' (tsx,
|
|
12
|
-
// no build step) and running straight from a source checkout.
|
|
13
|
-
export function resolveSkillsDir() {
|
|
14
|
-
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
const candidates = [join(moduleDir, "..", "skills"), join(moduleDir, "..", "..", "..", "blocks-skills")];
|
|
16
|
-
for (const candidate of candidates) {
|
|
17
|
-
if (existsSync(candidate))
|
|
18
|
-
return candidate;
|
|
19
|
-
}
|
|
20
|
-
throw new Error("No blocks-skills content found. Expected a bundled 'skills' folder next to this package, or a 'blocks-skills' folder at the monorepo root.");
|
|
21
|
-
}
|
|
22
|
-
// Hand-rolled parser for this repo's flat, single-line SKILL.md frontmatter
|
|
23
|
-
// (`name: ...` / `description: "..."`) -- no YAML dependency exists in this
|
|
24
|
-
// package and none of these fields span multiple lines.
|
|
25
|
-
export function parseFrontmatter(raw) {
|
|
26
|
-
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
27
|
-
if (!match)
|
|
28
|
-
return { body: raw };
|
|
29
|
-
const [, frontmatter, body] = match;
|
|
30
|
-
const fields = {};
|
|
31
|
-
for (const line of frontmatter.split(/\r?\n/)) {
|
|
32
|
-
const separator = line.indexOf(":");
|
|
33
|
-
if (separator === -1)
|
|
34
|
-
continue;
|
|
35
|
-
const key = line.slice(0, separator).trim();
|
|
36
|
-
let value = line.slice(separator + 1).trim();
|
|
37
|
-
if (value.length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
|
|
38
|
-
value = value.slice(1, -1);
|
|
39
|
-
}
|
|
40
|
-
fields[key] = value;
|
|
41
|
-
}
|
|
42
|
-
return { body, description: fields.description, name: fields.name };
|
|
43
|
-
}
|
|
44
|
-
export async function listSkills() {
|
|
45
|
-
const dir = resolveSkillsDir();
|
|
46
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
47
|
-
const summaries = [];
|
|
48
|
-
for (const entry of entries) {
|
|
49
|
-
if (!entry.isDirectory())
|
|
50
|
-
continue;
|
|
51
|
-
const skillPath = join(dir, entry.name, "SKILL.md");
|
|
52
|
-
if (!existsSync(skillPath))
|
|
53
|
-
continue;
|
|
54
|
-
const raw = await readFile(skillPath, "utf8");
|
|
55
|
-
const { description, name } = parseFrontmatter(raw);
|
|
56
|
-
summaries.push({ description: description ?? "", name: name ?? entry.name, path: skillPath });
|
|
57
|
-
}
|
|
58
|
-
return summaries.sort((a, b) => a.name.localeCompare(b.name));
|
|
59
|
-
}
|
|
60
|
-
export async function readSkill(name) {
|
|
61
|
-
const skills = await listSkills();
|
|
62
|
-
const match = skills.find((skill) => skill.name === name);
|
|
63
|
-
if (!match) {
|
|
64
|
-
const available = skills.map((skill) => skill.name).join(", ") || "(none found)";
|
|
65
|
-
throw new Error(`Unknown skill '${name}'. Available skills: ${available}. If the skill you're looking for isn't listed (the bundled set may be out of date), check the full catalog at ${SKILLS_REPO_URL}.`);
|
|
66
|
-
}
|
|
67
|
-
const content = await readFile(match.path, "utf8");
|
|
68
|
-
return { ...match, content };
|
|
69
|
-
}
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-data-gateway-configuration
|
|
3
|
-
description: "Configure a SELISE Blocks project's data model via the blocks CLI — never raw fetch/curl against api.seliseblocks.com. Covers data-source config (data config get/create/update), schema authoring and push (data schema list/pull/push, plus granular get/fields/info commands), data-access policies (data rules pull/deploy/policy), field-level validation rules (data validation *), and reloading so changes go live (data reload, or the composed data sync). Use for defining, editing, securing, validating, or reloading a project's DATA MODEL — schema fields, access policies, and validation rules."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks Data — Gateway Configuration
|
|
7
|
-
|
|
8
|
-
The Data schema/rules model of a Blocks project is configured entirely through the `blocks` CLI now — there is no supported reason to hand-roll `fetch`/`curl` calls against `api.seliseblocks.com/data/v4` anymore. The CLI reads and writes local files under `blocks/data/` and talks to the Data service for you.
|
|
9
|
-
|
|
10
|
-
**Prerequisite:** `blocks init` has been run (creates `blocks/data/schemas/` and `blocks/data/rules.json`) and a project is selected (`blocks use <tenantId>`). If either is missing, or auth state is unknown, run the blocks-onboarding skill first — it covers `auth status` probing, login, and project selection in detail; this skill assumes that's already done.
|
|
11
|
-
|
|
12
|
-
## Check the data-source configuration first
|
|
13
|
-
|
|
14
|
-
Before touching schemas, confirm what database actually backs this project's Data Gateway:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
blocks data config get --json
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
By default every Blocks project runs on **Blocks-managed storage** — most of the time this is the only data-source command you'll ever need, just to confirm it. Only reach for the mutating commands below if the user explicitly wants to point the gateway at their own external database — this is a rare, deliberate action, not a routine step:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
blocks data config create --connection-string "<connection string>" --database-name "<name>" --dry-run --json
|
|
24
|
-
blocks data config create --connection-string "<connection string>" --database-name "<name>" --yes --json
|
|
25
|
-
|
|
26
|
-
blocks data config update --item-id <id> --connection-string "<new connection string>" --dry-run --json
|
|
27
|
-
blocks data config update --item-id <id> --connection-string "<new connection string>" --yes --json
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
`data config update` also takes `--database-name`, `--collection-name-pattern`, and `--collection-name-editable` (boolean) — use these to rename the target database or adjust how collection names are derived/whether they're editable, on an existing configuration (`--item-id` required either way).
|
|
31
|
-
|
|
32
|
-
Treat `--connection-string` as a secret: never print it back unredacted, and don't log it outside the command's own `--dry-run` preview (which redacts it).
|
|
33
|
-
|
|
34
|
-
## Probe first, ask second
|
|
35
|
-
|
|
36
|
-
Don't assume the local workspace matches the cloud project. Before editing anything, find out what's actually there:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
blocks data schema list --json # what schemas exist in the selected project (read-only)
|
|
40
|
-
blocks data schema pull --json # sync them into blocks/data/schemas/*.json locally
|
|
41
|
-
blocks data rules pull --json # sync data-access policies into blocks/data/rules.json
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Pulling before editing avoids clobbering schema changes someone else made in the portal or another session.
|
|
45
|
-
|
|
46
|
-
## Workflow: define or edit a schema
|
|
47
|
-
|
|
48
|
-
1. **Pull current state** (above), so local files reflect the project.
|
|
49
|
-
2. **Edit** the relevant JSON file(s) under `blocks/data/schemas/` — add/rename fields, change types, add a new schema file. This is plain file editing; there's no *file-oriented* CLI subcommand for individual field edits (`data schema push` always sends the whole schema), you edit the JSON directly. (`data schema fields` exists as a raw API alternative that adds/updates fields on an existing schema without touching the local file — see "More granular Schema commands" below — but for the local-file workflow described here, just edit the JSON.)
|
|
50
|
-
3. **Validate locally, no API call:**
|
|
51
|
-
```bash
|
|
52
|
-
blocks data validate --json
|
|
53
|
-
```
|
|
54
|
-
Fix anything it flags before going further — this catches malformed schema/rules JSON before it reaches the network.
|
|
55
|
-
4. **Dry-run the push** to see exactly what would change (create vs. update, which schemas):
|
|
56
|
-
```bash
|
|
57
|
-
blocks data schema push --dry-run --json
|
|
58
|
-
```
|
|
59
|
-
5. **Get user approval**, then push for real:
|
|
60
|
-
```bash
|
|
61
|
-
blocks data schema push --yes --json
|
|
62
|
-
```
|
|
63
|
-
This is mutating — it creates new schemas and updates existing ones in a single call. Never skip straight to `--yes`.
|
|
64
|
-
6. **Reload so it goes live.** Schema/rule edits are staged until reload succeeds — the runtime gateway doesn't see them before this:
|
|
65
|
-
```bash
|
|
66
|
-
blocks data reload --dry-run --json
|
|
67
|
-
blocks data reload --yes --json
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**Shortcut — recommended default:** steps 3–6 above (validate → schema push → rules deploy → reload) are exactly what `blocks data sync` automates behind a single confirmation:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
blocks data sync --dry-run --json
|
|
74
|
-
blocks data sync --yes --json
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Reach for `data sync` first unless the user specifically wants to inspect or run one step at a time — it's also the only way to *guarantee* the reload actually happens: nothing else in this CLI calls `data reload` automatically, so a bare `schema push` (or `rules deploy`) without a following `data reload` can leave changes staged but not live. Keep the manual step-by-step above for cases where you want to push schema without touching rules, or need to stop and inspect a dry-run at an individual step.
|
|
78
|
-
|
|
79
|
-
## Workflow: data-access policies / schema security
|
|
80
|
-
|
|
81
|
-
Same shape as schemas, in `blocks/data/rules.json`:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
blocks data rules pull --json # get current policies locally
|
|
85
|
-
# edit blocks/data/rules.json
|
|
86
|
-
blocks data validate --json # local-only check
|
|
87
|
-
blocks data rules deploy --dry-run --json # preview
|
|
88
|
-
blocks data rules deploy --yes --json # apply, after approval
|
|
89
|
-
blocks data reload --dry-run --json # then reload so it's live
|
|
90
|
-
blocks data reload --yes --json
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**Shortcut:** `blocks data sync --dry-run --json` then `--yes --json` runs validate → schema push → rules deploy → reload together in one confirmed step (see the schema workflow above for the full explanation) — use it instead of the manual deploy+reload above unless you need to run/inspect these steps individually.
|
|
94
|
-
|
|
95
|
-
`data rules deploy` applies schema security and data-access policies together — there's no finer-grained CLI split between "field access level" and "policy rule"; both live in `rules.json`.
|
|
96
|
-
|
|
97
|
-
For a single policy without touching the rest of `rules.json`, use the granular commands instead of a full pull/edit/deploy round-trip:
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
blocks data rules policy get <schemaName> --json # read-only, all policies for one schema
|
|
101
|
-
blocks data rules policy delete <itemId> --dry-run --json
|
|
102
|
-
blocks data rules policy delete <itemId> --yes --json
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
There's no single-policy `create`/`update` command — those go through `data rules deploy` (it POSTs new policies and PUTs existing ones from `rules.json`).
|
|
106
|
-
|
|
107
|
-
## Workflow: field-level validation rules
|
|
108
|
-
|
|
109
|
-
Data validations are a separate resource from schema field types — a schema field's `type` says *what kind* of value it holds, a validation rule says *what values are acceptable*. There's no file-oriented pull/push for these yet (no `blocks/data/validations.json`); work with them directly:
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
blocks data validation by-schema <schemaId> --json # everything for one schema
|
|
113
|
-
blocks data validation by-schema-field <schemaId> <fieldName> --json # one field's rule
|
|
114
|
-
blocks data validation list --schema-id <schemaId> --json # paginated browse
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
Create or update a rule (upsert: omit `--item-id` to create, pass it to update). The `validations` array itself has no scalar-flag equivalent — pass it via `--body`/`--file`:
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
blocks data validation save --schema-id <schemaId> --field-name email \
|
|
121
|
-
--body '{"validations":[{"type":1,"value":"^[^@]+@[^@]+\\.[^@]+$","errorMessage":"Enter a valid email","isActive":true}]}' \
|
|
122
|
-
--dry-run --json
|
|
123
|
-
blocks data validation save --schema-id <schemaId> --field-name email \
|
|
124
|
-
--body '{"validations":[{"type":1,"value":"^[^@]+@[^@]+\\.[^@]+$","errorMessage":"Enter a valid email","isActive":true}]}' \
|
|
125
|
-
--yes --json
|
|
126
|
-
|
|
127
|
-
blocks data validation delete <validationId> --dry-run --json
|
|
128
|
-
blocks data validation delete <validationId> --yes --json
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
The API doesn't publish named constants for the `type` enum in its schema — if the user needs a specific validation type and you're not sure of its numeric value, run `data validation by-schema-field` on a field with a known-working rule (e.g. one set up in the portal) to see the value in context, rather than guessing.
|
|
132
|
-
|
|
133
|
-
## More granular Schema commands
|
|
134
|
-
|
|
135
|
-
`data schema list/pull/push` cover the everyday file-based workflow above. For one-off lookups or advanced schema metadata, these go straight to the API without touching local files:
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
blocks data schema get <id> --json # single schema by id
|
|
139
|
-
blocks data schema get-by-name <schemaName> --json # full field detail by collection name
|
|
140
|
-
blocks data schema aggregation --json # schemas + access-level summary (Public/User/Custom x Read/Write/Edit/Delete)
|
|
141
|
-
blocks data schema change-logs --json # unadapted change logs; data reload clears these
|
|
142
|
-
blocks data schema delete <id> --dry-run --json # irreversible
|
|
143
|
-
blocks data schema delete <id> --yes --json
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
`data schema info list/save/update` and `data schema fields` are the two-step alternative to `data schema push` (metadata first, fields second) — prefer the file-based `push` workflow above for normal schema authoring; reach for these only if the user specifically wants to add fields to an existing schema without touching its full JSON file, or needs the raw `/schemas/info` metadata-only shape.
|
|
147
|
-
|
|
148
|
-
## `--dry-run` before `--yes` — always
|
|
149
|
-
|
|
150
|
-
Every mutating command here (`data config create/update`, `data schema push`, `data schema delete`, `data schema fields`, `data schema info save/update`, `data rules deploy`, `data rules policy delete`, `data validation save/delete`, `data reload`) supports `--dry-run`. Run it, show the user what it says it will do, and only add `--yes` after they approve. This is not optional caution — it's the standard pattern across every `blocks` mutation, not unique to this skill.
|
|
151
|
-
|
|
152
|
-
## What this skill does NOT cover (and why)
|
|
153
|
-
|
|
154
|
-
Two things the old, pre-CLI version of this skill used to handle no longer have any supported path — do not paper over the gap by inventing a command or improvising a raw API call:
|
|
155
|
-
|
|
156
|
-
- **Mock/sample data cleanup.** There is no `blocks data mock*` command, and the SDK's `data.utilities.mockData()` (in `@seliseblocks/client`) is **read-only** — it inventories mock data, it does not delete it. If a user asks to "wipe the demo data" or "clean up sample records," tell them plainly: this isn't exposed in the current CLI or SDK. Check whether the OS portal (`https://os.seliseblocks.com`) has a Data-section control for it; if not, there's no way to do this today short of deleting real records through generated GraphQL mutations one at a time, which is not the same thing and should not be presented as equivalent.
|
|
157
|
-
- **Schema export/import between projects** (e.g. cloning a dev project's data model into staging). No CLI command and no SDK method exist for this. If a user wants to copy a data model between projects, the honest answer is: not supported by current tooling. Check the OS portal for a manual option; otherwise the only fallback is manually recreating schemas in the target project's `blocks/data/schemas/` and pushing them — which is a manual reconstruction, not a real export/import, and should be described as such.
|
|
158
|
-
|
|
159
|
-
Don't guess at a raw API call to work around either gap — there is no supported path today, full stop.
|
|
160
|
-
|
|
161
|
-
## The one thing that goes through the SDK, not the CLI
|
|
162
|
-
|
|
163
|
-
**AI-generated regex for field validation** is real, but it lives only in `@seliseblocks/client`, not in `blocks`. There's no CLI command for it because it's a single request/response utility call better suited to being scripted inline in app code than wrapped as a terminal command:
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
import { createBlocksClient } from "@seliseblocks/client";
|
|
167
|
-
|
|
168
|
-
const blocks = createBlocksClient({
|
|
169
|
-
apiUrl: "https://api.seliseblocks.com",
|
|
170
|
-
xBlocksKey: "<project-tenant-id>",
|
|
171
|
-
accessToken: () => currentAccessToken
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const suggestion = await blocks.data.utilities.generateRegex({
|
|
175
|
-
description: "a valid US phone number, digits only, 10 characters"
|
|
176
|
-
});
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
If a user wants a regex suggestion for a field, write a small one-off script using the SDK like the above rather than trying to shoehorn it into a `blocks` invocation — the CLI genuinely has no equivalent, this isn't an oversight to work around. Once you have the pattern, put it into the relevant field's validation in `blocks/data/schemas/<Schema>.json` and continue with the normal push/reload workflow above.
|
|
180
|
-
|
|
181
|
-
## Gotchas
|
|
182
|
-
|
|
183
|
-
- **Reload or it didn't happen.** `data schema push` and `data rules deploy` stage changes; `data reload` is what makes them visible to the runtime gateway (and to any app querying it via `@seliseblocks/client`).
|
|
184
|
-
- **Pull before you edit** if you're not sure local files are current — someone may have changed the schema in the portal since your last pull.
|
|
185
|
-
- **`data validate` is local-only** — it does not confirm the push will succeed against the server, only that the JSON is well-formed. Still run `--dry-run` on the actual push/deploy/reload commands.
|
|
186
|
-
- **Don't invent mock-data-delete or schema-export commands.** They don't exist in the CLI or the SDK today — say so, check the portal, don't fake it with unrelated calls.
|
|
187
|
-
- **Never define platform-managed system fields** (`ItemId`, `CreatedDate`, `CreatedBy`, `LastUpdatedDate`, `LastUpdatedBy`, `Language`, `OrganizationId`, `Tags`) in your schema JSON — Blocks adds these to every entity schema automatically.
|
|
188
|
-
- **Check `data config get` before assuming Blocks-managed storage.** Most projects use it, but don't state it as fact without checking — and never create/update a data source configuration without explicit user intent, it repoints the project at a different database.
|
|
189
|
-
- **`data validation save` requires a `validations` array via `--body`/`--file`.** There's no flag for it — the command errors out with a clear message if it's missing, don't try to work around that by guessing a flag name.
|
|
190
|
-
|
|
191
|
-
## Example trigger prompts
|
|
192
|
-
|
|
193
|
-
- "Add an `email` field to my `Customer` schema and push it."
|
|
194
|
-
- "Pull the current schemas so I can see what's already defined."
|
|
195
|
-
- "Validate my local schema files before I push."
|
|
196
|
-
- "Set up a data-access policy so only admins can delete `Order` records."
|
|
197
|
-
- "Reload the data schema, I just pushed some field changes."
|
|
198
|
-
- "Suggest a regex for validating a postal code field."
|
|
199
|
-
- "What database is this project actually using?" → `data config get`.
|
|
200
|
-
- "Add a validation rule so the `phone` field only accepts digits." → `data validation save`.
|
|
201
|
-
- "What validation rules exist on the `Order` schema?" → `data validation by-schema`.
|
|
202
|
-
- "Delete this one data-access policy without touching the rest of my rules file." → `data rules policy delete`.
|
|
203
|
-
- "Can you wipe the demo/sample data from my project?" → explain this isn't supported by the CLI or SDK today; point to the portal.
|
|
204
|
-
- "Copy my dev project's schemas over to staging." → explain export/import isn't supported by current tooling; point to the portal or manual recreation.
|