@velven/cli 0.5.1 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ - `--type` and velven.json's `type` and `how_made` are gone: Velven no longer asks what kind of project it is, and the
6
+ page no longer shows a prompt. This version refuses them with a sentence; remove them from velven.json. A new space
7
+ needs only `title` and `devices`. Velven ignores both keys from older versions.
8
+
3
9
  ## 0.5.1
4
10
 
5
11
  - `velven create credits` names the free allowance as this week's: Velven's builder now refills it weekly, from Monday
package/README.md CHANGED
@@ -20,19 +20,18 @@ and neither is a `velven.json` in any folder below, whatever its letter case.
20
20
  ```json
21
21
  {
22
22
  "title": "Star Hop",
23
- "type": "game",
24
23
  "devices": ["desktop", "mobile"],
25
24
  "description": "Hop between stars before the light runs out.",
26
25
  "engine": "three.js"
27
26
  }
28
27
  ```
29
28
 
30
- Three fields are required: `title`, `type` (`game`, `world`, `tool` or `wonder`) and `devices` (`desktop`, `mobile`,
31
- `vr`). If one is missing and you're in a terminal, `velven publish` asks for it and saves your answer in `velven.json`.
32
- Anywhere else, it stops and lists each missing field.
29
+ Two fields are required: `title` and `devices` (`desktop`, `mobile`, `vr`). If one is missing and you're in a
30
+ terminal, `velven publish` asks for it and saves your answer in `velven.json`. Anywhere else, it stops and lists each
31
+ missing field. Since 0.6.0, a `velven.json` that still has `type` or `how_made` is refused with exit 2
32
+ (`invalid_config`): Velven no longer uses them, so remove them and publish again.
33
33
 
34
- The optional fields are `description`, `engine`, `ai_tools`, `models`, `how_made` and `source_url`, plus these for
35
- hosting:
34
+ The optional fields are `description`, `engine`, `ai_tools`, `models` and `source_url`, plus these for hosting:
36
35
 
37
36
  | Key | What it does |
38
37
  | --- | --- |
@@ -139,8 +138,8 @@ with exit 6 if it has one of these in it.
139
138
  live. A refused version prints the reason. A version Velven couldn't judge prints what Velven saw, and a start hint
140
139
  usually fixes it. Either way, you can ask for a review from the printed link. The exception is a program or a miner,
141
140
  which is never served: remove the file and publish again.
142
- - `--title`, `--type`, `--devices desktop,mobile`, `--description` and `--engine` override `velven.json` for this run
143
- only.
141
+ - `--title`, `--devices desktop,mobile`, `--description` and `--engine` override `velven.json` for this run only.
142
+ `--type` is refused with exit 2: Velven no longer asks what kind of project it is.
144
143
  - `--yes` never asks for missing fields. It fails and lists them instead.
145
144
  - `--json` prints one JSON object, for scripts and agents. It also works on `whoami` and `versions`.
146
145
 
package/dist/velven.js CHANGED
@@ -23,7 +23,7 @@ class CliError extends Error {
23
23
  }
24
24
  }
25
25
  // package.json
26
- var version = "0.5.1";
26
+ var version = "0.6.0";
27
27
 
28
28
  // src/version.ts
29
29
  var VERSION = version;
@@ -3155,7 +3155,6 @@ function mediaProblem(kind, path, size2, bytes, missing = "is not among the file
3155
3155
  // src/project.ts
3156
3156
  import { readdir, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
3157
3157
  import { join as join3, win32 } from "node:path";
3158
- var SPACE_TYPES = ["game", "world", "tool", "wonder"];
3159
3158
  var DEVICES = ["desktop", "mobile", "vr"];
3160
3159
  var PROJECT_FILE = "velven.json";
3161
3160
  var isProjectName = (name) => name.toLowerCase() === PROJECT_FILE;
@@ -3188,6 +3187,15 @@ async function readProject(dir) {
3188
3187
  }
3189
3188
  return { path, exists: true, data };
3190
3189
  }
3190
+ var RETIRED_KEYS = ["type", "how_made"];
3191
+ function refuseRetiredKeys(data) {
3192
+ const found = RETIRED_KEYS.filter((key) => data[key] !== undefined);
3193
+ if (!found.length)
3194
+ return;
3195
+ const named = found.map((key) => `"${key}"`).join(" and ");
3196
+ const sentence = found.length === 1 ? "Remove it and publish again." : "Remove them and publish again.";
3197
+ throw new CliError(`${PROJECT_FILE} has ${named}, which Velven no longer uses. ${sentence}`, EXIT.usage, "invalid_config");
3198
+ }
3191
3199
  async function updateProject(project, values) {
3192
3200
  for (const [key, value] of Object.entries(values)) {
3193
3201
  if (value === undefined)
@@ -3206,8 +3214,6 @@ function withFlags(data, flags) {
3206
3214
  const out = { ...data };
3207
3215
  if (flags.title !== undefined)
3208
3216
  out.title = flags.title;
3209
- if (flags.type !== undefined)
3210
- out.type = flags.type.trim().toLowerCase();
3211
3217
  if (flags.devices !== undefined)
3212
3218
  out.devices = list2(flags.devices);
3213
3219
  if (flags.description !== undefined)
@@ -3216,7 +3222,7 @@ function withFlags(data, flags) {
3216
3222
  out.engine = flags.engine;
3217
3223
  return out;
3218
3224
  }
3219
- var REQUIRED = ["title", "type", "devices"];
3225
+ var REQUIRED = ["title", "devices"];
3220
3226
  function requiredProblem(field, value) {
3221
3227
  if (value === undefined || value === null || value === "" || Array.isArray(value) && value.length === 0)
3222
3228
  return "missing";
@@ -3227,9 +3233,6 @@ function requiredProblem(field, value) {
3227
3233
  return "must be under 80 characters";
3228
3234
  return null;
3229
3235
  }
3230
- if (field === "type") {
3231
- return typeof value === "string" && SPACE_TYPES.includes(value) ? null : `must be one of ${SPACE_TYPES.join(", ")}`;
3232
- }
3233
3236
  if (!Array.isArray(value) || !value.every((d) => typeof d === "string" && DEVICES.includes(d))) {
3234
3237
  return `must be a list from ${DEVICES.join(", ")}, like ["desktop", "mobile"]`;
3235
3238
  }
@@ -3262,7 +3265,6 @@ var OPTIONAL = {
3262
3265
  engine: [isString, 'must be text, like "three.js"'],
3263
3266
  ai_tools: [isStringList, "must be a list of text"],
3264
3267
  models: [isStringList, "must be a list of text"],
3265
- how_made: [(v) => isString(v) && v.length <= 2000, "must be text, under 2000 characters"],
3266
3268
  source_url: [isString, "must be a web address"],
3267
3269
  entry: [isInsidePath, 'must be a path inside the folder, like "index.html"'],
3268
3270
  thumbnail: [isInsidePath, 'must be a path inside the folder, like "media/thumbnail.jpg"'],
@@ -3293,14 +3295,11 @@ function requiredProblems(data) {
3293
3295
  }
3294
3296
  var QUESTIONS = {
3295
3297
  title: "Title, the name people see on Velven: ",
3296
- type: `Type (${SPACE_TYPES.join(", ")}): `,
3297
3298
  devices: `Devices it works on, comma separated (${DEVICES.join(", ")}): `
3298
3299
  };
3299
3300
  function parseAnswer(field, answer) {
3300
3301
  if (field === "title")
3301
3302
  return answer.trim();
3302
- if (field === "type")
3303
- return answer.trim().toLowerCase();
3304
3303
  return list2(answer);
3305
3304
  }
3306
3305
  async function completeRequired(ctx, project, merged, canAsk) {
@@ -3865,8 +3864,8 @@ var DONE = ["live", "refused", "unjudged", "replaced", "preview"];
3865
3864
  var POLL_MS = 3000;
3866
3865
  var WAIT_LIMIT_MS = 20 * 60 * 1000;
3867
3866
  function listingFields(config) {
3868
- const fields = { title: config.title, space_type: config.type, devices: config.devices };
3869
- for (const key of ["description", "engine", "ai_tools", "models", "how_made", "source_url"]) {
3867
+ const fields = { title: config.title, devices: config.devices };
3868
+ for (const key of ["description", "engine", "ai_tools", "models", "source_url"]) {
3870
3869
  if (config[key] !== undefined)
3871
3870
  fields[key] = config[key];
3872
3871
  }
@@ -3925,6 +3924,7 @@ async function publish(ctx, options) {
3925
3924
  const creds = await findToken(ctx, base);
3926
3925
  const guest = !creds;
3927
3926
  const project = await readProject(dir);
3927
+ refuseRetiredKeys(project.data);
3928
3928
  const merged = withFlags(project.data, options);
3929
3929
  const shape = optionalProblems(merged);
3930
3930
  if (shape.length)
@@ -4209,6 +4209,7 @@ async function reset(ctx, options) {
4209
4209
  }
4210
4210
 
4211
4211
  // src/cli.ts
4212
+ var TYPE_FLAG_GONE = "--type is no longer an option: Velven no longer asks what kind of project it is. Run the command without it.";
4212
4213
  var HELP = `velven ${VERSION}: publish a folder to Velven.
4213
4214
 
4214
4215
  Usage:
@@ -4220,7 +4221,6 @@ Usage:
4220
4221
  (not signed in: an unlisted page with a claim token, no --prod)
4221
4222
  --wait Wait for the preview link, or with --prod until it is live
4222
4223
  --title <text> Override velven.json for this run
4223
- --type <type> game, world, tool or wonder
4224
4224
  --devices <list> desktop, mobile, vr (comma separated)
4225
4225
  --description <text>
4226
4226
  --engine <engine>
@@ -4261,18 +4261,21 @@ var COMMANDS = {
4261
4261
  description: "string",
4262
4262
  engine: "string"
4263
4263
  },
4264
- run: (ctx, p) => publish(ctx, {
4265
- dir: p.positionals[0],
4266
- prod: p.flags.prod === true,
4267
- wait: p.flags.wait === true,
4268
- yes: p.flags.yes === true,
4269
- json: p.flags.json === true,
4270
- title: stringFlag(p, "title"),
4271
- type: stringFlag(p, "type"),
4272
- devices: stringFlag(p, "devices"),
4273
- description: stringFlag(p, "description"),
4274
- engine: stringFlag(p, "engine")
4275
- })
4264
+ run: (ctx, p) => {
4265
+ if (p.flags.type !== undefined)
4266
+ throw new CliError(TYPE_FLAG_GONE, EXIT.usage, "usage");
4267
+ return publish(ctx, {
4268
+ dir: p.positionals[0],
4269
+ prod: p.flags.prod === true,
4270
+ wait: p.flags.wait === true,
4271
+ yes: p.flags.yes === true,
4272
+ json: p.flags.json === true,
4273
+ title: stringFlag(p, "title"),
4274
+ devices: stringFlag(p, "devices"),
4275
+ description: stringFlag(p, "description"),
4276
+ engine: stringFlag(p, "engine")
4277
+ });
4278
+ }
4276
4279
  },
4277
4280
  versions: {
4278
4281
  flags: { json: "boolean", space: "string" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velven/cli",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Publish a folder to Velven, the community marketplace for spaces built with AI: a private preview first, then hosted and live on its own page in seconds.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://velven.ai/docs",