@minnovate/shadow-publisher 0.17.3 → 0.18.1

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,7 +1,7 @@
1
1
  {
2
2
  "name": "git-publisher",
3
3
  "displayName": "Git Publisher",
4
- "version": "0.17.3",
4
+ "version": "0.18.1",
5
5
  "description": "Publish an app folder's Git history to the serverless Git publishing backend and keep it updated (\"publish my app\", \"update my app\", \"fetch the engineered version\").",
6
6
  "author": { "name": "git-publisher project" },
7
7
  "keywords": ["git", "publish", "deploy", "serverless"]
@@ -205,6 +205,8 @@ following, for when the person asks not to wait.
205
205
  - `REF_FORBIDDEN`: the user may not publish this branch; tell them which branch and stop.
206
206
  When it comes as `error.code` with a `hint`, a limit of the organization refused it: tell them
207
207
  the reason and whom to ask that the `hint` gives, and stop.
208
+ When `error.details.feature` names a feature, that feature is off for the organization: pass on
209
+ the `hint` as it is, and stop. Nobody in the organization can turn it on, so name nobody to ask.
208
210
  - `MISSING_OBJECTS`: the local copy is incomplete (for example a shallow clone). Tell the user to
209
211
  publish from a complete copy: `publisher checkout <new folder> --repo <id>`.
210
212
  - `LIMIT_EXCEEDED`, `PACK_INVALID`: quote the message; suggest removing very large files from the
@@ -75,7 +75,7 @@ publisher history --json # the versions that went live, newest
75
75
  publisher go-back <version> --json # ask the person first; puts that version's code back
76
76
  publisher suggestions --json # what colleagues asked for, still open
77
77
  publisher suggestion decline <id> --json # when the person does not want one
78
- publisher share invited --add ann@example.com --json # who can open it
78
+ publisher share emails --add ann@example.com --json # who can open it
79
79
  publisher columns <id> --json # the column names of connected data, before code reads it
80
80
  publisher data add <sheet link> --app <app> --name "<name>" --json # a Google sheet the app reads
81
81
  publisher data remove <id> --app <app> --json # the app stops reading that data
@@ -91,7 +91,7 @@ terminal, do what it says with the command that does the same thing:
91
91
  | `app_history` / `go_back` | `publisher history --json` / `publisher go-back <version> --json` |
92
92
  | `list_starters` / `use_starter` | `publisher starters` / `publisher start <starter>` |
93
93
  | `resolve_suggestion` | `publisher suggestion done\|decline <id> --json` |
94
- | `share_app` | `publisher share <access> --json` |
94
+ | `share_app` | `publisher share <app-rule> --json` |
95
95
  | `list_apps` | `publisher list --json` |
96
96
  | `data_columns` | `publisher columns <id> --json` |
97
97
  | `connect_data_source` | `publisher data add <sheet link> --app <app> --name "<name>" --json` |
@@ -5221,7 +5221,7 @@ var PortalSession = class {
5221
5221
  continue;
5222
5222
  }
5223
5223
  }
5224
- return { ...answer2, merged: answer2.status === 403 ? mergedSay(answer2.body) : null };
5224
+ return { ...answer2, say: answer2.status === 403 ? mergedSay(answer2.body) ?? featureOffSay(answer2.body) : null };
5225
5225
  }
5226
5226
  }
5227
5227
  };
@@ -5255,6 +5255,21 @@ function mergedSay(body) {
5255
5255
  const say = isRecord(details) ? details["say"] : void 0;
5256
5256
  return typeof say === "string" && say !== "" ? say : null;
5257
5257
  }
5258
+ var TERMINAL_FEATURE = "terminal";
5259
+ function featureOffSay(body) {
5260
+ const error2 = isRecord(body) ? body["error"] : void 0;
5261
+ if (!isRecord(error2) || error2["code"] !== "feature-unavailable") {
5262
+ return null;
5263
+ }
5264
+ return featureOffWords(isRecord(error2["details"]) ? error2["details"]["feature"] : void 0);
5265
+ }
5266
+ function featureOffWords(feature) {
5267
+ if (feature === TERMINAL_FEATURE) {
5268
+ return "The publisher command is not available for this organization, and nobody in it can turn it on.";
5269
+ }
5270
+ const named = typeof feature === "string" && feature !== "" ? ` (the feature "${feature}")` : "";
5271
+ return `This is not available for this organization${named}, and nobody in it can turn it on.`;
5272
+ }
5258
5273
 
5259
5274
  // ../client/src/portal-refusal.ts
5260
5275
  function portalRefusalCode(body) {
@@ -5307,7 +5322,7 @@ async function createApplication(input, opts) {
5307
5322
  const limit = portalRefusalLimit(answer2.body);
5308
5323
  throw new PublisherError(
5309
5324
  "FORBIDDEN",
5310
- answer2.merged ?? `the portal refused to make an application here (${limit?.permission ?? (code || "forbidden")})`,
5325
+ answer2.say ?? `the portal refused to make an application here (${limit?.permission ?? (code || "forbidden")})`,
5311
5326
  limit === null ? {} : { details: limit }
5312
5327
  );
5313
5328
  }
@@ -5542,7 +5557,7 @@ async function followRun(input, opts) {
5542
5557
  return { kind: "unavailable", reason: "no-route" };
5543
5558
  }
5544
5559
  if (answer2.status === 403) {
5545
- return { kind: "forbidden", say: answer2.merged, limit: portalRefusalLimit(answer2.body) };
5560
+ return { kind: "forbidden", say: answer2.say, limit: portalRefusalLimit(answer2.body) };
5546
5561
  }
5547
5562
  if (answer2.status === 200) {
5548
5563
  const run2 = soleRun(answer2.body);
@@ -5652,7 +5667,7 @@ async function call(input, opts, body) {
5652
5667
  return { kind: "unauthorized" };
5653
5668
  }
5654
5669
  if (answer2.status === 403) {
5655
- return { kind: "forbidden", say: answer2.merged, limit: portalRefusalLimit(answer2.body) };
5670
+ return { kind: "forbidden", say: answer2.say, limit: portalRefusalLimit(answer2.body) };
5656
5671
  }
5657
5672
  if (answer2.status === 409) {
5658
5673
  return { kind: "moved-on" };
@@ -5757,7 +5772,7 @@ async function runCreatorTool(input, opts) {
5757
5772
  return { kind: "unauthorized" };
5758
5773
  }
5759
5774
  if (answer2.status === 403) {
5760
- return { kind: "forbidden", say: answer2.merged, limit: portalRefusalLimit(answer2.body) };
5775
+ return { kind: "forbidden", say: answer2.say, limit: portalRefusalLimit(answer2.body) };
5761
5776
  }
5762
5777
  if (answer2.status === 404) {
5763
5778
  return { kind: "unavailable", detail: "the portal does not serve this tool" };
@@ -5770,7 +5785,8 @@ async function runCreatorTool(input, opts) {
5770
5785
  return { kind: "malformed", detail: "an answer with no say and next" };
5771
5786
  }
5772
5787
  const { say, next, isError, ...fields } = body;
5773
- return { kind: "answer", answer: { say, next, isError: isError === true, fields } };
5788
+ const told = isError === true && fields["code"] === "feature-unavailable" ? featureOffWords(fields["feature"]) : say;
5789
+ return { kind: "answer", answer: { say: told, next, isError: isError === true, fields } };
5774
5790
  }
5775
5791
 
5776
5792
  // ../client/src/onboard.ts
@@ -7053,6 +7069,10 @@ var REFUSED = /* @__PURE__ */ new Set(["REF_FORBIDDEN", "FORBIDDEN"]);
7053
7069
  var Limited = class _Limited {
7054
7070
  /** The lines for a refusal with `code` and `details`, or null when it is not a permission's or names no reason and no contact. */
7055
7071
  static hint(code, details) {
7072
+ const feature = details?.["feature"];
7073
+ if (REFUSED.has(code) && typeof feature === "string" && feature !== "") {
7074
+ return featureOffWords(feature);
7075
+ }
7056
7076
  const lines = REFUSED.has(code) ? _Limited.lines(details) : [];
7057
7077
  return lines.length === 0 ? null : lines.join("\n ");
7058
7078
  }
@@ -8257,15 +8277,23 @@ var columns = {
8257
8277
  git: false,
8258
8278
  run: (inv) => run(inv, void 0, "data_columns", inv.cmd[1] === void 0 ? {} : { id: inv.cmd[1] })
8259
8279
  };
8280
+ var APP_RULES = ["members", "emails", "link"];
8281
+ function shareArgs(cmd, app, add, remove) {
8282
+ return { app, appRule: appRuleOf(cmd), add, remove };
8283
+ }
8284
+ function appRuleOf(cmd) {
8285
+ const named = APP_RULES.find((rule) => rule === cmd[1]);
8286
+ if (named === void 0) {
8287
+ throw new PublisherError("INVALID_REQUEST", "share takes members, emails or link");
8288
+ }
8289
+ return named;
8290
+ }
8260
8291
  var share = {
8261
8292
  git: false,
8262
8293
  async run(inv) {
8263
- const access2 = inv.cmd[1];
8264
- if (access2 === void 0) {
8265
- throw new PublisherError("INVALID_REQUEST", "share takes organization, invited or anyone-with-link");
8266
- }
8294
+ appRuleOf(inv.cmd);
8267
8295
  const { dir, app } = await folderApp(inv);
8268
- return run(inv, dir, "share_app", { app, access: access2, add: listFlag(inv, "add"), remove: listFlag(inv, "remove") });
8296
+ return run(inv, dir, "share_app", shareArgs(inv.cmd, app, listFlag(inv, "add"), listFlag(inv, "remove")));
8269
8297
  }
8270
8298
  };
8271
8299
  function dataCall(cmd, app, name) {
@@ -8646,7 +8674,7 @@ Usage:
8646
8674
  (the data and who can open the app stay as they are)
8647
8675
  publisher suggestions what colleagues suggested for this folder's app, still open
8648
8676
  publisher suggestion done|decline <id> [--run <id>] close one; sync --answers <id> closes it with that publication
8649
- publisher share organization|invited|anyone-with-link [--add <emails>] [--remove <emails>]
8677
+ publisher share members|emails|link [--add <emails>] [--remove <emails>]
8650
8678
  who can open this folder's app; new invitees get the link by mail
8651
8679
  publisher columns [<id>] the column names of connected data, for the code that reads it;
8652
8680
  its first rows only to an owner or admin who allowed that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minnovate/shadow-publisher",
3
- "version": "0.17.3",
3
+ "version": "0.18.1",
4
4
  "description": "publisher: publish an app's Git history to the serverless Git backend",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",