@thatopen/services 0.20.0 → 0.21.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/cli.js CHANGED
@@ -6812,6 +6812,9 @@ const OPS_SCHEMA = "revitflow/ops@1";
6812
6812
  const LEGACY_MODEL_FILE = "revitflow_model.frag";
6813
6813
  const INTERNAL_PREFIX = "revitflow_";
6814
6814
  const versionTag = () => `v-${Date.now()}`;
6815
+ function childrenOf(folders, parentId) {
6816
+ return folders.filter((f) => String(f.parentId ?? "") === parentId);
6817
+ }
6815
6818
  function idOf(item) {
6816
6819
  return String(item._id ?? item.id ?? "");
6817
6820
  }
@@ -6830,7 +6833,7 @@ class ProjectHistory {
6830
6833
  projectId: this.projectId
6831
6834
  });
6832
6835
  const docs = [];
6833
- for (const folder of folders) {
6836
+ for (const folder of childrenOf(folders, root)) {
6834
6837
  const name = String(folder.name ?? "");
6835
6838
  const dash = name.indexOf("-");
6836
6839
  if (dash <= 0) continue;
@@ -6937,7 +6940,7 @@ class FlowDoc {
6937
6940
  throw new StaleHistoryError(input.expectedLatestGuid, head?.guid);
6938
6941
  }
6939
6942
  const version2 = {
6940
- guid: cryptoRandomGuid(),
6943
+ guid: mintGuid(),
6941
6944
  ...head ? { parents: [head.guid] } : {},
6942
6945
  author: input.author,
6943
6946
  source: input.source,
@@ -6999,7 +7002,7 @@ class FlowDoc {
6999
7002
  const index = await this.#readOps() ?? { schema: OPS_SCHEMA, ops: [] };
7000
7003
  const indexFile = await this.#file(OPS_FILE);
7001
7004
  const suggestion = {
7002
- opId: cryptoRandomGuid(),
7005
+ opId: input.opId ?? mintGuid(),
7003
7006
  title: input.title,
7004
7007
  verb: input.verb,
7005
7008
  author: input.author,
@@ -7067,7 +7070,7 @@ class FlowDoc {
7067
7070
  parentFolderId: rootId,
7068
7071
  projectId: this.project.projectId
7069
7072
  });
7070
- const found = folders.find(
7073
+ const found = childrenOf(folders, rootId).find(
7071
7074
  (f) => String(f.name ?? "") === this.#folderName
7072
7075
  );
7073
7076
  if (found) {
@@ -7225,7 +7228,7 @@ function lastByGraph(versions) {
7225
7228
  const ordered = orderByGraph(versions);
7226
7229
  return ordered[ordered.length - 1];
7227
7230
  }
7228
- function cryptoRandomGuid() {
7231
+ function mintGuid() {
7229
7232
  const anyCrypto = globalThis.crypto;
7230
7233
  if (anyCrypto?.randomUUID) return anyCrypto.randomUUID();
7231
7234
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
@@ -7256,12 +7259,40 @@ class Recipes {
7256
7259
  get(name) {
7257
7260
  return this.#registry.get(name);
7258
7261
  }
7262
+ /**
7263
+ * Runs a recipe WITHOUT queueing anything: the dry pass. Returns the
7264
+ * recipe's result — title, tallies per rule, targets — so an app can show
7265
+ * what would be proposed before anybody confirms. The payload it may have
7266
+ * built is discarded along with its opId.
7267
+ */
7268
+ async plan(name, options) {
7269
+ const { result } = await this.#execute(name, options);
7270
+ return result;
7271
+ }
7259
7272
  /**
7260
7273
  * Runs a recipe and queues its suggestion on the target document. Safe to
7261
7274
  * call freely: nothing touches the native application until its owner
7262
- * accepts the suggestion there.
7275
+ * accepts the suggestion there. Use {@link plan} first when the app wants
7276
+ * to show the tallies before queueing.
7263
7277
  */
7264
7278
  async run(name, options) {
7279
+ const { targetDoc, base, opId, result } = await this.#execute(
7280
+ name,
7281
+ options
7282
+ );
7283
+ const suggestion = await targetDoc.suggest({
7284
+ opId,
7285
+ title: result.title,
7286
+ verb: result.verb,
7287
+ author: options.author,
7288
+ payload: result.payload,
7289
+ targets: result.targets,
7290
+ userId: options.userId,
7291
+ baseCommitGuid: base?.guid
7292
+ });
7293
+ return { suggestion, result };
7294
+ }
7295
+ async #execute(name, options) {
7265
7296
  const recipe = this.#registry.get(name);
7266
7297
  if (!recipe) throw new Error(`No recipe named "${name}" is registered.`);
7267
7298
  if (recipe.to !== options.target.source) {
@@ -7271,23 +7302,16 @@ class Recipes {
7271
7302
  }
7272
7303
  const targetDoc = this.client.history(options.projectId).doc(options.target.source, options.target.docId);
7273
7304
  const base = await targetDoc.latest();
7305
+ const opId = mintGuid();
7274
7306
  const result = await recipe.run({
7275
7307
  client: this.client,
7276
7308
  projectId: options.projectId,
7277
7309
  targetDoc,
7310
+ opId,
7278
7311
  input: options.input,
7279
7312
  settings: options.settings ?? {}
7280
7313
  });
7281
- const suggestion = await targetDoc.suggest({
7282
- title: result.title,
7283
- verb: result.verb,
7284
- author: options.author,
7285
- payload: result.payload,
7286
- targets: result.targets,
7287
- userId: options.userId,
7288
- baseCommitGuid: base?.guid
7289
- });
7290
- return { suggestion, result };
7314
+ return { recipe, targetDoc, base, opId, result };
7291
7315
  }
7292
7316
  }
7293
7317
  const STORAGE_BATCH_MAX = 100;