@lumerahq/cli 0.19.16-dev.0 → 0.19.17-dev.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/dist/{chunk-TPQGGLSD.js → chunk-4WZMUFC7.js} +1 -1
- package/dist/{chunk-WIX3DUD5.js → chunk-MDCAEFUH.js} +0 -7
- package/dist/{chunk-VM5YR3HF.js → chunk-VOIZWYZD.js} +3 -12
- package/dist/{deps-ALKBN6UT.js → deps-KVHWZARX.js} +2 -2
- package/dist/{dev-33OLPWUK.js → dev-PONRO7VN.js} +3 -3
- package/dist/index.js +12 -12
- package/dist/{init-EBNELAZA.js → init-KJOWD2KQ.js} +1 -1
- package/dist/{register-EQ5KYVLV.js → register-QBRKXWNX.js} +1 -1
- package/dist/{resources-EZQGSI5L.js → resources-M6R2RFSW.js} +5 -5
- package/dist/{run-BQPH6BIK.js → run-R6MO23U7.js} +1 -1
- package/package.json +1 -1
- package/templates/default/AGENTS.md +13 -4
|
@@ -25,12 +25,6 @@ while (__pkgDir !== "/") {
|
|
|
25
25
|
}
|
|
26
26
|
var pkg = JSON.parse(readFileSync(resolve(__pkgDir, "package.json"), "utf-8"));
|
|
27
27
|
var CLI_USER_AGENT = `lumera-cli/${pkg.version}`;
|
|
28
|
-
var USER_CONTEXT_ENV = "LUMERA_USER_ID";
|
|
29
|
-
var USER_CONTEXT_HEADER = "X-Lumera-User-Id";
|
|
30
|
-
function userContextHeaders() {
|
|
31
|
-
const userID = process.env[USER_CONTEXT_ENV]?.trim();
|
|
32
|
-
return userID ? { [USER_CONTEXT_HEADER]: userID } : {};
|
|
33
|
-
}
|
|
34
28
|
var ApiError = class extends Error {
|
|
35
29
|
status;
|
|
36
30
|
body;
|
|
@@ -73,7 +67,6 @@ var ApiClient = class {
|
|
|
73
67
|
"User-Agent": CLI_USER_AGENT,
|
|
74
68
|
"X-Lumera-Client": "lumera-cli",
|
|
75
69
|
...this.projectExternalId ? { "X-Lumera-Project": this.projectExternalId } : {},
|
|
76
|
-
...userContextHeaders(),
|
|
77
70
|
...options.headers
|
|
78
71
|
};
|
|
79
72
|
const method = (options.method || "GET").toUpperCase();
|
|
@@ -9,12 +9,6 @@ import { existsSync, readFileSync } from "fs";
|
|
|
9
9
|
import { resolve, dirname } from "path";
|
|
10
10
|
import archiver from "archiver";
|
|
11
11
|
import pc from "picocolors";
|
|
12
|
-
var USER_CONTEXT_ENV = "LUMERA_USER_ID";
|
|
13
|
-
var USER_CONTEXT_HEADER = "X-Lumera-User-Id";
|
|
14
|
-
function userContextHeaders() {
|
|
15
|
-
const userID = process.env[USER_CONTEXT_ENV]?.trim();
|
|
16
|
-
return userID ? { [USER_CONTEXT_HEADER]: userID } : {};
|
|
17
|
-
}
|
|
18
12
|
function formatTimestampVersion(date = /* @__PURE__ */ new Date()) {
|
|
19
13
|
const pad = (value) => String(value).padStart(2, "0");
|
|
20
14
|
return [
|
|
@@ -62,8 +56,7 @@ async function ensureAppRecord(apiBase, token, appName, appTitle) {
|
|
|
62
56
|
{
|
|
63
57
|
headers: {
|
|
64
58
|
Authorization: `Bearer ${token}`,
|
|
65
|
-
"X-Lumera-Client": "lumera-cli"
|
|
66
|
-
...userContextHeaders()
|
|
59
|
+
"X-Lumera-Client": "lumera-cli"
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
);
|
|
@@ -82,8 +75,7 @@ async function ensureAppRecord(apiBase, token, appName, appTitle) {
|
|
|
82
75
|
headers: {
|
|
83
76
|
Authorization: `Bearer ${token}`,
|
|
84
77
|
"Content-Type": "application/json",
|
|
85
|
-
"X-Lumera-Client": "lumera-cli"
|
|
86
|
-
...userContextHeaders()
|
|
78
|
+
"X-Lumera-Client": "lumera-cli"
|
|
87
79
|
},
|
|
88
80
|
body: JSON.stringify(appData)
|
|
89
81
|
});
|
|
@@ -116,8 +108,7 @@ async function deploy(options) {
|
|
|
116
108
|
method: "POST",
|
|
117
109
|
headers: {
|
|
118
110
|
Authorization: `Bearer ${token}`,
|
|
119
|
-
"X-Lumera-Client": "lumera-cli"
|
|
120
|
-
...userContextHeaders()
|
|
111
|
+
"X-Lumera-Client": "lumera-cli"
|
|
121
112
|
},
|
|
122
113
|
body: formData
|
|
123
114
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deps,
|
|
3
3
|
syncDeps
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4WZMUFC7.js";
|
|
5
5
|
import "./chunk-2CR762KB.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-MDCAEFUH.js";
|
|
7
7
|
import "./chunk-ZH3NVYEQ.js";
|
|
8
8
|
import "./chunk-FJFIWC7G.js";
|
|
9
9
|
import "./chunk-PNKVD2UK.js";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dev
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VOIZWYZD.js";
|
|
4
4
|
import {
|
|
5
5
|
syncDeps
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4WZMUFC7.js";
|
|
7
7
|
import {
|
|
8
8
|
loadEnv
|
|
9
9
|
} from "./chunk-2CR762KB.js";
|
|
10
10
|
import {
|
|
11
11
|
createApiClient
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-MDCAEFUH.js";
|
|
13
13
|
import {
|
|
14
14
|
findProjectRoot,
|
|
15
15
|
getApiUrl,
|
package/dist/index.js
CHANGED
|
@@ -219,39 +219,39 @@ async function main() {
|
|
|
219
219
|
switch (command) {
|
|
220
220
|
// Resource commands
|
|
221
221
|
case "plan":
|
|
222
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.plan(args.slice(1)));
|
|
223
223
|
break;
|
|
224
224
|
case "apply":
|
|
225
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.apply(args.slice(1)));
|
|
226
226
|
break;
|
|
227
227
|
case "pull":
|
|
228
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.pull(args.slice(1)));
|
|
229
229
|
break;
|
|
230
230
|
case "destroy":
|
|
231
|
-
await import("./resources-
|
|
231
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.destroy(args.slice(1)));
|
|
232
232
|
break;
|
|
233
233
|
case "list":
|
|
234
|
-
await import("./resources-
|
|
234
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.list(args.slice(1)));
|
|
235
235
|
break;
|
|
236
236
|
case "show":
|
|
237
|
-
await import("./resources-
|
|
237
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.show(args.slice(1)));
|
|
238
238
|
break;
|
|
239
239
|
case "diff":
|
|
240
|
-
await import("./resources-
|
|
240
|
+
await import("./resources-M6R2RFSW.js").then((m) => m.diff(args.slice(1)));
|
|
241
241
|
break;
|
|
242
242
|
// Development
|
|
243
243
|
case "dev":
|
|
244
|
-
await import("./dev-
|
|
244
|
+
await import("./dev-PONRO7VN.js").then((m) => m.dev(args.slice(1)));
|
|
245
245
|
break;
|
|
246
246
|
case "run":
|
|
247
|
-
await import("./run-
|
|
247
|
+
await import("./run-R6MO23U7.js").then((m) => m.run(args.slice(1)));
|
|
248
248
|
break;
|
|
249
249
|
// Project
|
|
250
250
|
case "init":
|
|
251
|
-
await import("./init-
|
|
251
|
+
await import("./init-KJOWD2KQ.js").then((m) => m.init(args.slice(1)));
|
|
252
252
|
break;
|
|
253
253
|
case "register":
|
|
254
|
-
await import("./register-
|
|
254
|
+
await import("./register-QBRKXWNX.js").then((m) => m.register(args.slice(1)));
|
|
255
255
|
break;
|
|
256
256
|
case "templates":
|
|
257
257
|
await import("./templates-LNUOTNLN.js").then((m) => m.templates(subcommand, args.slice(2)));
|
|
@@ -268,7 +268,7 @@ async function main() {
|
|
|
268
268
|
break;
|
|
269
269
|
// Dependencies
|
|
270
270
|
case "deps":
|
|
271
|
-
await import("./deps-
|
|
271
|
+
await import("./deps-KVHWZARX.js").then((m) => m.deps(args.slice(1)));
|
|
272
272
|
break;
|
|
273
273
|
// Auth
|
|
274
274
|
case "login":
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deploy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VOIZWYZD.js";
|
|
4
4
|
import {
|
|
5
5
|
syncDeps
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4WZMUFC7.js";
|
|
7
7
|
import {
|
|
8
8
|
loadEnv
|
|
9
9
|
} from "./chunk-2CR762KB.js";
|
|
10
10
|
import {
|
|
11
11
|
ApiError,
|
|
12
12
|
createApiClient
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-MDCAEFUH.js";
|
|
14
14
|
import {
|
|
15
15
|
findProjectRoot,
|
|
16
16
|
getApiUrl,
|
|
@@ -3073,7 +3073,7 @@ async function plan(args) {
|
|
|
3073
3073
|
showPlanHelp();
|
|
3074
3074
|
return;
|
|
3075
3075
|
}
|
|
3076
|
-
const jsonOutput =
|
|
3076
|
+
const jsonOutput = process.env.LUMERA_JSON === "1";
|
|
3077
3077
|
const projectRoot = findProjectRoot();
|
|
3078
3078
|
loadEnv(projectRoot);
|
|
3079
3079
|
const platformDir = getPlatformDir();
|
|
@@ -3081,7 +3081,7 @@ async function plan(args) {
|
|
|
3081
3081
|
const api = createApiClient(void 0, void 0, appName);
|
|
3082
3082
|
const projectId = getProjectId(projectRoot);
|
|
3083
3083
|
const positionalArgs = args.filter((a) => !a.startsWith("-"));
|
|
3084
|
-
const { type, name } = parseResource(positionalArgs
|
|
3084
|
+
const { type, name } = parseResource(positionalArgs[0]);
|
|
3085
3085
|
console.log();
|
|
3086
3086
|
console.log(pc2.cyan(pc2.bold(" Plan")));
|
|
3087
3087
|
console.log(pc2.dim(" Comparing local files to remote state..."));
|
package/package.json
CHANGED
|
@@ -41,9 +41,9 @@ All resources use **external IDs** in the format `<app-name>:<resource-name>` (a
|
|
|
41
41
|
**All collection names are automatically namespaced by project.** Always use bare names (e.g. `orders`, not `myproject__orders`) everywhere — in collection JSON files, Python SDK calls, JavaScript hooks, and frontend queries. The platform resolves bare names to the project-scoped version transparently.
|
|
42
42
|
|
|
43
43
|
- `pb.ensure_collection("orders", ...)` → stored as `{project}__orders`
|
|
44
|
-
- `
|
|
44
|
+
- `query_sql("SELECT id FROM orders")` → resolves to `{project}__orders`
|
|
45
45
|
- `ctx.dao.find("orders", ...)` → resolves to `{project}__orders`
|
|
46
|
-
- `
|
|
46
|
+
- `pbSql({ sql: "SELECT id FROM orders" })` in frontend → resolves via `X-Lumera-Project` header
|
|
47
47
|
|
|
48
48
|
**Never manually prefix collection names with `{project}__`.** Two projects can each have an `orders` collection — they are fully isolated.
|
|
49
49
|
|
|
@@ -96,10 +96,16 @@ Custom apps run in an **iframe**. **Always use the `@lumerahq/ui` bridge for API
|
|
|
96
96
|
|
|
97
97
|
```ts
|
|
98
98
|
// ✅ Correct — uses postMessage bridge, no CORS issues
|
|
99
|
-
import { pbSql,
|
|
99
|
+
import { pbSql, pbCreate, pbUpdate, pbDelete } from '@lumerahq/ui/lib';
|
|
100
|
+
|
|
101
|
+
// New read queries: use SQL for collection access, including lookups, lists, reports, joins, ordering, and filters
|
|
102
|
+
const result = await pbSql<{ id: string; amount: number }>({
|
|
103
|
+
sql: 'SELECT id, amount FROM orders WHERE status = {:status} ORDER BY updated DESC LIMIT 100',
|
|
104
|
+
params: { status: 'pending' },
|
|
105
|
+
});
|
|
106
|
+
const records = result.rows;
|
|
100
107
|
|
|
101
108
|
// CRUD
|
|
102
|
-
const records = await pbList('orders', { filter: JSON.stringify({ status: "pending" }) });
|
|
103
109
|
await pbCreate('orders', { amount: 100 });
|
|
104
110
|
await pbUpdate('orders', recordId, { status: 'done' });
|
|
105
111
|
await pbDelete('orders', recordId);
|
|
@@ -113,6 +119,9 @@ fetch('https://app.lumerahq.com/api/pb/sql', ...);
|
|
|
113
119
|
|
|
114
120
|
**Rules:**
|
|
115
121
|
- Always import from `@lumerahq/ui/lib` — never write a custom `apiFetch` with raw `fetch()`
|
|
122
|
+
- Use `pbSql()` for new read-only collection access
|
|
123
|
+
- Existing `pbList()` / `pbSearch()` filter code remains supported for simple existing list/search reads; do not rewrite working code just because SQL exists
|
|
124
|
+
- Use record helpers such as `pbCreate()`, `pbUpdate()`, and `pbDelete()` for mutations
|
|
116
125
|
- Token is not needed — the bridge handles auth via the parent session
|
|
117
126
|
- `X-Lumera-Project` header is not needed — the parent adds it automatically
|
|
118
127
|
|