@minnovate/shadow-publisher 0.17.2 → 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.2",
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"]
@@ -203,6 +203,10 @@ following, for when the person asks not to wait.
203
203
  moment between the merge and the publish. Run `publisher sync . --json` once more
204
204
  (`publication.next.command` says the same).
205
205
  - `REF_FORBIDDEN`: the user may not publish this branch; tell them which branch and stop.
206
+ When it comes as `error.code` with a `hint`, a limit of the organization refused it: tell them
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.
206
210
  - `MISSING_OBJECTS`: the local copy is incomplete (for example a shallow clone). Tell the user to
207
211
  publish from a complete copy: `publisher checkout <new folder> --repo <id>`.
208
212
  - `LIMIT_EXCEEDED`, `PACK_INVALID`: quote the message; suggest removing very large files from the
@@ -50,7 +50,8 @@ publisher answer <question id>=<value> --json
50
50
 
51
51
  A value that is not an option is refused before anything is sent; `error.details.questions` lists
52
52
  the choices. Exit 4 means this sign-in may not answer (an owner or admin can, or the app's creator for the
53
- first preparation after an adoption); exit 3 means ask
53
+ first preparation after an adoption); when it carries a `hint`, a limit refused it, so tell them the reason
54
+ and whom to ask that the `hint` gives. Exit 3 means ask
54
55
  again. Then `publisher follow . --publication <id> --until-change --timeout 100 --json` to see it go live, telling them each step as `publish-app` step 4 says.
55
56
 
56
57
  ## When it did not go live because of a fault on our side
@@ -74,7 +75,7 @@ publisher history --json # the versions that went live, newest
74
75
  publisher go-back <version> --json # ask the person first; puts that version's code back
75
76
  publisher suggestions --json # what colleagues asked for, still open
76
77
  publisher suggestion decline <id> --json # when the person does not want one
77
- 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
78
79
  publisher columns <id> --json # the column names of connected data, before code reads it
79
80
  publisher data add <sheet link> --app <app> --name "<name>" --json # a Google sheet the app reads
80
81
  publisher data remove <id> --app <app> --json # the app stops reading that data
@@ -90,7 +91,7 @@ terminal, do what it says with the command that does the same thing:
90
91
  | `app_history` / `go_back` | `publisher history --json` / `publisher go-back <version> --json` |
91
92
  | `list_starters` / `use_starter` | `publisher starters` / `publisher start <starter>` |
92
93
  | `resolve_suggestion` | `publisher suggestion done\|decline <id> --json` |
93
- | `share_app` | `publisher share <access> --json` |
94
+ | `share_app` | `publisher share <app-rule> --json` |
94
95
  | `list_apps` | `publisher list --json` |
95
96
  | `data_columns` | `publisher columns <id> --json` |
96
97
  | `connect_data_source` | `publisher data add <sheet link> --app <app> --name "<name>" --json` |
@@ -226,7 +226,7 @@ var PublisherError = class _PublisherError extends Error {
226
226
  }
227
227
  };
228
228
 
229
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/util.js
229
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/util.js
230
230
  function getEnumValues(entries) {
231
231
  const numericValues = Object.values(entries).filter((v) => typeof v === "number");
232
232
  const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
@@ -461,6 +461,18 @@ function prefixIssues(path, issues) {
461
461
  function unwrapMessage(message) {
462
462
  return typeof message === "string" ? message : message?.message;
463
463
  }
464
+ function sizeCaps(defChecks) {
465
+ const caps = [];
466
+ for (const ch of defChecks ?? []) {
467
+ const d = ch._zod.def;
468
+ if (!/_(length|size)$|_equals$/.test(d.check))
469
+ break;
470
+ const max = d.maximum ?? d.length ?? d.size;
471
+ if (max >= 0)
472
+ caps.push([max, ch]);
473
+ }
474
+ return caps;
475
+ }
464
476
  function attachSchema(issues, start2, inst) {
465
477
  var _a2;
466
478
  for (let i = start2; i < issues.length; i++) {
@@ -636,7 +648,7 @@ function installLazyProp(inst, key, make, enumerable) {
636
648
  });
637
649
  }
638
650
 
639
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/core.js
651
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/core.js
640
652
  var _a;
641
653
  var _zodDesc = { value: void 0, enumerable: false };
642
654
  var _E = "captureStackTrace" in Error ? Error : null;
@@ -748,7 +760,7 @@ function config(newConfig) {
748
760
  return globalConfig;
749
761
  }
750
762
 
751
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/errors.js
763
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/errors.js
752
764
  function _getMessage() {
753
765
  const internals = this._zod;
754
766
  internals.message ?? (internals.message = JSON.stringify(internals.def, jsonStringifyReplacer, 2));
@@ -793,7 +805,7 @@ var $ZodRealError = $constructor("$ZodError", initializer, void 0, {
793
805
  Parent: Error
794
806
  });
795
807
 
796
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/parse.js
808
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/parse.js
797
809
  var _parse = (_Err) => {
798
810
  const fn = (schema, value, _ctx, _params) => {
799
811
  const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
@@ -864,7 +876,7 @@ var _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
864
876
  };
865
877
  var safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
866
878
 
867
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/regexes.js
879
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/regexes.js
868
880
  var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
869
881
  var httpProtocol = /^https?$/;
870
882
  var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
@@ -892,7 +904,7 @@ var anyString = /^[\s\S]{0,}$/;
892
904
  var number = /^-?\d+(?:\.\d+)?$/;
893
905
  var boolean = /^(?:true|false)$/i;
894
906
 
895
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/checks.js
907
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/checks.js
896
908
  var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
897
909
  var _a2;
898
910
  inst._zod ?? (inst._zod = {});
@@ -1081,14 +1093,14 @@ var $ZodCheckRegex = /* @__PURE__ */ $constructor("$ZodCheckRegex", (inst, def)
1081
1093
  };
1082
1094
  });
1083
1095
 
1084
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/versions.js
1096
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/versions.js
1085
1097
  var version = {
1086
1098
  major: 4,
1087
1099
  minor: 6,
1088
- patch: 5
1100
+ patch: 7
1089
1101
  };
1090
1102
 
1091
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/schemas.js
1103
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/schemas.js
1092
1104
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
1093
1105
  var _a2;
1094
1106
  inst ?? (inst = {});
@@ -1423,6 +1435,29 @@ var $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
1423
1435
  $ZodType.init(inst, def);
1424
1436
  inst._zod.parse = (payload) => payload;
1425
1437
  });
1438
+ function capSize(inst, size) {
1439
+ const caps = sizeCaps(inst._zod.def.checks);
1440
+ if (!caps.length)
1441
+ return;
1442
+ const cap = Math.min(...caps.map((c) => c[0]));
1443
+ const parse3 = inst._zod.parse;
1444
+ inst._zod.parse = (payload, ctx) => {
1445
+ const n = size(payload.value);
1446
+ if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
1447
+ for (const [max, ch] of sizeCaps(inst._zod.def.checks)) {
1448
+ if (n > max && ch._zod.def.when(payload)) {
1449
+ const start2 = payload.issues.length;
1450
+ ch._zod.check(payload);
1451
+ payload.issues[start2].continue = false;
1452
+ attachSchema(payload.issues, start2, inst);
1453
+ return payload;
1454
+ }
1455
+ }
1456
+ }
1457
+ return parse3(payload, ctx);
1458
+ };
1459
+ }
1460
+ var arraySize = (input) => Array.isArray(input) ? input.length : -1;
1426
1461
  function handleArrayResult(result, final, index) {
1427
1462
  if (result.issues.length) {
1428
1463
  final.issues.push(...prefixIssues(index, result.issues));
@@ -1466,6 +1501,7 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
1466
1501
  }
1467
1502
  return payload;
1468
1503
  };
1504
+ capSize(inst, arraySize);
1469
1505
  });
1470
1506
  function handlePropertyResult(result, final, key, input, optin, optout) {
1471
1507
  const isPresent = key in input;
@@ -2098,7 +2134,7 @@ function handleRefineResult(result, payload, input, inst) {
2098
2134
  }
2099
2135
  }
2100
2136
 
2101
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/en.js
2137
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/en.js
2102
2138
  var error = () => {
2103
2139
  const Sizable = {
2104
2140
  string: { unit: "characters", verb: "to have" },
@@ -2223,7 +2259,7 @@ function en_default() {
2223
2259
  };
2224
2260
  }
2225
2261
 
2226
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/api.js
2262
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/api.js
2227
2263
  function snapshotChecks(def) {
2228
2264
  if (def.checks)
2229
2265
  def.checks = [...def.checks];
@@ -2369,7 +2405,7 @@ function _refine(Class, fn, _params) {
2369
2405
  return schema;
2370
2406
  }
2371
2407
 
2372
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/mini/schemas.js
2408
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/mini/schemas.js
2373
2409
  var ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
2374
2410
  if (!inst._zod)
2375
2411
  throw new Error("Uninitialized schema in ZodMiniType.");
@@ -2614,7 +2650,7 @@ function refine(fn, _params = {}) {
2614
2650
  return _refine(ZodMiniCustom, fn, _params);
2615
2651
  }
2616
2652
 
2617
- // ../../../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/mini/iso.js
2653
+ // ../../../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/mini/iso.js
2618
2654
  var iso_exports = {};
2619
2655
  __export(iso_exports, {
2620
2656
  ZodMiniISODate: () => ZodMiniISODate,
@@ -5185,7 +5221,7 @@ var PortalSession = class {
5185
5221
  continue;
5186
5222
  }
5187
5223
  }
5188
- return { ...answer2, merged: answer2.status === 403 ? mergedSay(answer2.body) : null };
5224
+ return { ...answer2, say: answer2.status === 403 ? mergedSay(answer2.body) ?? featureOffSay(answer2.body) : null };
5189
5225
  }
5190
5226
  }
5191
5227
  };
@@ -5219,6 +5255,21 @@ function mergedSay(body) {
5219
5255
  const say = isRecord(details) ? details["say"] : void 0;
5220
5256
  return typeof say === "string" && say !== "" ? say : null;
5221
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
+ }
5222
5273
 
5223
5274
  // ../client/src/portal-refusal.ts
5224
5275
  function portalRefusalCode(body) {
@@ -5235,6 +5286,16 @@ function portalRefusalCode(body) {
5235
5286
  const { code, message } = error2;
5236
5287
  return typeof code === "string" && code !== "" && typeof message === "string" ? code : null;
5237
5288
  }
5289
+ function portalRefusalLimit(body) {
5290
+ const error2 = isRecord(body) ? body["error"] : null;
5291
+ const details = isRecord(error2) ? error2["details"] : null;
5292
+ if (!isRecord(details)) {
5293
+ return null;
5294
+ }
5295
+ const text = (value) => typeof value === "string" && value !== "" ? value : null;
5296
+ const limit = { permission: text(details["permission"]), reason: text(details["reason"]), contact: text(details["contact"]) };
5297
+ return limit.permission === null && limit.reason === null && limit.contact === null ? null : limit;
5298
+ }
5238
5299
 
5239
5300
  // ../client/src/application.ts
5240
5301
  var APPLICATION_CREATION = "application-creation";
@@ -5258,7 +5319,12 @@ async function createApplication(input, opts) {
5258
5319
  throw new PublisherError("UNAUTHORIZED", 'the portal did not accept this credential; run "publisher login" again');
5259
5320
  }
5260
5321
  if (answer2.status === 403) {
5261
- throw new PublisherError("FORBIDDEN", answer2.merged ?? `the portal refused to make an application here (${code || "forbidden"})`);
5322
+ const limit = portalRefusalLimit(answer2.body);
5323
+ throw new PublisherError(
5324
+ "FORBIDDEN",
5325
+ answer2.say ?? `the portal refused to make an application here (${limit?.permission ?? (code || "forbidden")})`,
5326
+ limit === null ? {} : { details: limit }
5327
+ );
5262
5328
  }
5263
5329
  if (answer2.status === 409 && REFUSALS[code] !== void 0) {
5264
5330
  throw new PublisherError(REFUSALS[code], `the portal refused the repository (${code})`, { details: { portal: code } });
@@ -5491,7 +5557,7 @@ async function followRun(input, opts) {
5491
5557
  return { kind: "unavailable", reason: "no-route" };
5492
5558
  }
5493
5559
  if (answer2.status === 403) {
5494
- return { kind: "forbidden", say: answer2.merged };
5560
+ return { kind: "forbidden", say: answer2.say, limit: portalRefusalLimit(answer2.body) };
5495
5561
  }
5496
5562
  if (answer2.status === 200) {
5497
5563
  const run2 = soleRun(answer2.body);
@@ -5601,7 +5667,7 @@ async function call(input, opts, body) {
5601
5667
  return { kind: "unauthorized" };
5602
5668
  }
5603
5669
  if (answer2.status === 403) {
5604
- return { kind: "forbidden", say: answer2.merged };
5670
+ return { kind: "forbidden", say: answer2.say, limit: portalRefusalLimit(answer2.body) };
5605
5671
  }
5606
5672
  if (answer2.status === 409) {
5607
5673
  return { kind: "moved-on" };
@@ -5706,7 +5772,7 @@ async function runCreatorTool(input, opts) {
5706
5772
  return { kind: "unauthorized" };
5707
5773
  }
5708
5774
  if (answer2.status === 403) {
5709
- return { kind: "forbidden", say: answer2.merged };
5775
+ return { kind: "forbidden", say: answer2.say, limit: portalRefusalLimit(answer2.body) };
5710
5776
  }
5711
5777
  if (answer2.status === 404) {
5712
5778
  return { kind: "unavailable", detail: "the portal does not serve this tool" };
@@ -5719,7 +5785,8 @@ async function runCreatorTool(input, opts) {
5719
5785
  return { kind: "malformed", detail: "an answer with no say and next" };
5720
5786
  }
5721
5787
  const { say, next, isError, ...fields } = body;
5722
- 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 } };
5723
5790
  }
5724
5791
 
5725
5792
  // ../client/src/onboard.ts
@@ -6997,6 +7064,30 @@ async function discoverEndpoint(portal, fetchImpl = fetch) {
6997
7064
  return endpoint;
6998
7065
  }
6999
7066
 
7067
+ // src/limited.ts
7068
+ var REFUSED = /* @__PURE__ */ new Set(["REF_FORBIDDEN", "FORBIDDEN"]);
7069
+ var Limited = class _Limited {
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. */
7071
+ static hint(code, details) {
7072
+ const feature = details?.["feature"];
7073
+ if (REFUSED.has(code) && typeof feature === "string" && feature !== "") {
7074
+ return featureOffWords(feature);
7075
+ }
7076
+ const lines = REFUSED.has(code) ? _Limited.lines(details) : [];
7077
+ return lines.length === 0 ? null : lines.join("\n ");
7078
+ }
7079
+ /** The same words in one line, for a sentence that a 403 ends, such as the one `follow` relays; '' for none. */
7080
+ static inline(details) {
7081
+ return _Limited.lines(details).join(" ");
7082
+ }
7083
+ static lines(details) {
7084
+ const text = (value) => typeof value === "string" && value.trim() !== "" ? value.trim() : null;
7085
+ const reason = text(details?.["reason"]);
7086
+ const contact = text(details?.["contact"]);
7087
+ return [reason === null ? null : `The organization's reason: ${reason}`, contact === null ? null : `Ask ${contact}.`].filter((line) => line !== null);
7088
+ }
7089
+ };
7090
+
7000
7091
  // src/portal.ts
7001
7092
  var confirmed = /* @__PURE__ */ new Map();
7002
7093
  async function confirmedPortal(endpoint, opts = {}) {
@@ -7235,8 +7326,11 @@ function progressHint(r, portal, answerable = false) {
7235
7326
  return inPortal(portal, "Published. This portal cannot show progress in the terminal yet.", "Follow it");
7236
7327
  case "unauthorized":
7237
7328
  return inPortal(portal, "Published, but the portal did not accept this sign-in (run publisher login).", "Follow it");
7238
- case "forbidden":
7239
- return inPortal(portal, r.say === null ? "Published, but the portal would not show this sign-in the run." : `Published. ${r.say}`, "Follow it");
7329
+ case "forbidden": {
7330
+ const limited = Limited.inline(r.limit);
7331
+ const lead = r.say === null ? "Published, but the portal would not show this sign-in the run." : `Published. ${r.say}`;
7332
+ return inPortal(portal, limited === "" ? lead : `${lead} ${limited}`, "Follow it");
7333
+ }
7240
7334
  case "malformed":
7241
7335
  return inPortal(portal, `Published, but the portal's answer about the run could not be read (${r.detail}).`, "Follow it");
7242
7336
  }
@@ -7922,7 +8016,7 @@ async function questionAt(p, endpoint, repoId, opts = {}) {
7922
8016
  if ("reason" in at) {
7923
8017
  return at;
7924
8018
  }
7925
- return shown(at.portal, await p.readPreparation({ portal: at.portal, repoId }));
8019
+ return shown(at.portal, await p.readPreparation({ portal: at.portal, repoId }), REFUSED2.read);
7926
8020
  }
7927
8021
  async function answerAt(p, endpoint, repoId, specs, opts = {}) {
7928
8022
  const answers = parseSpecs(specs);
@@ -7930,7 +8024,7 @@ async function answerAt(p, endpoint, repoId, specs, opts = {}) {
7930
8024
  if ("reason" in at) {
7931
8025
  return at;
7932
8026
  }
7933
- const read2 = shown(at.portal, await p.readPreparation({ portal: at.portal, repoId }));
8027
+ const read2 = shown(at.portal, await p.readPreparation({ portal: at.portal, repoId }), REFUSED2.read);
7934
8028
  if (read2.kind !== "view") {
7935
8029
  return read2;
7936
8030
  }
@@ -7949,7 +8043,7 @@ async function answerAt(p, endpoint, repoId, specs, opts = {}) {
7949
8043
  throw new PublisherError("INVALID_REQUEST", `"${value}" is not one of ${values.join(", ")} for "${id}"`, { details: { questions: read2.questions } });
7950
8044
  }
7951
8045
  }
7952
- return shown(at.portal, await p.answerPreparation({ portal: at.portal, repoId, id: read2.preparation.id, revision: read2.preparation.revision, answers }));
8046
+ return shown(at.portal, await p.answerPreparation({ portal: at.portal, repoId, id: read2.preparation.id, revision: read2.preparation.revision, answers }), REFUSED2.answer);
7953
8047
  }
7954
8048
  async function retryAt(p, endpoint, repoId, opts = {}) {
7955
8049
  const read2 = await questionAt(p, endpoint, repoId, opts);
@@ -7962,7 +8056,7 @@ async function retryAt(p, endpoint, repoId, opts = {}) {
7962
8056
  if (!read2.preparation.canRetry) {
7963
8057
  throw new PublisherError("LOCAL_STATE", "this version cannot be tried again: only one that stopped because of a fault on our side can, three times at most");
7964
8058
  }
7965
- const tried = shown(read2.portal, await p.retryPreparation({ portal: read2.portal, repoId, id: read2.preparation.id, revision: read2.preparation.revision }));
8059
+ const tried = shown(read2.portal, await p.retryPreparation({ portal: read2.portal, repoId, id: read2.preparation.id, revision: read2.preparation.revision }), REFUSED2.retry);
7966
8060
  return tried.kind === "view" ? { ...tried, hint: "It is being tried again. Run: publisher follow, or watch it in the portal." } : tried;
7967
8061
  }
7968
8062
  function parseSpecs(specs) {
@@ -7995,7 +8089,12 @@ async function portalAt(endpoint, opts) {
7995
8089
  };
7996
8090
  }
7997
8091
  }
7998
- function shown(portal, r) {
8092
+ var REFUSED2 = {
8093
+ read: "the portal will not show this sign-in the preparation in this organization",
8094
+ answer: "the portal will not let this sign-in answer for this organization (an owner or admin can, or the app's creator for the first preparation after an adoption)",
8095
+ retry: "the portal will not let this sign-in try it again in this organization (an owner or admin can, or the app's creator, except for the first preparation after an adoption)"
8096
+ };
8097
+ function shown(portal, r, refused) {
7999
8098
  switch (r.kind) {
8000
8099
  case "view": {
8001
8100
  const { questions, ...preparation } = r.view;
@@ -8008,10 +8107,7 @@ function shown(portal, r) {
8008
8107
  case "unauthorized":
8009
8108
  throw new PublisherError("UNAUTHORIZED", "the portal did not accept this sign-in; run publisher login");
8010
8109
  case "forbidden":
8011
- throw new PublisherError(
8012
- "FORBIDDEN",
8013
- r.say ?? "the portal will not let this sign-in answer for this organization (an owner or admin can, or the app's creator for the first preparation after an adoption)"
8014
- );
8110
+ throw new PublisherError("FORBIDDEN", r.say ?? refused, r.limit === null ? {} : { details: r.limit });
8015
8111
  case "unavailable":
8016
8112
  throw new PublisherError("UNAVAILABLE", `the portal could not be asked: ${r.detail}`, { retryable: true });
8017
8113
  case "malformed":
@@ -8094,7 +8190,11 @@ async function creatorTool(p, endpoint, tool, args, opts = {}) {
8094
8190
  case "unauthorized":
8095
8191
  throw new PublisherError("UNAUTHORIZED", "the portal did not accept this sign-in; run publisher login");
8096
8192
  case "forbidden":
8097
- throw new PublisherError("FORBIDDEN", result.say ?? "the portal will not let this sign-in do that in this organization");
8193
+ throw new PublisherError(
8194
+ "FORBIDDEN",
8195
+ result.say ?? "the portal will not let this sign-in do that in this organization",
8196
+ result.limit === null ? {} : { details: result.limit }
8197
+ );
8098
8198
  case "unavailable":
8099
8199
  throw new PublisherError("UNAVAILABLE", `the portal could not be asked: ${result.detail}`, { retryable: true });
8100
8200
  case "malformed":
@@ -8177,15 +8277,23 @@ var columns = {
8177
8277
  git: false,
8178
8278
  run: (inv) => run(inv, void 0, "data_columns", inv.cmd[1] === void 0 ? {} : { id: inv.cmd[1] })
8179
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
+ }
8180
8291
  var share = {
8181
8292
  git: false,
8182
8293
  async run(inv) {
8183
- const access2 = inv.cmd[1];
8184
- if (access2 === void 0) {
8185
- throw new PublisherError("INVALID_REQUEST", "share takes organization, invited or anyone-with-link");
8186
- }
8294
+ appRuleOf(inv.cmd);
8187
8295
  const { dir, app } = await folderApp(inv);
8188
- 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")));
8189
8297
  }
8190
8298
  };
8191
8299
  function dataCall(cmd, app, name) {
@@ -8566,7 +8674,7 @@ Usage:
8566
8674
  (the data and who can open the app stay as they are)
8567
8675
  publisher suggestions what colleagues suggested for this folder's app, still open
8568
8676
  publisher suggestion done|decline <id> [--run <id>] close one; sync --answers <id> closes it with that publication
8569
- publisher share organization|invited|anyone-with-link [--add <emails>] [--remove <emails>]
8677
+ publisher share members|emails|link [--add <emails>] [--remove <emails>]
8570
8678
  who can open this folder's app; new invitees get the link by mail
8571
8679
  publisher columns [<id>] the column names of connected data, for the code that reads it;
8572
8680
  its first rows only to an owner or admin who allowed that
@@ -8667,7 +8775,7 @@ main(process.argv.slice(2)).then(
8667
8775
  (e) => {
8668
8776
  const json = process.argv.includes("--json");
8669
8777
  if (e instanceof PublisherError) {
8670
- const moved = Moved.hint(e.code, e.details);
8778
+ const moved = Moved.hint(e.code, e.details) ?? Limited.hint(e.code, e.details);
8671
8779
  const payload = { error: { code: e.code, message: e.message, retryable: e.retryable, details: e.details ?? null }, ...moved === null ? {} : { hint: moved } };
8672
8780
  const hint = e.code === "NETWORK" ? `
8673
8781
  if this folder's service moved, "publisher doctor" says where to` : moved === null ? "" : `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minnovate/shadow-publisher",
3
- "version": "0.17.2",
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",