@cellapp/cli 0.1.0 → 0.2.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/LICENSE +1 -1
- package/NOTICE +1 -1
- package/README.md +19 -6
- package/dist/packages/cli/src/client.js +1 -1
- package/dist/packages/cli/src/data.js +40 -0
- package/dist/packages/cli/src/data.js.map +1 -0
- package/dist/packages/cli/src/deploy.js +10 -5
- package/dist/packages/cli/src/deploy.js.map +1 -1
- package/dist/packages/cli/src/main.js +8 -4
- package/dist/packages/cli/src/main.js.map +1 -1
- package/dist/packages/shared/src/data.js +103 -0
- package/dist/packages/shared/src/data.js.map +1 -0
- package/package.json +26 -7
- package/skills/cellapp-deploy/SKILL.md +35 -10
- package/skills/cellapp-deploy/examples/notes/README.md +21 -0
- package/skills/cellapp-deploy/examples/notes/app.ts +115 -0
- package/skills/cellapp-deploy/examples/notes/cellapp.data.json +22 -0
- package/skills/cellapp-deploy/examples/notes/index.html +40 -0
- package/skills/cellapp-deploy/examples/notes/notes.ts +37 -0
- package/skills/cellapp-deploy/examples/notes/package-lock.json +622 -0
- package/skills/cellapp-deploy/examples/notes/package.json +16 -0
- package/skills/cellapp-deploy/examples/notes/tsconfig.json +13 -0
package/LICENSE
CHANGED
package/NOTICE
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
Cellapp CLI and Agent Skill were initially extracted from the private Cellapp
|
|
2
2
|
monorepo at commit 018274858c6435f01e1a8dc10c88b4f679b8c4c3. The public
|
|
3
3
|
repository starts with a new history to avoid publishing private material.
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Cellapp CLI and Agent Skill
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cellapp publishes static HTML applications from a local project. The CLI builds and uploads only the chosen static output directory. The Agent Skill guides an AI agent through the same process. A Cellapp control service URL is required; the Skill does not supply one.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
Requires Node.js 22.12 or later. Install the CLI from the published
|
|
7
|
+
Requires Node.js 22.12 or later. Install the CLI from the published Cellapp package when available:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
npm install -g @cellapp/cli
|
|
@@ -27,11 +27,24 @@ cellapp deploy --project /absolute/project --output dist --build 'npm run build'
|
|
|
27
27
|
cellapp apps --origin https://control.example
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Plain HTML directories do not need `--build`. Use `--spa` only if the site has client-side routes. The first deployment returns the app URL and
|
|
30
|
+
Plain HTML directories do not need `--build`. Use `--spa` only if the site has client-side routes. The first deployment returns the stable app-ID URL and an access key once; keep the key private. Add `--namespace <handle> --slug <alias>` on first deployment for a readable `@namespace/alias` reference; the owner console provides its share link. Handles and aliases are immutable in this release, while display names may repeat. Visitors first sign in with Cellapp. Restricted applications then require owner approval or access-key redemption; public applications admit any signed-in user. Rotating a key stops new redemptions and preserves existing user grants. `cellapp.json` stores the app association and pending deployment metadata without secrets. Credentials are stored in `~/.config/cellapp/` with private file permissions.
|
|
31
|
+
|
|
32
|
+
## Application data
|
|
33
|
+
|
|
34
|
+
Cellapp hosts each application's managed PostgreSQL tables separately from platform data. A linked project can define a non-secret `cellapp.data.json` manifest with tables and `none`, `all-admitted-users`, or `own-rows` policies. Start with [the runnable notes demo](skills/cellapp-deploy/examples/notes/README.md), which includes a buildable frontend, manifest, and CRUD page:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
cellapp data status --project /absolute/project
|
|
38
|
+
cellapp data plan --project /absolute/project
|
|
39
|
+
cellapp data apply --project /absolute/project
|
|
40
|
+
cellapp data verify --project /absolute/project
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Table changes are versioned and applied separately from static deployments. Dropping a table or column requires `allowDestructive: true` in the manifest and `--allow-destructive` after reviewing the plan. The frontend can use `@supabase/supabase-js@2.117.3` with its own origin and the non-secret `cellapp-public` identifier for table select, insert, update, delete, equality filter, order, page range, and write-return. `/_cellapp/me` returns a stable application-scoped user ID. Supabase Auth, Realtime, Storage, RPC, custom servers, and direct PostgreSQL access are not supported. The publishable identifier never authorizes access; Cellapp checks login, admission, table grants, and row policies on every data request.
|
|
31
44
|
|
|
32
45
|
An existing `ohmyapp.json` and matching `~/.config/ohmyapp/` credential are copied safely on first use. The old files remain for recovery. `OHMYAPP_ORIGIN` and the `ohmyapp` command alias are supported during the transition; use `CELLAPP_ORIGIN` and `cellapp` for new setups.
|
|
33
46
|
|
|
34
|
-
The service hosts static content only. Frontend code and bundled values are readable by authorized visitors; never include private API credentials. Browser local data is not synchronized between devices.
|
|
47
|
+
The service hosts static content only. Frontend code and bundled values are readable by authorized visitors; never include private API credentials. Browser local-only data is not synchronized between devices; managed table data is.
|
|
35
48
|
|
|
36
49
|
## Development
|
|
37
50
|
|
|
@@ -45,4 +58,4 @@ npm run check:boundary
|
|
|
45
58
|
npm pack --dry-run --json
|
|
46
59
|
```
|
|
47
60
|
|
|
48
|
-
The [public HTTP contract](contracts/http-
|
|
61
|
+
The [public HTTP v2 contract](contracts/http-v2.json) describes the CLI, application access, and data boundary. [v1](contracts/http-v1.json) remains for older static-deploy clients. The CLI and Skill are MIT licensed; see [LICENSE](LICENSE). Contributions follow [CONTRIBUTING.md](CONTRIBUTING.md), and security reports follow [SECURITY.md](SECURITY.md).
|
|
@@ -73,7 +73,7 @@ export class Client {
|
|
|
73
73
|
}
|
|
74
74
|
const migrated = await readJSON(this.credentialFile);
|
|
75
75
|
if (migrated?.token !== legacy.token)
|
|
76
|
-
throw new Error('
|
|
76
|
+
throw new Error('Cellapp credential conflicts with legacy credential; resolve the files manually');
|
|
77
77
|
this.token = migrated.token;
|
|
78
78
|
}
|
|
79
79
|
async request(path, method = 'GET', body, binary = false) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { join, resolve } from 'node:path';
|
|
2
|
+
import { readJSON } from './client.js';
|
|
3
|
+
import { parseDataManifest } from '../../shared/src/data.js';
|
|
4
|
+
function plan(value) {
|
|
5
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
6
|
+
throw new Error('Unexpected data plan response');
|
|
7
|
+
const data = value;
|
|
8
|
+
if (!Number.isSafeInteger(data.version) || typeof data.digest !== 'string' || !/^[a-f0-9]{64}$/.test(data.digest) ||
|
|
9
|
+
!Array.isArray(data.operations) || data.operations.some(item => typeof item !== 'string') ||
|
|
10
|
+
typeof data.requiresDestructive !== 'boolean' || typeof data.alreadyApplied !== 'boolean')
|
|
11
|
+
throw new Error('Unexpected data plan response');
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
export async function runData(client, action, projectPath, project, explicitAppID, manifestPath, allowDestructive = false) {
|
|
15
|
+
if (!['plan', 'apply', 'status', 'verify'].includes(action ?? ''))
|
|
16
|
+
throw new Error('Use data plan, apply, status, or verify');
|
|
17
|
+
const operation = action;
|
|
18
|
+
const appID = explicitAppID ?? project?.appId;
|
|
19
|
+
if (!appID || !/^[a-f0-9]{32}$/.test(appID))
|
|
20
|
+
throw new Error('Link a project or provide a valid app ID');
|
|
21
|
+
const path = `/apps/${appID}/data`;
|
|
22
|
+
if (operation === 'status')
|
|
23
|
+
return { appId: appID, status: await client.request(path) };
|
|
24
|
+
if (operation === 'verify')
|
|
25
|
+
return { appId: appID, verification: await client.request(`${path}/verify`, 'POST') };
|
|
26
|
+
const input = await readJSON(resolve(projectPath, manifestPath ?? 'cellapp.data.json'));
|
|
27
|
+
if (input === undefined)
|
|
28
|
+
throw new Error(`Data manifest not found: ${join(projectPath, manifestPath ?? 'cellapp.data.json')}`);
|
|
29
|
+
const manifest = parseDataManifest(input);
|
|
30
|
+
const preview = plan(await client.request(`${path}/plan`, 'POST', manifest));
|
|
31
|
+
if (operation === 'plan')
|
|
32
|
+
return { appId: appID, plan: preview };
|
|
33
|
+
if (preview.requiresDestructive && !allowDestructive)
|
|
34
|
+
throw new Error('Destructive table changes require --allow-destructive after reviewing data plan');
|
|
35
|
+
const applied = plan(await client.request(`${path}/apply`, 'POST', manifest));
|
|
36
|
+
if (applied.digest !== preview.digest)
|
|
37
|
+
throw new Error('Applied data digest differs from the reviewed plan; run data status');
|
|
38
|
+
return { appId: appID, tables: applied, verification: await client.request(`${path}/verify`, 'POST') };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../../../packages/cli/src/data.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,6 +44,9 @@ export async function deploy(client, directory, options, notify) {
|
|
|
44
44
|
let project = await readProject(projectPath);
|
|
45
45
|
if (project && project.origin !== client.origin)
|
|
46
46
|
throw new Error('Project belongs to another control origin');
|
|
47
|
+
if (project?.appId && (options.namespace !== undefined || options.slug !== undefined)) {
|
|
48
|
+
throw new Error('Namespace and app alias are set only when creating an application');
|
|
49
|
+
}
|
|
47
50
|
const output = options.output ?? project?.output;
|
|
48
51
|
ensure(output, 400, 'output_required', 'Specify --output with the static build directory');
|
|
49
52
|
const outPath = resolve(projectPath, output);
|
|
@@ -57,13 +60,14 @@ export async function deploy(client, directory, options, notify) {
|
|
|
57
60
|
ensure(!isAbsolute(actualRelative) && actualRelative !== '..' && !actualRelative.startsWith('../'), 400, 'invalid_output', 'Output resolves outside the project');
|
|
58
61
|
const limits = await client.request('/limits');
|
|
59
62
|
const files = await collect(outPath, limits);
|
|
60
|
-
project = { ...project, origin: client.origin, name: options.name ?? project?.name ?? 'My app', output, build: command, spa: options.spa ?? project?.spa ?? false, createRequestId: project?.createRequestId ?? requestID() };
|
|
63
|
+
project = { ...project, origin: client.origin, name: options.name ?? project?.name ?? 'My app', namespace: options.namespace ?? project?.namespace, slug: options.slug ?? project?.slug, output, build: command, spa: options.spa ?? project?.spa ?? false, createRequestId: project?.createRequestId ?? requestID() };
|
|
61
64
|
let initialKey;
|
|
62
65
|
if (!project.appId) {
|
|
63
66
|
// The secret stays in memory; after a process crash the owner can list apps and
|
|
64
|
-
// explicitly link/
|
|
67
|
+
// explicitly link/rotate the key. Never persist access keys in project metadata.
|
|
65
68
|
initialKey = randomKey();
|
|
66
|
-
const body = { name: project.name, key: initialKey, requestId: project.createRequestId
|
|
69
|
+
const body = { name: project.name, key: initialKey, requestId: project.createRequestId,
|
|
70
|
+
...(project.namespace ? { namespace: project.namespace } : {}), ...(project.slug ? { slug: project.slug } : {}) };
|
|
67
71
|
const create = () => client.request('/apps', 'POST', body);
|
|
68
72
|
let app;
|
|
69
73
|
try {
|
|
@@ -102,7 +106,8 @@ export async function deploy(client, directory, options, notify) {
|
|
|
102
106
|
const result = await client.request(`${base}/${d.id}/publish`, 'POST', {});
|
|
103
107
|
delete project.pending;
|
|
104
108
|
await saveJSON(configPath, project);
|
|
105
|
-
notify('
|
|
106
|
-
return { ...result,
|
|
109
|
+
notify('静态应用已发布。');
|
|
110
|
+
return { ...result, namespace: app.namespace, slug: app.slug, aliasUrl: app.aliasUrl,
|
|
111
|
+
...(initialKey ? { accessKey: initialKey } : { keyUnchanged: true }) };
|
|
107
112
|
}
|
|
108
113
|
//# sourceMappingURL=deploy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../../packages/cli/src/deploy.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../../packages/cli/src/deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,16 +6,18 @@ import { deploy } from './deploy.js';
|
|
|
6
6
|
import { AppError } from '../../shared/src/errors.js';
|
|
7
7
|
import { readProject } from './project.js';
|
|
8
8
|
import { selectOrigin } from './origin.js';
|
|
9
|
+
import { runData } from './data.js';
|
|
9
10
|
const { values, positionals } = parseArgs({ allowPositionals: true, options: {
|
|
10
11
|
origin: { type: 'string' }, project: { type: 'string', default: '.' }, output: { type: 'string' },
|
|
11
|
-
build: { type: 'string' }, name: { type: 'string' }, spa: { type: 'boolean' }, help: { type: 'boolean' },
|
|
12
|
+
build: { type: 'string' }, name: { type: 'string' }, namespace: { type: 'string' }, slug: { type: 'string' }, spa: { type: 'boolean' }, help: { type: 'boolean' },
|
|
12
13
|
'config-dir': { type: 'string' },
|
|
14
|
+
manifest: { type: 'string' }, 'allow-destructive': { type: 'boolean' },
|
|
13
15
|
} });
|
|
14
|
-
const [command, appId] = positionals;
|
|
16
|
+
const [command, appId, dataAppId] = positionals;
|
|
15
17
|
const notify = (s) => process.stderr.write(s + '\n');
|
|
16
18
|
try {
|
|
17
19
|
if (values.help || !command) {
|
|
18
|
-
process.stdout.write('cellapp <login|logout|deploy|apps|link|reset-key|delete> [app-id] --origin https://control.example\nDeploy: --project . --output dist [--build "npm run build"] [--spa]\n');
|
|
20
|
+
process.stdout.write('cellapp <login|logout|deploy|apps|link|reset-key|delete|data> [app-id] --origin https://control.example\nDeploy: --project . --output dist [--build "npm run build"] [--namespace handle] [--slug alias] [--spa]\nData: data <plan|apply|status|verify> [app-id] --project . [--manifest cellapp.data.json] [--allow-destructive]\n');
|
|
19
21
|
}
|
|
20
22
|
else {
|
|
21
23
|
const projectPath = resolve(values.project);
|
|
@@ -43,13 +45,15 @@ try {
|
|
|
43
45
|
result = await deploy(client, projectPath, values, notify);
|
|
44
46
|
else if (command === 'apps')
|
|
45
47
|
result = await client.request('/apps');
|
|
48
|
+
else if (command === 'data')
|
|
49
|
+
result = await runData(client, appId, projectPath, project, dataAppId, values.manifest, values['allow-destructive']);
|
|
46
50
|
else {
|
|
47
51
|
if (!appId || !/^[a-f0-9]{32}$/.test(appId))
|
|
48
52
|
throw new Error('A valid app ID is required');
|
|
49
53
|
if (command === 'reset-key') {
|
|
50
54
|
const key = randomKey();
|
|
51
55
|
await client.request(`/apps/${appId}/key`, 'POST', { key });
|
|
52
|
-
result = {
|
|
56
|
+
result = { accessKey: key };
|
|
53
57
|
}
|
|
54
58
|
else if (command === 'delete')
|
|
55
59
|
result = await client.request(`/apps/${appId}`, 'DELETE');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../packages/cli/src/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,MAAM,EAAgB,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../packages/cli/src/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
const identifier = /^[a-z][a-z0-9_]{0,62}$/;
|
|
3
|
+
const columnTypes = new Set(['text', 'uuid', 'bigint', 'boolean', 'timestamptz', 'jsonb']);
|
|
4
|
+
const modes = new Set(['none', 'all-admitted-users', 'own-rows']);
|
|
5
|
+
const systemColumns = new Set(['ctid', 'tableoid', 'xmin', 'cmin', 'xmax', 'cmax']);
|
|
6
|
+
function object(value, keys) {
|
|
7
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
8
|
+
throw new Error('Expected an object in data manifest');
|
|
9
|
+
const result = value;
|
|
10
|
+
if (Object.keys(result).some(key => !keys.includes(key)))
|
|
11
|
+
throw new Error('Unsupported field in data manifest');
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
function name(value) {
|
|
15
|
+
if (typeof value !== 'string' || !identifier.test(value))
|
|
16
|
+
throw new Error('Invalid data identifier');
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function names(value, max) {
|
|
20
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > max)
|
|
21
|
+
throw new Error('Invalid data column list');
|
|
22
|
+
const result = value.map(name);
|
|
23
|
+
if (new Set(result).size !== result.length)
|
|
24
|
+
throw new Error('Duplicate data column');
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
function mode(value) {
|
|
28
|
+
if (value === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (typeof value !== 'string' || !modes.has(value))
|
|
31
|
+
throw new Error('Invalid data policy');
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
export function parseDataManifest(input) {
|
|
35
|
+
const root = object(input, ['version', 'allowDestructive', 'tables']);
|
|
36
|
+
if (!Number.isSafeInteger(root.version) || root.version < 1 || root.version > 1_000_000)
|
|
37
|
+
throw new Error('Invalid data manifest version');
|
|
38
|
+
if (root.allowDestructive !== undefined && typeof root.allowDestructive !== 'boolean')
|
|
39
|
+
throw new Error('Invalid destructive-change flag');
|
|
40
|
+
if (!Array.isArray(root.tables) || root.tables.length > 20)
|
|
41
|
+
throw new Error('Invalid data table list');
|
|
42
|
+
const tables = root.tables.map(value => {
|
|
43
|
+
const table = object(value, ['name', 'columns', 'primaryKey', 'indexes', 'policies']);
|
|
44
|
+
const tableName = name(table.name);
|
|
45
|
+
if (tableName === 'rpc')
|
|
46
|
+
throw new Error('Reserved data table name: rpc');
|
|
47
|
+
if (!Array.isArray(table.columns) || table.columns.length < 1 || table.columns.length > 30)
|
|
48
|
+
throw new Error('Invalid data columns');
|
|
49
|
+
const columns = table.columns.map(value => {
|
|
50
|
+
const column = object(value, ['name', 'type', 'nullable']);
|
|
51
|
+
if (typeof column.type !== 'string' || !columnTypes.has(column.type) || (column.nullable !== undefined && typeof column.nullable !== 'boolean'))
|
|
52
|
+
throw new Error('Unsupported data column');
|
|
53
|
+
const columnName = name(column.name);
|
|
54
|
+
if (systemColumns.has(columnName))
|
|
55
|
+
throw new Error(`Reserved PostgreSQL system column: ${columnName}`);
|
|
56
|
+
return { name: columnName, type: column.type, ...(column.nullable === undefined ? {} : { nullable: column.nullable }) };
|
|
57
|
+
});
|
|
58
|
+
const columnNames = new Set(columns.map(column => column.name));
|
|
59
|
+
if (columnNames.size !== columns.length)
|
|
60
|
+
throw new Error('Duplicate data column');
|
|
61
|
+
const primaryKey = names(table.primaryKey, 3);
|
|
62
|
+
if (primaryKey.some(key => !columnNames.has(key) || columns.find(column => column.name === key)?.nullable))
|
|
63
|
+
throw new Error('Invalid primary key');
|
|
64
|
+
if (table.indexes !== undefined && (!Array.isArray(table.indexes) || table.indexes.length > 10))
|
|
65
|
+
throw new Error('Invalid data indexes');
|
|
66
|
+
const indexes = table.indexes?.map(value => {
|
|
67
|
+
const index = object(value, ['columns', 'unique']);
|
|
68
|
+
const indexColumns = names(index.columns, 3);
|
|
69
|
+
if (indexColumns.some(column => !columnNames.has(column)) || (index.unique !== undefined && typeof index.unique !== 'boolean'))
|
|
70
|
+
throw new Error('Invalid data index');
|
|
71
|
+
return { columns: indexColumns, ...(index.unique === undefined ? {} : { unique: index.unique }) };
|
|
72
|
+
});
|
|
73
|
+
const policies = object(table.policies, ['select', 'insert', 'update', 'delete', 'ownerColumn']);
|
|
74
|
+
const parsedPolicies = { select: mode(policies.select), insert: mode(policies.insert), update: mode(policies.update), delete: mode(policies.delete) };
|
|
75
|
+
const ownRows = Object.values(parsedPolicies).includes('own-rows');
|
|
76
|
+
if (ownRows) {
|
|
77
|
+
if (typeof policies.ownerColumn !== 'string')
|
|
78
|
+
throw new Error('own-rows requires an owner column');
|
|
79
|
+
const ownerColumn = name(policies.ownerColumn);
|
|
80
|
+
const column = columns.find(column => column.name === ownerColumn);
|
|
81
|
+
if (!column || column.type !== 'text' || column.nullable)
|
|
82
|
+
throw new Error('own-rows requires a non-null text owner column');
|
|
83
|
+
parsedPolicies.ownerColumn = ownerColumn;
|
|
84
|
+
}
|
|
85
|
+
else if (policies.ownerColumn !== undefined)
|
|
86
|
+
throw new Error('ownerColumn requires own-rows');
|
|
87
|
+
return { name: tableName, columns, primaryKey, ...(indexes === undefined ? {} : { indexes }), policies: parsedPolicies };
|
|
88
|
+
});
|
|
89
|
+
if (new Set(tables.map(table => table.name)).size !== tables.length)
|
|
90
|
+
throw new Error('Duplicate data table');
|
|
91
|
+
const relations = new Set(tables.map(table => table.name));
|
|
92
|
+
for (const table of tables) {
|
|
93
|
+
for (const position of table.indexes?.keys() ?? []) {
|
|
94
|
+
const digest = createHash('sha256').update(`${table.name}:${position}`).digest('hex').slice(0, 8);
|
|
95
|
+
const indexName = `i_${table.name.slice(0, 40)}_${digest}`;
|
|
96
|
+
if (relations.has(indexName))
|
|
97
|
+
throw new Error(`Generated index name conflicts with table or index: ${indexName}`);
|
|
98
|
+
relations.add(indexName);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { version: root.version, ...(root.allowDestructive === undefined ? {} : { allowDestructive: root.allowDestructive }), tables };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../../../packages/shared/src/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQzC,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAC5C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3F,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,oBAAoB,EAAE,UAAU,CAAC,CAAC,CAAC;AAClE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AACpF,SAAS,MAAM,CAAC,KAAc,EAAE,IAAc;IAC5C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACxH,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAChH,OAAO,MAAM,CAAC;AAChB,CAAC;AACD,SAAS,IAAI,CAAC,KAAc;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACrG,OAAO,KAAK,CAAC;AACf,CAAC;AACD,SAAS,KAAK,CAAC,KAAc,EAAE,GAAW;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACjH,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACrF,OAAO,MAAM,CAAC;AAChB,CAAC;AACD,SAAS,IAAI,CAAC,KAAc;IAC1B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC3F,OAAO,KAAiB,CAAC;AAC3B,CAAC;AACD,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAK,IAAI,CAAC,OAAkB,GAAG,CAAC,IAAK,IAAI,CAAC,OAAkB,GAAG,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAClK,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,gBAAgB,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC1I,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACvG,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,SAAS,KAAK,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC1E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACpI,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;YAC3D,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC5L,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,UAAU,EAAE,CAAC,CAAC;YACvG,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,IAA0B,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAC,CAAC,EAAC,CAAC;QAC5I,CAAC,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAChE,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAClF,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC9C,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,QAAQ,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACnJ,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACzI,MAAM,OAAO,GAAI,KAAK,CAAC,OAAiC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE;YACpE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;YACnD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC7C,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACtK,OAAO,EAAC,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAC,CAAC,EAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;QACjG,MAAM,cAAc,GAAiB,EAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAC,CAAC;QAClK,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACnE,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACnG,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;YACnE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;YAC5H,cAAc,CAAC,WAAW,GAAG,WAAW,CAAC;QAC3C,CAAC;aAAM,IAAI,QAAQ,CAAC,WAAW,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAChG,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,OAAO,EAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAC,CAAC;IACvH,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC7G,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YACnD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAClG,MAAM,SAAS,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC;YAC3D,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,SAAS,EAAE,CAAC,CAAC;YAClH,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,EAAC,OAAO,EAAE,IAAI,CAAC,OAAiB,EAAE,GAAG,CAAC,IAAI,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,gBAAgB,EAAE,IAAI,CAAC,gBAA2B,EAAC,CAAC,EAAE,MAAM,EAAC,CAAC;AACzJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cellapp/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Cellapp static application deployment CLI and Agent Skill",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"publishConfig": {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public",
|
|
9
|
+
"registry": "https://registry.npmjs.org/"
|
|
10
|
+
},
|
|
11
|
+
"workspaces": [
|
|
12
|
+
"packages/cli",
|
|
13
|
+
"packages/shared"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22.12.0"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"cellapp": "dist/packages/cli/src/main.js",
|
|
20
|
+
"ohmyapp": "dist/packages/cli/src/main.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/packages",
|
|
24
|
+
"skills/cellapp-deploy",
|
|
25
|
+
"!skills/cellapp-deploy/examples/**/node_modules",
|
|
26
|
+
"!skills/cellapp-deploy/examples/**/dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"NOTICE"
|
|
30
|
+
],
|
|
12
31
|
"scripts": {
|
|
13
32
|
"build": "tsc -p tsconfig.json",
|
|
14
33
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cellapp-deploy
|
|
3
|
-
description:
|
|
3
|
+
description: Build and publish a static Cellapp frontend, manage its PostgreSQL tables and row policies, and connect supported supabase-js CRUD without an application backend.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Develop and deploy a Cellapp application
|
|
7
7
|
|
|
8
|
-
Use the installed `cellapp` CLI. Installing this Skill does not install the CLI; if it is unavailable,
|
|
8
|
+
Use the installed `cellapp` CLI. Installing this Skill does not install the CLI; if it is unavailable, direct the user to the public repository README. Use the configured `CELLAPP_ORIGIN`, existing `cellapp.json`, or an origin supplied by the user. Preserve `ohmyapp.json` and `OHMYAPP_ORIGIN` migration behavior. Never invent an origin or store a credential in the project.
|
|
9
9
|
|
|
10
|
-
Inspect
|
|
10
|
+
## Inspect
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Read `cellapp.json`, the existing build command, static output directory, and `cellapp.data.json` if present. Reuse the application association on updates. For plain HTML omit the build command. Ask only for an ambiguous output or build setting. Cellapp hosts static frontend code; do not deploy SSR, a custom server, private service key, direct PostgreSQL credential, or arbitrary SQL. Bundled frontend values are readable by admitted visitors.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## Choose an application reference
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
The display name may repeat. Every owner has one public namespace, and aliases are unique inside it. On the first deployment a new owner may choose `--namespace <handle>`; each new app may choose `--slug <alias>`. Both use lowercase ASCII letters, digits and hyphens and start with a letter. Without choices, Cellapp assigns a random privacy-preserving namespace and an alias derived from the display name, adding a suffix on collision. Existing owners must reuse their established namespace. These identifiers are immutable in this release; choose them before the first publish. The CLI's returned app-ID URL remains the stable app host. The owner console shows the share link for `@namespace/alias`, which redirects to that host. Never treat a namespace, alias or display name as an authorization identity; app access and tables remain bound to the app ID.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
## Plan, apply, and verify tables
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
The versioned, non-secret [`cellapp.data.json`](examples/notes/cellapp.data.json) manifest defines tables, columns, primary keys, indexes and operation policies. Types: `text`, `uuid`, `bigint`, `boolean`, `timestamptz`, `jsonb`. Policy modes: `none` (default), `all-admitted-users`, `own-rows`. The `own-rows` mode needs a non-null text `ownerColumn`; reads and writes are checked against the signed application user ID. Every table needs a primary key. No SQL, function, trigger, database password or provider identity belongs in the manifest. Table names are scoped to the app: an app may define `users` without touching platform users or another app's `users`. This is ordinary app data, not the platform identity source. Keep names unique within one app; `rpc` is reserved for the unsupported PostgREST route, PostgreSQL system column names are unavailable, and generated index names must not collide with table names. Check these rules with `data plan` before applying.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
A new project needs its first static deployment to create the application association in `cellapp.json`. Build and deploy the frontend once, then use the linked app and configured origin to apply the data manifest. Do not report the table-dependent page as ready until verification succeeds:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
cellapp data status --project <project>
|
|
26
|
+
cellapp data plan --project <project>
|
|
27
|
+
cellapp data apply --project <project>
|
|
28
|
+
cellapp data verify --project <project>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The first manifest version is `1`; increase by exactly one. Inspect the plan and data version separately from the static release. Identical retries are safe; changed content at an applied version conflicts. For a table or column drop, set `allowDestructive: true` in the manifest and pass `--allow-destructive` to `data apply` after reviewing the plan and backup implications. After a timeout, run status and verify, then retry the same manifest if needed. Do not create a new version for a retry. Adding a non-null column to a populated table fails and rolls back; use a nullable column in this initial subset.
|
|
32
|
+
|
|
33
|
+
New tables and operations deny frontend access until granted. Apply with an owner credential. Verify an allowed operation and a denied cross-user or ungranted operation before handing out the app URL. Distinguish database-only tests from real browser and PostgREST acceptance. The application database is separate from control data and other apps; application code gets no database password.
|
|
34
|
+
|
|
35
|
+
## Connect the static frontend
|
|
36
|
+
|
|
37
|
+
Use `@supabase/supabase-js@2.117.3` for the declared table subset. Initialize `createClient(window.location.origin, 'cellapp-public', {auth: {autoRefreshToken: false, persistSession: false, detectSessionInUrl: false}})`. The publishable string is non-secret and grants nothing. Cellapp checks the logged-in user's host-only app session and admission on each request. Fetch `/_cellapp/me` with same-origin credentials for the stable app-scoped ID; never expose or derive a global Cellapp ID. See the [runnable notes demo](examples/notes/README.md), which includes its build, manifest, and browser CRUD page.
|
|
38
|
+
|
|
39
|
+
Use only `.from(table).select(columns)`, `.insert(values)`, `.update(values)`, `.delete()`, `.eq()`, `.order()`, `.range()` and `.select()` after a write for returned rows. Handle `{data,error}` and 401/403 states visibly. Supabase Auth, Realtime, Storage, RPC, Edge Functions, joins, arbitrary filters, direct database access, and custom application servers are outside this release. The gateway ignores client authorization/profile headers. A public app admits any signed-in Cellapp user, while tables still require policies. A restricted app requires owner approval or access-key redemption after login.
|
|
40
|
+
|
|
41
|
+
## Publish and report
|
|
42
|
+
|
|
43
|
+
Run `cellapp deploy --project <project> --output <output-directory> --build <existing-build-command>` (optionally adding `--namespace` and `--slug` on the first deployment), omitting `--build` for plain HTML. Add `--spa` only for client-side routes. The CLI performs device authorization when needed; provide the verification link and code, keep the command running, and never request account passwords. Report publication only after `status: published`. Report data version/verification and static release separately, then provide the app URL.
|
|
44
|
+
|
|
45
|
+
The first deployment returns an access key once. Give it only to the requesting owner; never put it in a URL, repository, issue or project state. Old keys can be redeemed only after platform login. `cellapp reset-key <app-id>` rotates future redemption; existing user grants remain active. Revoke an individual grant in the owner console. Use reset or delete only when requested. A lost initial key can be explicitly rotated.
|
|
46
|
+
|
|
47
|
+
On transient upload/network failure, retry the same deploy command once: pending project metadata reuses the operation. Stop after another failure and report the error. A release version conflict needs review. For data errors use `data status` and `data verify`; do not claim a table-dependent frontend is ready while its data API is unready. Browser local-only state does not synchronize between devices; managed table data does.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Cellapp 笔记 Demo
|
|
2
|
+
|
|
3
|
+
这是一个可以直接发布的静态前端。Cellapp 管理登录身份、应用数据库和访问控制;浏览器用 `supabase-js` 读写 `notes` 表。每位已获准访问应用的用户只能看到自己的笔记。无需自建服务端、Supabase 项目或数据库密码。
|
|
4
|
+
|
|
5
|
+
## 运行
|
|
6
|
+
|
|
7
|
+
需要 Node.js 22.12+、已安装并登录的 `cellapp` CLI,以及一个可用的 Cellapp 环境。先设置 `CELLAPP_ORIGIN` 为控制台 HTTPS 地址。
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
cd <本示例目录>
|
|
11
|
+
npm ci
|
|
12
|
+
npm run build
|
|
13
|
+
cellapp deploy --project . --output dist --name "Notes demo" --slug notes-demo
|
|
14
|
+
cellapp data plan --project .
|
|
15
|
+
cellapp data apply --project .
|
|
16
|
+
cellapp data verify --project .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
首次部署可加 `--namespace <你的空间名>` 自选命名空间;未指定时 Cellapp 生成与平台用户 ID 无关的空间名。示例中的 `--slug notes-demo` 在同一空间内必须唯一。应用显示名可以重名,控制台提供 `@空间名/notes-demo` 分享链接,原应用 ID 地址保持稳定。首次部署会创建应用及项目关联,然后 `data apply` 在独立应用数据库中建表并授予当前应用的表操作权限。首次发布返回的访问密钥只交给所有者,不要存入项目文件。打开部署返回的应用地址,完成 Cellapp 登录;受限应用还需授权访问。页面可新增、查看、编辑、删除笔记;“Run CRUD” 会依次执行创建、读取、更新和删除,并显示结果。第一次打开前应完成 `data verify`,确认 `ready: true`。
|
|
20
|
+
|
|
21
|
+
`cellapp.data.json` 声明表、主键、索引及 `own-rows` 策略。[`notes.ts`](notes.ts) 只用支持的 `supabase-js` 表级操作和 `/_cellapp/me` 应用内身份;`cellapp-public` 是非秘密标识,不授予任何数据权限。构建产物仅包含静态前端,不包含 CLI 凭证、访问密钥或数据库连接串。
|