@lumerahq/cli 0.19.10 → 0.19.11

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.
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createApiClient,
6
6
  isApiErrorStatus
7
- } from "./chunk-EDRAYUWN.js";
7
+ } from "./chunk-MDCAEFUH.js";
8
8
  import {
9
9
  findProjectRoot,
10
10
  getAppName
@@ -14,17 +14,7 @@ import {
14
14
  import pc from "picocolors";
15
15
  import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from "fs";
16
16
  import { join } from "path";
17
- var LEGACY_DEPS_FILE = "platform/project_deps.json";
18
17
  var SHARED_COLLECTIONS_DIR = "platform/collections/shared";
19
- function loadLegacyDeps(projectRoot) {
20
- const depsPath = join(projectRoot, LEGACY_DEPS_FILE);
21
- if (!existsSync(depsPath)) return null;
22
- try {
23
- return JSON.parse(readFileSync(depsPath, "utf-8"));
24
- } catch {
25
- return null;
26
- }
27
- }
28
18
  function sharedCollectionsDir(projectRoot) {
29
19
  return join(projectRoot, SHARED_COLLECTIONS_DIR);
30
20
  }
@@ -58,13 +48,6 @@ function loadSharedCollectionDeps(projectRoot) {
58
48
  }
59
49
  return deps2.sort((a, b) => a.file.localeCompare(b.file));
60
50
  }
61
- async function projectPermissionsModeEnabled(api) {
62
- try {
63
- return await api.isProjectPermissionsModeEnabled();
64
- } catch {
65
- return false;
66
- }
67
- }
68
51
  function declarationForShare(share, existing) {
69
52
  return {
70
53
  ...existing ?? {},
@@ -134,156 +117,76 @@ async function syncResourceShareDeps(projectRoot, api, projectExternalId, opts)
134
117
  }
135
118
  return true;
136
119
  }
137
- async function syncLegacyDeps(projectRoot, api, quiet = false) {
138
- const deps2 = loadLegacyDeps(projectRoot);
139
- if (!deps2 || !deps2.dependencies || Object.keys(deps2.dependencies).length === 0) {
140
- return true;
141
- }
142
- let allOk = true;
143
- for (const [depProject, config] of Object.entries(deps2.dependencies)) {
144
- try {
145
- const manifest = await api.getProjectManifest(depProject);
146
- const remoteNames = new Set(manifest.collections.map((c) => c.name));
147
- for (const col of config.collections) {
148
- if (remoteNames.has(col)) {
149
- if (!quiet) console.log(pc.green(" \u2713"), `${depProject}/${col}`);
150
- } else {
151
- if (!quiet) console.log(pc.red(" \u2717"), `${depProject}/${col} \u2014 not found in project manifest`);
152
- allOk = false;
153
- }
154
- }
155
- } catch (e) {
156
- if (!quiet) console.log(pc.red(" \u2717"), `${depProject}: failed to fetch manifest \u2014 ${e}`);
157
- allOk = false;
158
- }
159
- }
160
- return allOk;
161
- }
162
- async function projectResourceDepsEnabled(projectRoot) {
163
- const root = projectRoot ?? findProjectRoot();
164
- loadEnv(root);
165
- const appName = getAppName(root);
166
- const api = createApiClient(void 0, void 0, appName);
167
- return projectPermissionsModeEnabled(api);
168
- }
169
120
  async function syncDeps(projectRoot, options = {}) {
170
121
  const root = projectRoot ?? findProjectRoot();
171
122
  loadEnv(root);
172
123
  const appName = getAppName(root);
173
124
  const api = createApiClient(void 0, void 0, appName);
174
- const flagOn = await projectPermissionsModeEnabled(api);
175
125
  const quiet = options.quiet === true;
176
126
  const write = options.write === true;
177
- if (flagOn) {
178
- return syncResourceShareDeps(root, api, appName, {
179
- write,
180
- quiet,
181
- ignorePermissionDenied: options.ignorePermissionDenied === true
182
- });
183
- }
184
- if (options.legacyWhenDisabled === false) {
185
- return true;
186
- }
187
- return syncLegacyDeps(root, api, quiet);
127
+ return syncResourceShareDeps(root, api, appName, {
128
+ write,
129
+ quiet,
130
+ ignorePermissionDenied: options.ignorePermissionDenied === true
131
+ });
188
132
  }
189
133
  async function deps(args) {
190
134
  const sub = args[0];
191
135
  const projectRoot = findProjectRoot();
192
136
  loadEnv(projectRoot);
193
- let cachedFlagOn;
194
- async function flagOn() {
195
- if (cachedFlagOn !== void 0) return cachedFlagOn;
196
- cachedFlagOn = await projectResourceDepsEnabled(projectRoot);
197
- return cachedFlagOn;
198
- }
199
137
  if (sub === "sync") {
200
- const enabled = await flagOn();
201
138
  console.log();
202
139
  console.log(pc.cyan(pc.bold(" Deps Sync")));
203
- console.log(pc.dim(enabled ? " Syncing incoming resource shares into platform/collections/shared..." : " Verifying legacy cross-project dependencies..."));
140
+ console.log(pc.dim(" Syncing incoming resource shares into platform/collections/shared..."));
204
141
  console.log();
205
- const ok = await syncDeps(projectRoot, { write: enabled });
142
+ const ok = await syncDeps(projectRoot, { write: true });
206
143
  if (!ok) {
207
144
  console.log();
208
- console.log(pc.red(enabled ? " Some resource-share dependencies could not be synced." : " Some dependencies could not be resolved."));
145
+ console.log(pc.red(" Some resource-share dependencies could not be synced."));
209
146
  process.exit(1);
210
147
  }
211
148
  console.log();
212
- console.log(pc.green(enabled ? " Resource shares synced." : " All dependencies verified."));
149
+ console.log(pc.green(" Resource shares synced."));
213
150
  return;
214
151
  }
215
152
  if (sub === "list") {
216
- if (await flagOn()) {
217
- const sharedDeps = loadSharedCollectionDeps(projectRoot);
218
- if (sharedDeps.length === 0) {
219
- console.log(pc.dim(" No shared collection declarations in platform/collections/shared"));
220
- return;
221
- }
222
- console.log();
223
- console.log(pc.cyan(pc.bold(" Shared Collection Dependencies")));
224
- console.log();
225
- for (const { file, dep } of sharedDeps) {
226
- const source = dep.source_project ?? "unknown-source";
227
- const collection = dep.collection ?? "unknown-table";
228
- const privilege = dep.privilege ?? "collection.read";
229
- console.log(` ${pc.bold(file)}`);
230
- console.log(` ${source}/${collection} ${pc.dim(`(${privilege})`)}`);
231
- }
232
- console.log();
233
- return;
234
- }
235
- const depsData = loadLegacyDeps(projectRoot);
236
- if (!depsData || Object.keys(depsData.dependencies).length === 0) {
237
- console.log(pc.dim(" No dependencies declared in platform/project_deps.json"));
153
+ const sharedDeps = loadSharedCollectionDeps(projectRoot);
154
+ if (sharedDeps.length === 0) {
155
+ console.log(pc.dim(" No shared collection declarations in platform/collections/shared"));
238
156
  return;
239
157
  }
240
158
  console.log();
241
- console.log(pc.cyan(pc.bold(" Project Dependencies")));
159
+ console.log(pc.cyan(pc.bold(" Shared Collection Dependencies")));
242
160
  console.log();
243
- for (const [depProject, config] of Object.entries(depsData.dependencies)) {
244
- console.log(` ${pc.bold(depProject)}`);
245
- for (const col of config.collections) {
246
- console.log(` \u2022 ${col}`);
247
- }
161
+ for (const { file, dep } of sharedDeps) {
162
+ const source = dep.source_project ?? "unknown-source";
163
+ const collection = dep.collection ?? "unknown-table";
164
+ const privilege = dep.privilege ?? "collection.read";
165
+ console.log(` ${pc.bold(file)}`);
166
+ console.log(` ${source}/${collection} ${pc.dim(`(${privilege})`)}`);
248
167
  }
249
168
  console.log();
250
169
  return;
251
170
  }
252
171
  if (sub === "init") {
253
- if (await flagOn()) {
254
- const dir = sharedCollectionsDir(projectRoot);
255
- mkdirSync(dir, { recursive: true });
256
- console.log(pc.green(" \u2713"), "Created platform/collections/shared/");
257
- return;
258
- }
259
- const depsPath = join(projectRoot, LEGACY_DEPS_FILE);
260
- if (existsSync(depsPath)) {
261
- console.log(pc.yellow(" platform/project_deps.json already exists."));
262
- return;
263
- }
264
- const platformDir = join(projectRoot, "platform");
265
- mkdirSync(platformDir, { recursive: true });
266
- const initial = { dependencies: {} };
267
- writeFileSync(depsPath, JSON.stringify(initial, null, 2) + "\n");
268
- console.log(pc.green(" \u2713"), "Created platform/project_deps.json");
172
+ const dir = sharedCollectionsDir(projectRoot);
173
+ mkdirSync(dir, { recursive: true });
174
+ console.log(pc.green(" \u2713"), "Created platform/collections/shared/");
269
175
  return;
270
176
  }
271
177
  console.log(`
272
178
  ${pc.bold("lumera deps")} \u2014 manage cross-project dependencies
273
179
 
274
180
  ${pc.bold("Commands:")}
275
- sync Sync dependencies. With project permissions on, writes incoming
276
- resource shares to platform/collections/shared/*.json
181
+ sync Sync incoming resource shares to platform/collections/shared/*.json
277
182
  list Show declared dependencies
278
- init Create dependency storage for the current feature mode
183
+ init Create dependency storage
279
184
 
280
- ${pc.bold("Project permissions mode:")} platform/collections/shared/*.json
281
- ${pc.bold("Legacy mode:")} platform/project_deps.json
185
+ ${pc.bold("Dependencies:")} platform/collections/shared/*.json
282
186
  `);
283
187
  }
284
188
 
285
189
  export {
286
- projectResourceDepsEnabled,
287
190
  syncDeps,
288
191
  deps
289
192
  };
@@ -90,10 +90,6 @@ var ApiClient = class {
90
90
  async getMe() {
91
91
  return this.request("/api/me");
92
92
  }
93
- async isProjectPermissionsModeEnabled() {
94
- const me = await this.getMe();
95
- return me.user?.feature_flags?.project_permissions_mode === true;
96
- }
97
93
  async listCollections() {
98
94
  const result = await this.request("/api/pb/collections");
99
95
  return result.items;
@@ -116,9 +116,10 @@ async function deploy(options) {
116
116
  throw new Error(`Deploy failed: ${await res.text()}`);
117
117
  }
118
118
  const result = await res.json();
119
+ const launchUrl = result.launch_url || result.url;
119
120
  console.log(pc.green(`
120
- Deployed! ${result.url}`));
121
- return { url: result.url, version };
121
+ Deployed! ${launchUrl}`));
122
+ return { url: launchUrl, version };
122
123
  }
123
124
  function isPortInUse(port, host = "127.0.0.1") {
124
125
  return new Promise((resolve2) => {
@@ -1,15 +1,13 @@
1
1
  import {
2
2
  deps,
3
- projectResourceDepsEnabled,
4
3
  syncDeps
5
- } from "./chunk-WWEIOMW6.js";
4
+ } from "./chunk-4WZMUFC7.js";
6
5
  import "./chunk-2CR762KB.js";
7
- import "./chunk-EDRAYUWN.js";
6
+ import "./chunk-MDCAEFUH.js";
8
7
  import "./chunk-ZH3NVYEQ.js";
9
8
  import "./chunk-FJFIWC7G.js";
10
9
  import "./chunk-PNKVD2UK.js";
11
10
  export {
12
11
  deps,
13
- projectResourceDepsEnabled,
14
12
  syncDeps
15
13
  };
@@ -1,16 +1,15 @@
1
1
  import {
2
2
  dev
3
- } from "./chunk-53NOF33P.js";
3
+ } from "./chunk-OGG5TR4Y.js";
4
4
  import {
5
- projectResourceDepsEnabled,
6
5
  syncDeps
7
- } from "./chunk-WWEIOMW6.js";
6
+ } from "./chunk-4WZMUFC7.js";
8
7
  import {
9
8
  loadEnv
10
9
  } from "./chunk-2CR762KB.js";
11
10
  import {
12
11
  createApiClient
13
- } from "./chunk-EDRAYUWN.js";
12
+ } from "./chunk-MDCAEFUH.js";
14
13
  import {
15
14
  findProjectRoot,
16
15
  getApiUrl,
@@ -125,14 +124,11 @@ async function dev2(args) {
125
124
  const appName = getAppName(projectRoot);
126
125
  const appTitle = getAppTitle(projectRoot);
127
126
  const apiUrl = getApiUrl();
128
- if (await projectResourceDepsEnabled(projectRoot)) {
129
- await syncDeps(projectRoot, {
130
- write: true,
131
- quiet: true,
132
- legacyWhenDisabled: false,
133
- ignorePermissionDenied: true
134
- });
135
- }
127
+ await syncDeps(projectRoot, {
128
+ write: true,
129
+ quiet: true,
130
+ ignorePermissionDenied: true
131
+ });
136
132
  if (!flags["skip-setup"]) {
137
133
  const fresh = await isFreshProject(projectRoot);
138
134
  if (fresh) {
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-M3ILBD6X.js").then((m) => m.plan(args.slice(1)));
222
+ await import("./resources-DPGY7KC3.js").then((m) => m.plan(args.slice(1)));
223
223
  break;
224
224
  case "apply":
225
- await import("./resources-M3ILBD6X.js").then((m) => m.apply(args.slice(1)));
225
+ await import("./resources-DPGY7KC3.js").then((m) => m.apply(args.slice(1)));
226
226
  break;
227
227
  case "pull":
228
- await import("./resources-M3ILBD6X.js").then((m) => m.pull(args.slice(1)));
228
+ await import("./resources-DPGY7KC3.js").then((m) => m.pull(args.slice(1)));
229
229
  break;
230
230
  case "destroy":
231
- await import("./resources-M3ILBD6X.js").then((m) => m.destroy(args.slice(1)));
231
+ await import("./resources-DPGY7KC3.js").then((m) => m.destroy(args.slice(1)));
232
232
  break;
233
233
  case "list":
234
- await import("./resources-M3ILBD6X.js").then((m) => m.list(args.slice(1)));
234
+ await import("./resources-DPGY7KC3.js").then((m) => m.list(args.slice(1)));
235
235
  break;
236
236
  case "show":
237
- await import("./resources-M3ILBD6X.js").then((m) => m.show(args.slice(1)));
237
+ await import("./resources-DPGY7KC3.js").then((m) => m.show(args.slice(1)));
238
238
  break;
239
239
  case "diff":
240
- await import("./resources-M3ILBD6X.js").then((m) => m.diff(args.slice(1)));
240
+ await import("./resources-DPGY7KC3.js").then((m) => m.diff(args.slice(1)));
241
241
  break;
242
242
  // Development
243
243
  case "dev":
244
- await import("./dev-35XSSGOG.js").then((m) => m.dev(args.slice(1)));
244
+ await import("./dev-EZTXUSD2.js").then((m) => m.dev(args.slice(1)));
245
245
  break;
246
246
  case "run":
247
- await import("./run-YUL73K5O.js").then((m) => m.run(args.slice(1)));
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-FW4RFXLL.js").then((m) => m.init(args.slice(1)));
251
+ await import("./init-QCNR4ULM.js").then((m) => m.init(args.slice(1)));
252
252
  break;
253
253
  case "register":
254
- await import("./register-HR2QQFWX.js").then((m) => m.register(args.slice(1)));
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-WSZGH35V.js").then((m) => m.deps(args.slice(1)));
271
+ await import("./deps-KVHWZARX.js").then((m) => m.deps(args.slice(1)));
272
272
  break;
273
273
  // Auth
274
274
  case "login":
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-BHYDYR75.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-EDRAYUWN.js";
10
+ } from "./chunk-MDCAEFUH.js";
11
11
  import {
12
12
  getToken,
13
13
  init_auth,
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-BHYDYR75.js";
7
7
  import {
8
8
  createApiClient
9
- } from "./chunk-EDRAYUWN.js";
9
+ } from "./chunk-MDCAEFUH.js";
10
10
  import {
11
11
  findProjectRoot,
12
12
  getAppName,
@@ -1,17 +1,16 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-53NOF33P.js";
3
+ } from "./chunk-OGG5TR4Y.js";
4
4
  import {
5
- projectResourceDepsEnabled,
6
5
  syncDeps
7
- } from "./chunk-WWEIOMW6.js";
6
+ } from "./chunk-4WZMUFC7.js";
8
7
  import {
9
8
  loadEnv
10
9
  } from "./chunk-2CR762KB.js";
11
10
  import {
12
11
  ApiError,
13
12
  createApiClient
14
- } from "./chunk-EDRAYUWN.js";
13
+ } from "./chunk-MDCAEFUH.js";
15
14
  import {
16
15
  findProjectRoot,
17
16
  getApiUrl,
@@ -3385,9 +3384,9 @@ async function pull(args) {
3385
3384
  console.log(pc2.bold(" Collections:"));
3386
3385
  await pullCollections(api, platformDir, name || void 0, appName);
3387
3386
  console.log();
3388
- if (!name && await projectResourceDepsEnabled(projectRoot)) {
3387
+ if (!name) {
3389
3388
  console.log(pc2.bold(" Resource shares:"));
3390
- await syncDeps(projectRoot, { write: true, legacyWhenDisabled: false, ignorePermissionDenied: true });
3389
+ await syncDeps(projectRoot, { write: true, ignorePermissionDenied: true });
3391
3390
  console.log();
3392
3391
  }
3393
3392
  }
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2CR762KB.js";
4
4
  import {
5
5
  createApiClient
6
- } from "./chunk-EDRAYUWN.js";
6
+ } from "./chunk-MDCAEFUH.js";
7
7
  import {
8
8
  findProjectRoot,
9
9
  getApiUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.19.10",
3
+ "version": "0.19.11",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {
@@ -13,6 +13,11 @@
13
13
  "dist",
14
14
  "templates"
15
15
  ],
16
+ "scripts": {
17
+ "build": "tsup src/index.ts --format esm --clean",
18
+ "dev": "tsup src/index.ts --format esm --watch",
19
+ "prepublishOnly": "pnpm build"
20
+ },
16
21
  "dependencies": {
17
22
  "acorn": "^8.16.0",
18
23
  "archiver": "^7.0.1",
@@ -30,9 +35,5 @@
30
35
  },
31
36
  "publishConfig": {
32
37
  "access": "public"
33
- },
34
- "scripts": {
35
- "build": "tsup src/index.ts --format esm --clean",
36
- "dev": "tsup src/index.ts --format esm --watch"
37
38
  }
38
- }
39
+ }
@@ -110,6 +110,18 @@ fetch('https://app.lumerahq.com/api/pb/sql', ...);
110
110
  - Token is not needed — the bridge handles auth via the parent session
111
111
  - `X-Lumera-Project` header is not needed — the parent adds it automatically
112
112
 
113
+ ## Shareable Links
114
+
115
+ For any URL a human will open (copy-link, invites, emails, QR codes), use `getShareableAppUrl()` or `buildShareableAppUrl()` from `@lumerahq/ui/lib` — **never `window.location.href`**. The app runs inside an iframe, so `window.location` returns the internal `/_apps/{company}/{app}/...` URL instead of the shell's `/app/{appId}` URL.
116
+
117
+ ```ts
118
+ import { buildShareableAppUrl, getShareableAppUrl } from '@lumerahq/ui/lib';
119
+ const link = getShareableAppUrl(); // preserves current path/search/hash
120
+ const invoiceLink = buildShareableAppUrl('/invoices/123', { router: 'hash' });
121
+ ```
122
+
123
+ When reporting a deployed app, use `launch_url` or `url` from the deploy response. Do not share `iframe_url`; it is only the internal iframe/static asset mount.
124
+
113
125
 
114
126
  ## Workflow
115
127