@lumerahq/cli 0.23.0-dev.3 → 0.24.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-WV5HOQNX.js → chunk-I7QEYKS7.js} +32 -4
- package/dist/{dev-UTPD4MN5.js → dev-VWHFYKGC.js} +1 -1
- package/dist/index.js +8 -8
- package/dist/{resources-QCCLRDOL.js → resources-CGMBV3T6.js} +15 -2
- package/package.json +1 -1
- package/templates/default/package.json +1 -1
- package/templates/default/src/main.tsx +34 -18
- package/templates/default/vite.config.ts +3 -1
|
@@ -41,6 +41,24 @@ function resolveVersion(cwd) {
|
|
|
41
41
|
}
|
|
42
42
|
return formatTimestampVersion();
|
|
43
43
|
}
|
|
44
|
+
function resolveUIVersion(cwd) {
|
|
45
|
+
try {
|
|
46
|
+
const installed = JSON.parse(
|
|
47
|
+
readFileSync(resolve(cwd, "node_modules/@lumerahq/ui/package.json"), "utf-8")
|
|
48
|
+
);
|
|
49
|
+
if (installed?.version) return String(installed.version);
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const pkg = JSON.parse(readFileSync(resolve(cwd, "package.json"), "utf-8"));
|
|
54
|
+
const spec = pkg?.dependencies?.["@lumerahq/ui"] ?? pkg?.devDependencies?.["@lumerahq/ui"];
|
|
55
|
+
if (!spec) return "none";
|
|
56
|
+
const cleaned = String(spec).replace(/^[\^~>=<\s]+/, "");
|
|
57
|
+
return /^\d+\.\d+/.test(cleaned) ? cleaned : "";
|
|
58
|
+
} catch {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
44
62
|
function resolveGitSha(cwd) {
|
|
45
63
|
try {
|
|
46
64
|
return execSync("git rev-parse HEAD", {
|
|
@@ -62,11 +80,14 @@ async function createTarball(distDir) {
|
|
|
62
80
|
archive.finalize();
|
|
63
81
|
});
|
|
64
82
|
}
|
|
65
|
-
async function ensureAppRecord(apiBase, token, appName, appTitle) {
|
|
83
|
+
async function ensureAppRecord(apiBase, token, appName, appTitle, accessLevel) {
|
|
66
84
|
const appData = {
|
|
67
85
|
name: appTitle,
|
|
68
86
|
hosting_type: "s3"
|
|
69
87
|
};
|
|
88
|
+
if (accessLevel) {
|
|
89
|
+
appData.access_level = accessLevel;
|
|
90
|
+
}
|
|
70
91
|
const res = await fetchWithRetry(`${apiBase}/custom-apps/${encodeURIComponent(appName)}/registration`, {
|
|
71
92
|
method: "PUT",
|
|
72
93
|
headers: {
|
|
@@ -87,13 +108,14 @@ async function deploy(options) {
|
|
|
87
108
|
appName,
|
|
88
109
|
appTitle,
|
|
89
110
|
distDir,
|
|
90
|
-
apiUrl
|
|
111
|
+
apiUrl,
|
|
112
|
+
accessLevel
|
|
91
113
|
} = options;
|
|
92
114
|
if (!existsSync(distDir)) {
|
|
93
115
|
throw new Error(`dist directory not found: ${distDir}`);
|
|
94
116
|
}
|
|
95
117
|
console.log(pc.dim("Ensuring app record..."));
|
|
96
|
-
await ensureAppRecord(apiUrl, token, appName, appTitle);
|
|
118
|
+
await ensureAppRecord(apiUrl, token, appName, appTitle, accessLevel);
|
|
97
119
|
console.log(pc.cyan(`Deploying ${appTitle}...`));
|
|
98
120
|
const version = options.version || process.env.LUMERA_APP_VERSION?.trim() || resolveVersion(dirname(distDir));
|
|
99
121
|
console.log(pc.dim(`Version: ${version}`));
|
|
@@ -104,6 +126,8 @@ async function deploy(options) {
|
|
|
104
126
|
formData.append("version", version);
|
|
105
127
|
const gitSha = resolveGitSha(dirname(distDir));
|
|
106
128
|
if (gitSha) formData.append("git_sha", gitSha);
|
|
129
|
+
const uiVersion = resolveUIVersion(dirname(distDir));
|
|
130
|
+
if (uiVersion) formData.append("ui_version", uiVersion);
|
|
107
131
|
const res = await fetchWithRetry(`${apiUrl}/custom-apps/${appName}/deploy`, {
|
|
108
132
|
method: "POST",
|
|
109
133
|
headers: {
|
|
@@ -118,9 +142,13 @@ async function deploy(options) {
|
|
|
118
142
|
}
|
|
119
143
|
const result = await res.json();
|
|
120
144
|
const launchUrl = result.launch_url;
|
|
145
|
+
const appUrl = result.app_url;
|
|
121
146
|
console.log(pc.green(`
|
|
122
147
|
Deployed! ${launchUrl}`));
|
|
123
|
-
|
|
148
|
+
if (appUrl) {
|
|
149
|
+
console.log(pc.green(`App URL: ${appUrl}`));
|
|
150
|
+
}
|
|
151
|
+
return { launchUrl, appUrl, version };
|
|
124
152
|
}
|
|
125
153
|
async function registerDevApp(apiBase, token, appName, appTitle, appUrl) {
|
|
126
154
|
const appData = {
|
package/dist/index.js
CHANGED
|
@@ -226,29 +226,29 @@ async function main() {
|
|
|
226
226
|
switch (command) {
|
|
227
227
|
// Resource commands
|
|
228
228
|
case "plan":
|
|
229
|
-
await import("./resources-
|
|
229
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.plan(args.slice(1)));
|
|
230
230
|
break;
|
|
231
231
|
case "apply":
|
|
232
|
-
await import("./resources-
|
|
232
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.apply(args.slice(1)));
|
|
233
233
|
break;
|
|
234
234
|
case "pull":
|
|
235
|
-
await import("./resources-
|
|
235
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.pull(args.slice(1)));
|
|
236
236
|
break;
|
|
237
237
|
case "destroy":
|
|
238
|
-
await import("./resources-
|
|
238
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.destroy(args.slice(1)));
|
|
239
239
|
break;
|
|
240
240
|
case "list":
|
|
241
|
-
await import("./resources-
|
|
241
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.list(args.slice(1)));
|
|
242
242
|
break;
|
|
243
243
|
case "show":
|
|
244
|
-
await import("./resources-
|
|
244
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.show(args.slice(1)));
|
|
245
245
|
break;
|
|
246
246
|
case "diff":
|
|
247
|
-
await import("./resources-
|
|
247
|
+
await import("./resources-CGMBV3T6.js").then((m) => m.diff(args.slice(1)));
|
|
248
248
|
break;
|
|
249
249
|
// Development
|
|
250
250
|
case "dev":
|
|
251
|
-
await import("./dev-
|
|
251
|
+
await import("./dev-VWHFYKGC.js").then((m) => m.dev(args.slice(1)));
|
|
252
252
|
break;
|
|
253
253
|
case "run":
|
|
254
254
|
await import("./run-DJXAXDD2.js").then((m) => m.run(args.slice(1)));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deploy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-I7QEYKS7.js";
|
|
4
4
|
import {
|
|
5
5
|
syncDeps
|
|
6
6
|
} from "./chunk-3ESHIPZH.js";
|
|
@@ -2184,7 +2184,20 @@ async function applyApp(args) {
|
|
|
2184
2184
|
}
|
|
2185
2185
|
}
|
|
2186
2186
|
const distDir = resolve(projectRoot, "dist");
|
|
2187
|
-
|
|
2187
|
+
const accessLevel = getFlagValue(args, "access-level");
|
|
2188
|
+
const validAccessLevels = [
|
|
2189
|
+
"org_members_with_permission",
|
|
2190
|
+
"org_members",
|
|
2191
|
+
"invited",
|
|
2192
|
+
"signed_in",
|
|
2193
|
+
"public"
|
|
2194
|
+
];
|
|
2195
|
+
if (accessLevel && !validAccessLevels.includes(accessLevel)) {
|
|
2196
|
+
throw new Error(
|
|
2197
|
+
`Invalid --access-level "${accessLevel}". Valid values: ${validAccessLevels.join(", ")}`
|
|
2198
|
+
);
|
|
2199
|
+
}
|
|
2200
|
+
await deploy({ token, appName, appTitle, distDir, apiUrl, accessLevel });
|
|
2188
2201
|
}
|
|
2189
2202
|
async function pullCollections(api, platformDir, filterName, projectId) {
|
|
2190
2203
|
const collectionsDir = join2(platformDir, "collections");
|
package/package.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type HostPayload,
|
|
3
|
+
isEmbedded,
|
|
4
|
+
onInitMessage,
|
|
5
|
+
postReadyMessage,
|
|
6
|
+
redirectToLogin,
|
|
7
|
+
} from '@lumerahq/ui/lib';
|
|
2
8
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
3
9
|
import { createHashHistory, createRouter, RouterProvider } from '@tanstack/react-router';
|
|
4
10
|
import { StrictMode, useEffect, useRef, useState } from 'react';
|
|
@@ -60,24 +66,27 @@ function RouteRestorer() {
|
|
|
60
66
|
|
|
61
67
|
const App = () => {
|
|
62
68
|
const [hostContext, setHostContext] = useState<AuthContextValue | null>(null);
|
|
63
|
-
const [status, setStatus] = useState<'pending' | 'ready' | '
|
|
69
|
+
const [status, setStatus] = useState<'pending' | 'ready' | 'unauthenticated'>('pending');
|
|
64
70
|
|
|
65
71
|
useEffect(() => {
|
|
66
72
|
if (typeof window === 'undefined') return;
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
setStatus('denied');
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
74
|
+
// The bridge picks the transport automatically: postMessage when embedded
|
|
75
|
+
// in the Lumera shell, same-origin /api with the app-session cookie when
|
|
76
|
+
// served standalone on the app's own hostname, and direct dev fetch when
|
|
77
|
+
// VITE_DEV_API_BASE_URL is set.
|
|
76
78
|
const cleanup = onInitMessage((payload?: HostPayload) => {
|
|
79
|
+
if (!payload) {
|
|
80
|
+
// No identity and no app context: authentication is required
|
|
81
|
+
// (payload.user alone being undefined means an anonymous visitor on
|
|
82
|
+
// a public app — that still counts as ready).
|
|
83
|
+
setStatus('unauthenticated');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
77
86
|
setHostContext({
|
|
78
|
-
company: payload
|
|
79
|
-
user: payload
|
|
80
|
-
sessionToken: payload
|
|
87
|
+
company: payload.company,
|
|
88
|
+
user: payload.user,
|
|
89
|
+
sessionToken: payload.session?.token,
|
|
81
90
|
});
|
|
82
91
|
setStatus('ready');
|
|
83
92
|
});
|
|
@@ -99,16 +108,23 @@ const App = () => {
|
|
|
99
108
|
);
|
|
100
109
|
}
|
|
101
110
|
|
|
102
|
-
if (status === '
|
|
111
|
+
if (status === 'unauthenticated' || !hostContext) {
|
|
103
112
|
return (
|
|
104
113
|
<main className="flex min-h-screen items-center justify-center bg-background">
|
|
105
114
|
<div className="text-center space-y-3">
|
|
106
115
|
<div className="inline-flex size-12 rounded-xl bg-muted items-center justify-center mb-2">
|
|
107
|
-
<span className="text-2xl font-semibold text-muted-foreground">
|
|
116
|
+
<span className="text-2xl font-semibold text-muted-foreground">401</span>
|
|
108
117
|
</div>
|
|
109
|
-
<p className="text-sm text-muted-foreground">
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
<p className="text-sm text-muted-foreground">Sign in to access this app.</p>
|
|
119
|
+
{!isEmbedded() && (
|
|
120
|
+
<button
|
|
121
|
+
type="button"
|
|
122
|
+
className="text-sm font-medium text-primary underline underline-offset-4"
|
|
123
|
+
onClick={() => redirectToLogin()}
|
|
124
|
+
>
|
|
125
|
+
Sign in with Lumera
|
|
126
|
+
</button>
|
|
127
|
+
)}
|
|
112
128
|
</div>
|
|
113
129
|
</main>
|
|
114
130
|
);
|
|
@@ -20,6 +20,8 @@ export default defineConfig({
|
|
|
20
20
|
dedupe: ['react', 'react-dom'],
|
|
21
21
|
},
|
|
22
22
|
server: {
|
|
23
|
-
|
|
23
|
+
// Local platform host plus standalone app hostnames
|
|
24
|
+
// (<project>--<company>.<env-suffix> on lumerahq.app).
|
|
25
|
+
allowedHosts: ['mac.lumerahq.com', '.lumerahq.app'],
|
|
24
26
|
},
|
|
25
27
|
});
|