create-flow-os 0.0.23 → 0.0.25

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.
@@ -1,6 +1,6 @@
1
- {
2
- "files.exclude": {
3
- "**/node_modules": true,
4
- "**/index.html": true
5
- }
6
- }
1
+ {
2
+ "files.exclude": {
3
+ "**/node_modules": true,
4
+ "**/index.html": true
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "create-flow-os",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "license": "PolyForm-Shield-1.0.0",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@flow-os/client": "^0.0.23"
7
+ "@flow-os/client": "^0.0.25"
8
8
  },
9
9
  "bin": {
10
10
  "create-flow-os": "./src/index.ts"
package/prova.tsx ADDED
@@ -0,0 +1,2 @@
1
+ provaaaaa
2
+ sdwdw
package/src/init/index.ts CHANGED
@@ -3,8 +3,8 @@
3
3
  import * as readline from "readline";
4
4
  import { join, dirname } from "path";
5
5
  import { fileURLToPath } from "url";
6
- import { libsWithConfig, toShortName } from "./lib";
7
- import { initLib, fetchFlowClientVersion } from "./scaffold";
6
+ import { libsWithConfig, toShortName, toPkgName } from "./lib";
7
+ import { initLib, fetchFlowPackageVersions } from "./scaffold";
8
8
 
9
9
  // ───────────────────────────────────────────────────────────────────────────────
10
10
  // Usage: bun create flow-os i [lib...] | bun create flow-os i (prompt interattivo)
@@ -62,12 +62,13 @@ if (!toInit.length) {
62
62
  }
63
63
 
64
64
  // ───────────────────────────────────────────────────────────────────────────────
65
- // Execute: fetch versione client da npm (latest/dev), init libs, poi output box
65
+ // Execute: fetch versioni pacchetti da npm (latest/dev), init libs, poi output box
66
66
  // ───────────────────────────────────────────────────────────────────────────────
67
- process.stdout.write(V + "Fetching latest @flow-os/client..." + R);
68
- const clientVersion = await fetchFlowClientVersion();
69
- process.stdout.write(clientVersion ? ` ${V}${clientVersion}${R}\n` : " (fallback)\n");
70
- await initLib(toInit, cwd, clientVersion);
67
+ const pkgNames = toInit.map(toPkgName);
68
+ process.stdout.write(V + "Fetching latest @flow-os/* packages..." + R);
69
+ const versions = await fetchFlowPackageVersions(pkgNames);
70
+ process.stdout.write(versions.size ? ` ${V}${versions.size} pkg${R}\n` : " (fallback)\n");
71
+ await initLib(toInit, cwd, versions);
71
72
 
72
73
  const iconOk = V + "◆" + R;
73
74
  const iconUnrec = Y + "?" + R;
@@ -72,28 +72,67 @@ function isCreateFlowOsDev(): boolean {
72
72
  }
73
73
  }
74
74
 
75
- /** Recupera la versione di @flow-os/client dal registry npm in tempo reale (latest o dev) */
76
- export async function fetchFlowClientVersion(): Promise<string | undefined> {
75
+ /** Recupera versione di un pacchetto @flow-os/* dal registry npm (latest o dev) */
76
+ async function fetchFlowPackageVersion(pkgName: string): Promise<string | undefined> {
77
77
  const tag = isCreateFlowOsDev() ? "dev" : "latest";
78
78
  try {
79
- const res = await fetch(`${NPM_REGISTRY}/@flow-os/client?t=${Date.now()}`, {
79
+ const res = await fetch(`${NPM_REGISTRY}/${pkgName}?t=${Date.now()}`, {
80
80
  cache: "no-store",
81
81
  headers: { "Cache-Control": "no-cache", Pragma: "no-cache" },
82
82
  });
83
83
  if (!res.ok) return undefined;
84
84
  const data = (await res.json()) as { "dist-tags"?: Record<string, string> };
85
- const version = data["dist-tags"]?.[tag] ?? data["dist-tags"]?.["latest"];
86
- return version;
85
+ return data["dist-tags"]?.[tag] ?? data["dist-tags"]?.["latest"];
87
86
  } catch {
88
87
  return undefined;
89
88
  }
90
89
  }
91
90
 
91
+ /** Recupera versioni di tutti i pacchetti @flow-os/* richiesti dal registry npm */
92
+ export async function fetchFlowPackageVersions(pkgNames: string[]): Promise<Map<string, string>> {
93
+ const out = new Map<string, string>();
94
+ await Promise.all(
95
+ pkgNames.map(async (name) => {
96
+ const v = await fetchFlowPackageVersion(name);
97
+ if (v) out.set(name, v);
98
+ })
99
+ );
100
+ return out;
101
+ }
102
+
103
+ /** @deprecated Usa fetchFlowPackageVersions. Mantenuto per retrocompatibilità. */
104
+ export async function fetchFlowClientVersion(): Promise<string | undefined> {
105
+ return fetchFlowPackageVersion("@flow-os/client");
106
+ }
107
+
108
+ /** Scarica config da npm per qualsiasi @flow-os/* (bypass cache) */
109
+ async function fetchConfigFromNpm(
110
+ pkgName: string,
111
+ version: string
112
+ ): Promise<{ files: Map<string, string>; configDir: string; tmpDir: string } | null> {
113
+ const shortName = pkgName.replace(/^@flow-os\//, "");
114
+ const url = `${NPM_REGISTRY}/${pkgName}/-/${shortName}-${version}.tgz`;
115
+ try {
116
+ const res = await fetch(url, { cache: "no-store" });
117
+ if (!res.ok) return null;
118
+ const archive = new Bun.Archive(await res.blob());
119
+ const { tmpdir } = await import("os");
120
+ const tmpDir = join(tmpdir(), `flow-os-${shortName}-${version}-${Date.now()}`);
121
+ await archive.extract(tmpDir, { glob: ["package/config/**"] });
122
+ const configDir = join(tmpDir, "package", "config");
123
+ if (!existsSync(configDir)) return null;
124
+ const files = collectConfigFiles(configDir);
125
+ return { files, configDir, tmpDir };
126
+ } catch {
127
+ return null;
128
+ }
129
+ }
130
+
92
131
  /** Sostituisce workspace:* e 0.0.1 con versione concreta (workspace va bene solo dentro flow-os) */
93
132
  function resolveFlowDeps(
94
133
  deps: Record<string, string> | undefined,
95
134
  configDir: string,
96
- clientVersionFromNpm: string | undefined
135
+ versionsFromNpm: Map<string, string>
97
136
  ): Record<string, string> {
98
137
  if (!deps) return {};
99
138
  const resolved = { ...deps };
@@ -108,21 +147,13 @@ function resolveFlowDeps(
108
147
  for (const k of Object.keys(resolved)) {
109
148
  if (!k.startsWith("@flow-os/")) continue;
110
149
  const v = resolved[k];
111
- if (v !== "workspace:*" && v !== "0.0.1" && k !== "@flow-os/client") continue;
150
+ if (v !== "workspace:*" && v !== "0.0.1" && !versionsFromNpm.has(k)) continue;
112
151
  let spec: string | undefined;
113
- if (k === "@flow-os/client") {
114
- if (clientVersionFromNpm) {
115
- spec = isDevSpec ? "dev" : `^${clientVersionFromNpm}`;
116
- } else if (isDevSpec) {
117
- spec = "dev";
118
- } else {
119
- try {
120
- const root = pkgRoot(k);
121
- const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf-8")) as { version?: string };
122
- if (pkg.version) spec = `^${pkg.version}`;
123
- } catch {}
124
- if (!spec && ownerVersion) spec = `^${ownerVersion}`;
125
- }
152
+ const npmVer = versionsFromNpm.get(k);
153
+ if (npmVer) {
154
+ spec = isDevSpec && k === "@flow-os/client" ? "dev" : `^${npmVer}`;
155
+ } else if (k === "@flow-os/client" && isDevSpec) {
156
+ spec = "dev";
126
157
  } else {
127
158
  try {
128
159
  const root = pkgRoot(k);
@@ -136,7 +167,7 @@ function resolveFlowDeps(
136
167
  return resolved;
137
168
  }
138
169
 
139
- function mergePkg(configDir: string, cwd: string, clientVersionFromNpm: string | undefined): void {
170
+ function mergePkg(configDir: string, cwd: string, versionsFromNpm: Map<string, string>): void {
140
171
  const configPkg = join(configDir, "package.json");
141
172
  if (!existsSync(configPkg)) return;
142
173
  const targetPath = join(cwd, "package.json");
@@ -146,55 +177,128 @@ function mergePkg(configDir: string, cwd: string, clientVersionFromNpm: string |
146
177
  : { ...config, name: basename(cwd) || "flow-app" };
147
178
  target.dependencies = { ...target.dependencies, ...config.dependencies };
148
179
  target.devDependencies = { ...target.devDependencies, ...config.devDependencies };
149
- for (const [k, v] of Object.entries(resolveFlowDeps(config.dependencies, configDir, clientVersionFromNpm)))
180
+ for (const [k, v] of Object.entries(resolveFlowDeps(config.dependencies, configDir, versionsFromNpm)))
150
181
  target.dependencies[k] = v;
151
- for (const [k, v] of Object.entries(resolveFlowDeps(config.devDependencies, configDir, clientVersionFromNpm)))
182
+ for (const [k, v] of Object.entries(resolveFlowDeps(config.devDependencies, configDir, versionsFromNpm)))
152
183
  target.devDependencies[k] = v;
153
184
  target.scripts = { ...target.scripts, ...config.scripts };
154
185
  writeFileSync(targetPath, JSON.stringify(target, null, 2));
155
186
  }
156
187
 
188
+ /** Assicura che versions abbia le versioni per pkgNames (fetch lazy) */
189
+ async function ensureVersions(versions: Map<string, string>, pkgNames: string[]): Promise<void> {
190
+ const missing = pkgNames.filter((n) => !versions.has(n));
191
+ if (!missing.length) return;
192
+ const fetched = await fetchFlowPackageVersions(missing);
193
+ for (const [k, v] of fetched) versions.set(k, v);
194
+ }
195
+
196
+ /** Legge flow deps da package.json (path a package.json o dir che lo contiene) */
197
+ function flowDepsFromPkg(pkgPath: string): string[] {
198
+ const pkgJson = pkgPath.endsWith("package.json") ? pkgPath : join(pkgPath, "package.json");
199
+ if (!existsSync(pkgJson)) return [];
200
+ try {
201
+ const pkg = JSON.parse(readFileSync(pkgJson, "utf-8"));
202
+ const deps = { ...pkg.dependencies, ...pkg.peerDependencies } as Record<string, string>;
203
+ return Object.keys(deps).filter((k) => k.startsWith("@flow-os/"));
204
+ } catch {
205
+ return [];
206
+ }
207
+ }
208
+
157
209
  /** Fase 1: raccoglie e merge tutti i template in memoria, ritorna ordine pacchetti */
158
210
  async function collectAllTemplates(
159
211
  libs: string[],
160
212
  combined: Map<string, string>,
161
213
  done: Set<string>,
162
214
  order: string[],
163
- _clientVersionFromNpm?: string
215
+ versionsFromNpm: Map<string, string>,
216
+ tmpDirs: string[]
164
217
  ): Promise<void> {
165
218
  for (const lib of libs) {
166
219
  const pkgName = toPkgName(lib);
167
220
  if (done.has(pkgName)) continue;
168
221
 
169
- const root = pkgRoot(pkgName);
170
- const configDir = join(root, "config");
171
- if (!existsSync(configDir)) continue;
172
-
173
- for (const sub of flowDeps(root)) {
174
- await collectAllTemplates([toShortName(sub)], combined, done, order, _clientVersionFromNpm);
222
+ let root: string;
223
+ let configDir: string;
224
+ try {
225
+ root = pkgRoot(pkgName);
226
+ configDir = join(root, "config");
227
+ } catch {
228
+ root = "";
229
+ configDir = "";
175
230
  }
231
+ const hasLocal = existsSync(configDir);
176
232
 
177
- const pkgFiles = collectConfigFiles(configDir);
233
+ let pkgFiles: Map<string, string>;
234
+ let configDirForPkg: string;
235
+ const npmVer = versionsFromNpm.get(pkgName);
236
+ if (npmVer) {
237
+ const fetched = await fetchConfigFromNpm(pkgName, npmVer);
238
+ if (fetched) {
239
+ pkgFiles = fetched.files;
240
+ configDirForPkg = fetched.configDir;
241
+ tmpDirs.push(fetched.tmpDir);
242
+ const subDeps = flowDepsFromPkg(join(configDirForPkg, ".."));
243
+ await ensureVersions(versionsFromNpm, subDeps);
244
+ for (const sub of subDeps) {
245
+ await collectAllTemplates([toShortName(sub)], combined, done, order, versionsFromNpm, tmpDirs);
246
+ }
247
+ } else if (hasLocal) {
248
+ const subDeps = flowDeps(root);
249
+ await ensureVersions(versionsFromNpm, subDeps);
250
+ for (const sub of subDeps) {
251
+ await collectAllTemplates([toShortName(sub)], combined, done, order, versionsFromNpm, tmpDirs);
252
+ }
253
+ pkgFiles = collectConfigFiles(configDir);
254
+ configDirForPkg = configDir;
255
+ } else {
256
+ continue;
257
+ }
258
+ } else if (hasLocal) {
259
+ const subDeps = flowDeps(root);
260
+ await ensureVersions(versionsFromNpm, subDeps);
261
+ for (const sub of subDeps) {
262
+ await collectAllTemplates([toShortName(sub)], combined, done, order, versionsFromNpm, tmpDirs);
263
+ }
264
+ pkgFiles = collectConfigFiles(configDir);
265
+ configDirForPkg = configDir;
266
+ } else {
267
+ continue;
268
+ }
178
269
  mergeTemplateInto(combined, pkgFiles);
179
- order.push(configDir);
270
+ order.push(configDirForPkg);
180
271
  done.add(pkgName);
181
272
  }
182
273
  }
183
274
 
184
- /** Init: 1) merge tutti i template in memoria, 2) mergePkg per ogni lib, 3) un solo merge con file utente */
275
+ /** Init: 1) fetch versioni npm per tutti i pacchetti, 2) merge template in memoria, 3) mergePkg, 4) merge con file utente */
185
276
  export async function initLib(
186
277
  libs: string[],
187
278
  cwd: string,
188
- clientVersionFromNpm?: string
279
+ versionsFromNpm?: Map<string, string>
189
280
  ): Promise<void> {
281
+ const pkgNames = libs.map(toPkgName);
282
+ const versions = versionsFromNpm ?? new Map<string, string>();
283
+ const fetched = await fetchFlowPackageVersions(pkgNames);
284
+ for (const [k, v] of fetched) versions.set(k, v);
285
+
190
286
  const combined = new Map<string, string>();
191
287
  const done = new Set<string>();
192
288
  const order: string[] = [];
193
- await collectAllTemplates(libs, combined, done, order, clientVersionFromNpm);
289
+ const tmpDirs: string[] = [];
290
+ await collectAllTemplates(libs, combined, done, order, versions, tmpDirs);
194
291
 
195
292
  for (const configDir of order) {
196
- mergePkg(configDir, cwd, clientVersionFromNpm);
293
+ mergePkg(configDir, cwd, versions);
197
294
  }
198
295
 
199
296
  await writeMergedWithUser(combined, cwd, (path, conflicts) => resolveConflicts(conflicts, path));
297
+
298
+ const { rmSync } = await import("fs");
299
+ for (const d of tmpDirs) {
300
+ try {
301
+ rmSync(d, { recursive: true, force: true });
302
+ } catch {}
303
+ }
200
304
  }