@sanity/runtime-cli 17.0.0 → 17.1.0-next.gcfbd613

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.
Files changed (81) hide show
  1. package/README.md +24 -23
  2. package/dist/actions/blueprints/assets.d.ts +2 -1
  3. package/dist/actions/blueprints/assets.js +2 -2
  4. package/dist/actions/blueprints/blueprint.d.ts +1 -1
  5. package/dist/actions/blueprints/wait-for-operation.js +4 -0
  6. package/dist/actions/functions/test.js +1 -1
  7. package/dist/actions/sanity/examples.d.ts +4 -4
  8. package/dist/baseCommands.d.ts +4 -4
  9. package/dist/baseCommands.js +13 -2
  10. package/dist/commands/blueprints/add.d.ts +1 -1
  11. package/dist/commands/blueprints/config.d.ts +1 -1
  12. package/dist/commands/blueprints/deploy.d.ts +1 -1
  13. package/dist/commands/blueprints/destroy.d.ts +1 -1
  14. package/dist/commands/blueprints/doctor.d.ts +0 -1
  15. package/dist/commands/blueprints/doctor.js +3 -7
  16. package/dist/commands/blueprints/info.d.ts +1 -1
  17. package/dist/commands/blueprints/logs.d.ts +1 -1
  18. package/dist/commands/blueprints/mint-deploy-token.d.ts +1 -1
  19. package/dist/commands/blueprints/plan.d.ts +1 -1
  20. package/dist/commands/blueprints/promote.d.ts +1 -1
  21. package/dist/commands/blueprints/stacks.d.ts +1 -1
  22. package/dist/commands/functions/add.d.ts +1 -1
  23. package/dist/commands/functions/build.d.ts +1 -1
  24. package/dist/commands/functions/dev.d.ts +1 -1
  25. package/dist/commands/functions/env/add.d.ts +1 -1
  26. package/dist/commands/functions/env/list.d.ts +1 -1
  27. package/dist/commands/functions/env/remove.d.ts +1 -1
  28. package/dist/commands/functions/logs.d.ts +1 -1
  29. package/dist/commands/functions/test.d.ts +1 -1
  30. package/dist/config.d.ts +1 -0
  31. package/dist/config.js +7 -1
  32. package/dist/constants.d.ts +1 -0
  33. package/dist/constants.js +1 -0
  34. package/dist/cores/blueprints/deploy.js +5 -4
  35. package/dist/cores/blueprints/doctor.js +15 -12
  36. package/dist/cores/functions/build.js +3 -2
  37. package/dist/cores/functions/test.js +48 -2
  38. package/dist/server/app.js +39 -5
  39. package/dist/server/handlers/invoke.d.ts +2 -2
  40. package/dist/server/handlers/invoke.js +7 -4
  41. package/dist/server/static/components/console-panel.js +59 -8
  42. package/dist/server/static/components/rule-panel.js +11 -8
  43. package/dist/server/static/components/shared-styles.js +24 -21
  44. package/dist/server/static/favicon-dark.svg +1 -0
  45. package/dist/server/static/favicon.svg +1 -0
  46. package/dist/server/static/index.html +2 -2
  47. package/dist/server/static/vendor/vendor.bundle.js +115 -61
  48. package/dist/server/static/web-socket.js +41 -0
  49. package/dist/utils/functions/child-process-wrapper.js +62 -7
  50. package/dist/utils/functions/find-entry-point.d.ts +1 -1
  51. package/dist/utils/functions/find-entry-point.js +10 -12
  52. package/dist/utils/functions/{invoke-local.d.ts → invoke/local.d.ts} +1 -1
  53. package/dist/utils/functions/invoke/local.js +306 -0
  54. package/dist/utils/functions/invoke/nested.d.ts +25 -0
  55. package/dist/utils/functions/invoke/nested.js +41 -0
  56. package/dist/utils/functions/invoke/prepare.d.ts +20 -0
  57. package/dist/utils/functions/invoke/prepare.js +101 -0
  58. package/dist/utils/functions/package-json.d.ts +1 -2
  59. package/dist/utils/functions/package-json.js +4 -6
  60. package/dist/utils/functions/prepare-asset.d.ts +2 -2
  61. package/dist/utils/functions/prepare-asset.js +18 -7
  62. package/dist/utils/functions/resolve-dependencies.d.ts +4 -1
  63. package/dist/utils/functions/resolve-dependencies.js +5 -6
  64. package/dist/utils/functions/resource-to-arc.d.ts +1 -1
  65. package/dist/utils/functions/resource-to-arc.js +4 -5
  66. package/dist/utils/functions/should-transpile.d.ts +7 -1
  67. package/dist/utils/functions/should-transpile.js +10 -10
  68. package/dist/utils/functions/transpile/function.d.ts +4 -1
  69. package/dist/utils/functions/transpile/function.js +9 -14
  70. package/dist/utils/functions/transpile/verify-handler.js +1 -1
  71. package/dist/utils/isTrueish.d.ts +6 -0
  72. package/dist/utils/isTrueish.js +9 -0
  73. package/dist/utils/logger.d.ts +7 -5
  74. package/dist/utils/logger.js +33 -1
  75. package/dist/utils/progress.d.ts +5 -0
  76. package/dist/utils/progress.js +40 -0
  77. package/dist/utils/types.d.ts +67 -5
  78. package/oclif.manifest.json +5 -4
  79. package/package.json +28 -23
  80. package/dist/server/static/hot-reload.js +0 -16
  81. package/dist/utils/functions/invoke-local.js +0 -185
@@ -4515,7 +4515,7 @@ function nextClusterBreak(str, pos, includeExtending) {
4515
4515
  }
4516
4516
 
4517
4517
  function prevClusterBreak(str, pos, includeExtending) {
4518
- while (pos > 0) {
4518
+ while (pos > 1) {
4519
4519
  let found = nextClusterBreak(str, pos - 2, includeExtending);
4520
4520
  if (found < pos) return found
4521
4521
  pos--;
@@ -5797,10 +5797,18 @@ class SelectionRange {
5797
5797
  /**
5798
5798
  The upper boundary of the range.
5799
5799
  */
5800
- to, flags) {
5800
+ to, flags,
5801
+ /**
5802
+ The goal column (stored vertical offset) associated with a
5803
+ cursor. This is used to preserve the vertical position when
5804
+ [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across
5805
+ lines of different length.
5806
+ */
5807
+ goalColumn) {
5801
5808
  this.from = from;
5802
5809
  this.to = to;
5803
5810
  this.flags = flags;
5811
+ this.goalColumn = goalColumn;
5804
5812
  }
5805
5813
  /**
5806
5814
  The anchor of the range—the side that doesn't move when you
@@ -5824,6 +5832,16 @@ class SelectionRange {
5824
5832
  */
5825
5833
  get assoc() { return this.flags & 8 /* RangeFlag.AssocBefore */ ? -1 : this.flags & 16 /* RangeFlag.AssocAfter */ ? 1 : 0; }
5826
5834
  /**
5835
+ A flag that, when set, makes some selection-extending commands
5836
+ treat the range's head and anchor as exchangeable, so that for
5837
+ example Shift-ArrowUp will make the lower side of the selection
5838
+ the anchor, even if that was the head before. Used to implement
5839
+ MacOS-style undirectional selections.
5840
+ */
5841
+ get undirectional() {
5842
+ return (this.flags & 64 /* RangeFlag.Undirectional */) > 0;
5843
+ }
5844
+ /**
5827
5845
  The bidirectional text level associated with this cursor, if
5828
5846
  any.
5829
5847
  */
@@ -5832,16 +5850,6 @@ class SelectionRange {
5832
5850
  return level == 7 ? null : level;
5833
5851
  }
5834
5852
  /**
5835
- The goal column (stored vertical offset) associated with a
5836
- cursor. This is used to preserve the vertical position when
5837
- [moving](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) across
5838
- lines of different length.
5839
- */
5840
- get goalColumn() {
5841
- let value = this.flags >> 6 /* RangeFlag.GoalColumnOffset */;
5842
- return value == 16777215 /* RangeFlag.NoGoalColumn */ ? undefined : value;
5843
- }
5844
- /**
5845
5853
  Map this range through a change, producing a valid range in the
5846
5854
  updated document.
5847
5855
  */
@@ -5854,7 +5862,7 @@ class SelectionRange {
5854
5862
  from = change.mapPos(this.from, 1);
5855
5863
  to = change.mapPos(this.to, -1);
5856
5864
  }
5857
- return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags);
5865
+ return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags, this.goalColumn);
5858
5866
  }
5859
5867
  /**
5860
5868
  Extend this range to cover at least `from` to `to`.
@@ -5888,8 +5896,8 @@ class SelectionRange {
5888
5896
  /**
5889
5897
  @internal
5890
5898
  */
5891
- static create(from, to, flags) {
5892
- return new SelectionRange(from, to, flags);
5899
+ static create(from, to, flags, goalColumn) {
5900
+ return new SelectionRange(from, to, flags, goalColumn);
5893
5901
  }
5894
5902
  }
5895
5903
  /**
@@ -6004,19 +6012,26 @@ class EditorSelection {
6004
6012
  */
6005
6013
  static cursor(pos, assoc = 0, bidiLevel, goalColumn) {
6006
6014
  return SelectionRange.create(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 8 /* RangeFlag.AssocBefore */ : 16 /* RangeFlag.AssocAfter */) |
6007
- (bidiLevel == null ? 7 : Math.min(6, bidiLevel)) |
6008
- ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */));
6015
+ (bidiLevel == null ? 7 : Math.min(6, bidiLevel)), goalColumn);
6009
6016
  }
6010
6017
  /**
6011
6018
  Create a selection range.
6012
6019
  */
6013
6020
  static range(anchor, head, goalColumn, bidiLevel, assoc) {
6014
- let flags = ((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215 /* RangeFlag.NoGoalColumn */) << 6 /* RangeFlag.GoalColumnOffset */) |
6015
- (bidiLevel == null ? 7 : Math.min(6, bidiLevel));
6021
+ let flags = bidiLevel == null ? 7 : Math.min(6, bidiLevel);
6016
6022
  if (!assoc && anchor != head)
6017
6023
  assoc = head < anchor ? 1 : -1;
6018
- return head < anchor ? SelectionRange.create(head, anchor, 32 /* RangeFlag.Inverted */ | 16 /* RangeFlag.AssocAfter */ | flags)
6019
- : SelectionRange.create(anchor, head, (!assoc ? 0 : assoc < 0 ? 8 /* RangeFlag.AssocBefore */ : 16 /* RangeFlag.AssocAfter */) | flags);
6024
+ if (assoc)
6025
+ flags |= assoc < 0 ? 8 /* RangeFlag.AssocBefore */ : 16 /* RangeFlag.AssocAfter */;
6026
+ return head < anchor ? SelectionRange.create(head, anchor, flags | 32 /* RangeFlag.Inverted */, goalColumn)
6027
+ : SelectionRange.create(anchor, head, flags, goalColumn);
6028
+ }
6029
+ /**
6030
+ Create an [undirectional](https://codemirror.net/6/docs/ref/#state.SelectionRange.undirectional)
6031
+ selection range.
6032
+ */
6033
+ static undirectionalRange(from, to) {
6034
+ return SelectionRange.create(from, to, 64 /* RangeFlag.Undirectional */, undefined);
6020
6035
  }
6021
6036
  /**
6022
6037
  @internal
@@ -6188,6 +6203,7 @@ class FacetProvider {
6188
6203
  }
6189
6204
  };
6190
6205
  }
6206
+ get extension() { return this; }
6191
6207
  }
6192
6208
  function compareArray(a, b, compare) {
6193
6209
  if (a.length != b.length)
@@ -6385,6 +6401,7 @@ class PrecExtension {
6385
6401
  this.inner = inner;
6386
6402
  this.prec = prec;
6387
6403
  }
6404
+ get extension() { return this; }
6388
6405
  }
6389
6406
  /**
6390
6407
  Extension compartments can be used to make a configuration
@@ -6419,6 +6436,7 @@ class CompartmentInstance {
6419
6436
  this.compartment = compartment;
6420
6437
  this.inner = inner;
6421
6438
  }
6439
+ get extension() { return this; }
6422
6440
  }
6423
6441
  class Configuration {
6424
6442
  constructor(base, compartments, dynamicSlots, address, staticValues, facets) {
@@ -6528,6 +6546,8 @@ function flatten(extension, compartments, newCompartments) {
6528
6546
  else {
6529
6547
  let content = ext.extension;
6530
6548
  if (!content)
6549
+ throw new Error(`Unrecognized extension value in extension set (${ext}).`);
6550
+ if (content == ext)
6531
6551
  throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);
6532
6552
  inner(content, prec);
6533
6553
  }
@@ -11521,10 +11541,12 @@ class TileUpdate {
11521
11541
  }
11522
11542
  pendingLineAttrs = null;
11523
11543
  }
11544
+ markCount = active.length;
11524
11545
  }
11525
11546
  });
11526
- b.addLineStartIfNotCovered(pendingLineAttrs);
11527
11547
  this.openWidget = openEnd > markCount;
11548
+ if (!this.openWidget)
11549
+ b.addLineStartIfNotCovered(pendingLineAttrs);
11528
11550
  this.openMarks = openEnd;
11529
11551
  }
11530
11552
  forward(from, to, side = 1) {
@@ -12349,7 +12371,7 @@ function groupAt(state, pos, bias = 1) {
12349
12371
  break;
12350
12372
  to = next;
12351
12373
  }
12352
- return EditorSelection.range(from + line.from, to + line.from);
12374
+ return EditorSelection.undirectionalRange(from + line.from, to + line.from);
12353
12375
  }
12354
12376
  function posAtCoordsImprecise(view, contentRect, block, x, y) {
12355
12377
  let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
@@ -12486,8 +12508,12 @@ function skipAtomsForSelection(atoms, sel) {
12486
12508
  else {
12487
12509
  let from = skipAtomicRanges(atoms, range.from, -1);
12488
12510
  let to = skipAtomicRanges(atoms, range.to, 1);
12489
- if (from != range.from || to != range.to)
12490
- updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
12511
+ if (from != range.from || to != range.to) {
12512
+ if (range.undirectional)
12513
+ updated = EditorSelection.undirectionalRange(range.from, range.to);
12514
+ else
12515
+ updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
12516
+ }
12491
12517
  }
12492
12518
  if (updated) {
12493
12519
  if (!ranges)
@@ -12893,7 +12919,8 @@ class DOMChange {
12893
12919
  // Chrome will put the selection *inside* them, confusing
12894
12920
  // posFromDOM
12895
12921
  let vp = view.viewport;
12896
- if ((browser.ios || browser.chrome) && curSel.main.empty && head != anchor &&
12922
+ if ((browser.ios || browser.chrome) && head != anchor &&
12923
+ Math.min(head, anchor) <= curSel.main.from && Math.max(head, anchor) >= curSel.main.to &&
12897
12924
  (vp.from > 0 || vp.to < view.state.doc.length)) {
12898
12925
  let from = Math.min(head, anchor), to = Math.max(head, anchor);
12899
12926
  let offFrom = vp.from - from, offTo = vp.to - to;
@@ -13214,13 +13241,11 @@ class InputState {
13214
13241
  // (after which we retroactively handle them and reset the DOM) to
13215
13242
  // avoid messing up the virtual keyboard state.
13216
13243
  this.pendingIOSKey = undefined;
13217
- /**
13218
- When enabled (>-1), tab presses are not given to key handlers,
13219
- leaving the browser's default behavior. If >0, the mode expires
13220
- at that timestamp, and any other keypress clears it.
13221
- Esc enables temporary tab focus mode for two seconds when not
13222
- otherwise handled.
13223
- */
13244
+ // When enabled (>-1), tab presses are not given to key handlers,
13245
+ // leaving the browser's default behavior. If >0, the mode expires
13246
+ // at that timestamp, and any other keypress clears it.
13247
+ // Esc enables temporary tab focus mode for two seconds when not
13248
+ // otherwise handled.
13224
13249
  this.tabFocusMode = -1;
13225
13250
  this.lastSelectionOrigin = null;
13226
13251
  this.lastSelectionTime = 0;
@@ -13328,11 +13353,16 @@ class InputState {
13328
13353
  // state. So we let it go through, and then, in
13329
13354
  // applyDOMChange, notify key handlers of it and reset to
13330
13355
  // the state they produce.
13331
- let pending;
13332
- if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey &&
13333
- ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
13356
+ if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey &&
13357
+ (PendingKeys.some(key => key.keyCode == event.keyCode) && !event.ctrlKey ||
13334
13358
  EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
13335
- this.pendingIOSKey = pending || event;
13359
+ let mods = { ctrlKey: event.ctrlKey, altKey: event.altKey, metaKey: event.metaKey, shiftKey: event.shiftKey };
13360
+ // On iOS with autocapitalize, drop the shift modifier for these
13361
+ // keys, since it will be set at the start of every sentence.
13362
+ if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
13363
+ iosVirtualKeyboardOpen(this.view.win))
13364
+ mods.shiftKey = false;
13365
+ this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
13336
13366
  setTimeout(() => this.flushIOSKey(), 250);
13337
13367
  return true;
13338
13368
  }
@@ -13348,7 +13378,7 @@ class InputState {
13348
13378
  if (key.key == "Enter" && change && change.from < change.to && /^\S+$/.test(change.insert.toString()))
13349
13379
  return false;
13350
13380
  this.pendingIOSKey = undefined;
13351
- return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : undefined);
13381
+ return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key.mods);
13352
13382
  }
13353
13383
  ignoreDuringComposition(event) {
13354
13384
  if (!/^key/.test(event.type) || event.synthetic)
@@ -13386,6 +13416,11 @@ class InputState {
13386
13416
  this.mouseSelection.destroy();
13387
13417
  }
13388
13418
  }
13419
+ function iosVirtualKeyboardOpen(win) {
13420
+ if (!win.visualViewport)
13421
+ return false;
13422
+ return win.visualViewport.height * win.visualViewport.scale / win.document.documentElement.clientHeight < 0.85;
13423
+ }
13389
13424
  function bindHandler(plugin, handler) {
13390
13425
  return (view, event) => {
13391
13426
  try {
@@ -13705,7 +13740,7 @@ function rangeForClick(view, pos, bias, type) {
13705
13740
  let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to;
13706
13741
  if (to < view.state.doc.length && to == line.to)
13707
13742
  to++;
13708
- return EditorSelection.range(from, to);
13743
+ return EditorSelection.undirectionalRange(from, to);
13709
13744
  }
13710
13745
  }
13711
13746
  const BadMouseDetail = browser.ie && browser.ie_version <= 11;
@@ -13763,7 +13798,7 @@ handlers.dragstart = (view, event) => {
13763
13798
  if (tile && tile.isWidget()) {
13764
13799
  let from = tile.posAtStart, to = from + tile.length;
13765
13800
  if (from >= range.to || to <= range.from)
13766
- range = EditorSelection.range(from, to);
13801
+ range = EditorSelection.undirectionalRange(from, to);
13767
13802
  }
13768
13803
  }
13769
13804
  let { inputState } = view;
@@ -16388,7 +16423,6 @@ class EditContextManager {
16388
16423
  for (let event in this.handlers)
16389
16424
  context.addEventListener(event, this.handlers[event]);
16390
16425
  this.measureReq = { read: view => {
16391
- this.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
16392
16426
  let sel = getSelection(view.root);
16393
16427
  if (sel && sel.rangeCount)
16394
16428
  this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
@@ -20524,8 +20558,7 @@ function topNodeAt(state, pos, side) {
20524
20558
  }
20525
20559
  /**
20526
20560
  A subclass of [`Language`](https://codemirror.net/6/docs/ref/#language.Language) for use with Lezer
20527
- [LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser)
20528
- parsers.
20561
+ [LR parsers](https://lezer.codemirror.net/docs/ref#lr.LRParser).
20529
20562
  */
20530
20563
  class LRLanguage extends Language {
20531
20564
  constructor(data, parser, name) {
@@ -21498,18 +21531,25 @@ const foldState = /*@__PURE__*/StateField.define({
21498
21531
  if (tr.isUserEvent("delete"))
21499
21532
  tr.changes.iterChangedRanges((fromA, toA) => folded = clearTouchedFolds(folded, fromA, toA));
21500
21533
  folded = folded.map(tr.changes);
21534
+ let rangesToFold = [];
21501
21535
  for (let e of tr.effects) {
21502
21536
  if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) {
21503
- let { preparePlaceholder } = tr.state.facet(foldConfig);
21504
- let widget = !preparePlaceholder ? foldWidget :
21505
- Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, e.value)) });
21506
- folded = folded.update({ add: [widget.range(e.value.from, e.value.to)] });
21537
+ rangesToFold.push(e.value);
21507
21538
  }
21508
21539
  else if (e.is(unfoldEffect)) {
21509
21540
  folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to,
21510
21541
  filterFrom: e.value.from, filterTo: e.value.to });
21511
21542
  }
21512
21543
  }
21544
+ if (rangesToFold.length) {
21545
+ let { preparePlaceholder } = tr.state.facet(foldConfig);
21546
+ let decorations = rangesToFold.map(value => {
21547
+ let widget = !preparePlaceholder ? foldWidget :
21548
+ Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, value)) });
21549
+ return widget.range(value.from, value.to);
21550
+ });
21551
+ folded = folded.update({ add: decorations });
21552
+ }
21513
21553
  // Clear folded ranges that cover the selection head
21514
21554
  if (tr.selection)
21515
21555
  folded = clearTouchedFolds(folded, tr.selection.main.head);
@@ -21825,7 +21865,7 @@ class HighlightStyle {
21825
21865
  or array of tags in their `tag` property, and either a single
21826
21866
  `class` property providing a static CSS class (for highlighter
21827
21867
  that rely on external styling), or a
21828
- [`style-mod`](https://github.com/marijnh/style-mod#documentation)-style
21868
+ [`style-mod`](https://code.haverbeke.berlin/marijn/style-mod#documentation)-style
21829
21869
  set of CSS properties (which define the styling for those tags).
21830
21870
 
21831
21871
  The CSS rules created for a highlighter will be emitted in the
@@ -23038,8 +23078,10 @@ Move the selection to the bracket matching the one it is currently
23038
23078
  on, if any.
23039
23079
  */
23040
23080
  const cursorMatchingBracket = ({ state, dispatch }) => toMatchingBracket(state, dispatch);
23041
- function extendSel(target, how) {
23081
+ function extendSel(target, forward, how) {
23042
23082
  let selection = updateSel(target.state.selection, range => {
23083
+ if (range.undirectional && (range.head >= range.anchor) != forward)
23084
+ range = EditorSelection.range(range.head, range.anchor);
23043
23085
  let head = how(range);
23044
23086
  return EditorSelection.range(range.anchor, head.head, head.goalColumn, head.bidiLevel || undefined, head.assoc);
23045
23087
  });
@@ -23049,7 +23091,7 @@ function extendSel(target, how) {
23049
23091
  return true;
23050
23092
  }
23051
23093
  function selectByChar(view, forward) {
23052
- return extendSel(view, range => view.moveByChar(range, forward));
23094
+ return extendSel(view, forward, range => view.moveByChar(range, forward));
23053
23095
  }
23054
23096
  /**
23055
23097
  Move the selection head one character to the left, while leaving
@@ -23061,7 +23103,7 @@ Move the selection head one character to the right.
23061
23103
  */
23062
23104
  const selectCharRight = view => selectByChar(view, ltrAtCursor(view));
23063
23105
  function selectByGroup(view, forward) {
23064
- return extendSel(view, range => view.moveByGroup(range, forward));
23106
+ return extendSel(view, forward, range => view.moveByGroup(range, forward));
23065
23107
  }
23066
23108
  /**
23067
23109
  Move the selection head one [group](https://codemirror.net/6/docs/ref/#commands.cursorGroupLeft) to
@@ -23075,13 +23117,19 @@ const selectGroupRight = view => selectByGroup(view, ltrAtCursor(view));
23075
23117
  /**
23076
23118
  Move the selection head over the next syntactic element to the left.
23077
23119
  */
23078
- const selectSyntaxLeft = view => extendSel(view, range => moveBySyntax(view.state, range, !ltrAtCursor(view)));
23120
+ const selectSyntaxLeft = view => {
23121
+ let forward = !ltrAtCursor(view);
23122
+ return extendSel(view, forward, range => moveBySyntax(view.state, range, forward));
23123
+ };
23079
23124
  /**
23080
23125
  Move the selection head over the next syntactic element to the right.
23081
23126
  */
23082
- const selectSyntaxRight = view => extendSel(view, range => moveBySyntax(view.state, range, ltrAtCursor(view)));
23127
+ const selectSyntaxRight = view => {
23128
+ let forward = ltrAtCursor(view);
23129
+ return extendSel(view, forward, range => moveBySyntax(view.state, range, forward));
23130
+ };
23083
23131
  function selectByLine(view, forward) {
23084
- return extendSel(view, range => view.moveVertically(range, forward));
23132
+ return extendSel(view, forward, range => view.moveVertically(range, forward));
23085
23133
  }
23086
23134
  /**
23087
23135
  Move the selection head one line up.
@@ -23092,7 +23140,7 @@ Move the selection head one line down.
23092
23140
  */
23093
23141
  const selectLineDown = view => selectByLine(view, true);
23094
23142
  function selectByPage(view, forward) {
23095
- return extendSel(view, range => view.moveVertically(range, forward, pageInfo(view).height));
23143
+ return extendSel(view, forward, range => view.moveVertically(range, forward, pageInfo(view).height));
23096
23144
  }
23097
23145
  /**
23098
23146
  Move the selection head one page up.
@@ -23105,27 +23153,33 @@ const selectPageDown = view => selectByPage(view, true);
23105
23153
  /**
23106
23154
  Move the selection head to the next line boundary.
23107
23155
  */
23108
- const selectLineBoundaryForward = view => extendSel(view, range => moveByLineBoundary(view, range, true));
23156
+ const selectLineBoundaryForward = view => extendSel(view, true, range => moveByLineBoundary(view, range, true));
23109
23157
  /**
23110
23158
  Move the selection head to the previous line boundary.
23111
23159
  */
23112
- const selectLineBoundaryBackward = view => extendSel(view, range => moveByLineBoundary(view, range, false));
23160
+ const selectLineBoundaryBackward = view => extendSel(view, false, range => moveByLineBoundary(view, range, false));
23113
23161
  /**
23114
23162
  Move the selection head one line boundary to the left.
23115
23163
  */
23116
- const selectLineBoundaryLeft = view => extendSel(view, range => moveByLineBoundary(view, range, !ltrAtCursor(view)));
23164
+ const selectLineBoundaryLeft = view => {
23165
+ let forward = !ltrAtCursor(view);
23166
+ return extendSel(view, forward, range => moveByLineBoundary(view, range, forward));
23167
+ };
23117
23168
  /**
23118
23169
  Move the selection head one line boundary to the right.
23119
23170
  */
23120
- const selectLineBoundaryRight = view => extendSel(view, range => moveByLineBoundary(view, range, ltrAtCursor(view)));
23171
+ const selectLineBoundaryRight = view => {
23172
+ let forward = ltrAtCursor(view);
23173
+ return extendSel(view, forward, range => moveByLineBoundary(view, range, forward));
23174
+ };
23121
23175
  /**
23122
23176
  Move the selection head to the start of the line.
23123
23177
  */
23124
- const selectLineStart = view => extendSel(view, range => EditorSelection.cursor(view.lineBlockAt(range.head).from));
23178
+ const selectLineStart = view => extendSel(view, false, range => EditorSelection.cursor(view.lineBlockAt(range.head).from));
23125
23179
  /**
23126
23180
  Move the selection head to the end of the line.
23127
23181
  */
23128
- const selectLineEnd = view => extendSel(view, range => EditorSelection.cursor(view.lineBlockAt(range.head).to));
23182
+ const selectLineEnd = view => extendSel(view, true, range => EditorSelection.cursor(view.lineBlockAt(range.head).to));
23129
23183
  /**
23130
23184
  Move the selection to the start of the document.
23131
23185
  */
@@ -0,0 +1,41 @@
1
+ import apiConstructor from '../api.js'
2
+
3
+ const api = apiConstructor()
4
+
5
+ // Create WebSocket connection.
6
+ const socket = new WebSocket('ws://localhost:8974')
7
+
8
+ // Connection opened
9
+ socket.addEventListener('open', () => {
10
+ console.log('Watching for Blueprint changes')
11
+ })
12
+
13
+ // Listen for messages
14
+ socket.addEventListener('message', (event) => {
15
+ if (event.data === 'reload-blueprint') {
16
+ api.blueprint()
17
+ return
18
+ }
19
+
20
+ let message
21
+ try {
22
+ message = JSON.parse(event.data)
23
+ } catch {
24
+ return
25
+ }
26
+
27
+ if (message?.type === 'nested-invoke') {
28
+ window.dispatchEvent(
29
+ new CustomEvent('nested-invoke', {
30
+ detail: {
31
+ name: message.name,
32
+ order: message.order,
33
+ logs: message.logs,
34
+ json: message.json,
35
+ error: message.error,
36
+ timings: message.timings,
37
+ },
38
+ }),
39
+ )
40
+ }
41
+ })
@@ -76,7 +76,34 @@ console.error = (...args) => {
76
76
  process.stdout.write(`${logPrefix('error', ...args)}\n`)
77
77
  }
78
78
 
79
- // Start when payload data arrives from parent process
79
+ /**
80
+ * Pending nested `context.invoke` calls, keyed by correlation id. Each entry
81
+ * holds the resolve/reject of the Promise returned to the user's handler; it is
82
+ * settled when the matching `invoke-response` arrives from the parent.
83
+ * @type {Map<string, {resolve: (value: unknown) => void, reject: (reason: Error) => void}>}
84
+ */
85
+ const pendingInvokes = new Map()
86
+ let invokeSeq = 0
87
+
88
+ /**
89
+ * `context.invoke(name, payload)` — ask the parent to execute another blueprint
90
+ * function and resolve with its return value. Sent over IPC and correlated by id.
91
+ * @param {string} name
92
+ * @param {Record<string, unknown>} [payload]
93
+ * @returns {Promise<unknown>}
94
+ */
95
+ function invokeFunction(name, payload = {}) {
96
+ if (typeof name !== 'string' || name.length === 0) {
97
+ return Promise.reject(new Error('context.invoke requires a function name'))
98
+ }
99
+ const id = String(++invokeSeq)
100
+ return new Promise((resolve, reject) => {
101
+ pendingInvokes.set(id, {resolve, reject})
102
+ process.send(JSON.stringify({type: 'invoke-request', id, name, payload}))
103
+ })
104
+ }
105
+
106
+ // Listen for IPC messages from the parent process.
80
107
  process.on('message', async (data) => {
81
108
  let jsonData = null
82
109
  try {
@@ -86,6 +113,25 @@ process.on('message', async (data) => {
86
113
  return
87
114
  }
88
115
 
116
+ // Response to a nested context.invoke() — route to the awaiting Promise and stop.
117
+ if (jsonData?.type === 'invoke-response') {
118
+ const pending = pendingInvokes.get(jsonData.id)
119
+ if (!pending) return
120
+ pendingInvokes.delete(jsonData.id)
121
+ if (jsonData.ok) {
122
+ pending.resolve(jsonData.result?.json)
123
+ } else {
124
+ const {message, stack, name} = jsonData.error ?? {}
125
+ const error = new Error(message ?? 'Nested invoke failed')
126
+ if (stack) error.stack = stack
127
+ if (name) error.name = name
128
+ pending.reject(error)
129
+ }
130
+ return
131
+ }
132
+
133
+ // Otherwise this is the initial start message. Support the legacy untyped
134
+ // `{srcPath, payload}` shape as well as the new `{type: 'start', ...}`.
89
135
  const {srcPath, payload} = jsonData
90
136
  const {context, ...event} = payload
91
137
 
@@ -93,17 +139,22 @@ process.on('message', async (data) => {
93
139
  let errorLogs = ''
94
140
  let json = null
95
141
 
96
- // Capture stdout and stderr
142
+ // Capture stdout and stderr in-memory for the terminal `result` message, and
143
+ // ALSO send them through to the real stdio pipes. The parent captures those
144
+ // pipes live, so logs written before a timeout (child killed) or a
145
+ // process.exit() aren't lost
97
146
  const originalStdoutWrite = process.stdout.write.bind(process.stdout)
98
147
  const originalStderrWrite = process.stderr.write.bind(process.stderr)
99
148
 
100
- process.stdout.write = (chunk) => {
149
+ process.stdout.write = (...args) => {
150
+ const chunk = args[0]
101
151
  if (typeof chunk === 'string') logs += chunk
102
- return true
152
+ return originalStdoutWrite(...args)
103
153
  }
104
- process.stderr.write = (chunk) => {
154
+ process.stderr.write = (...args) => {
155
+ const chunk = args[0]
105
156
  if (typeof chunk === 'string') errorLogs += chunk
106
- return true
157
+ return originalStderrWrite(...args)
107
158
  }
108
159
 
109
160
  try {
@@ -120,6 +171,9 @@ process.on('message', async (data) => {
120
171
  // Replace resources JSON with Resources API
121
172
  context.resources = createResourcesApi(context.resources)
122
173
 
174
+ // Allow the handler to invoke other blueprint functions by name.
175
+ context.invoke = invokeFunction
176
+
123
177
  json = await eventHandler({
124
178
  context,
125
179
  event,
@@ -132,13 +186,14 @@ process.on('message', async (data) => {
132
186
  process.stderr.write = originalStderrWrite
133
187
 
134
188
  // Send result to parent
135
- process.send(JSON.stringify({json, logs, errorLogs}))
189
+ process.send(JSON.stringify({type: 'result', json, logs, errorLogs}))
136
190
  } catch (err) {
137
191
  // Restore streams on error
138
192
  process.stdout.write = originalStdoutWrite
139
193
  process.stderr.write = originalStderrWrite
140
194
 
141
195
  const errorInfo = {
196
+ type: 'result',
142
197
  json: null,
143
198
  logs,
144
199
  errorLogs,
@@ -8,4 +8,4 @@
8
8
  * @returns The absolute path to the entry file.
9
9
  * @throws If the entry file cannot be determined.
10
10
  */
11
- export declare function findFunctionEntryPoint(srcPath: string, displayName?: string): Promise<string>;
11
+ export declare function findFunctionEntryPoint(functionPath: string, displayName?: string): Promise<string>;
@@ -1,6 +1,5 @@
1
1
  import { readFile, stat } from 'node:fs/promises';
2
2
  import { join, resolve } from 'node:path';
3
- import { cwd } from 'node:process';
4
3
  /**
5
4
  * Resolves the source path to an executable entry file path.
6
5
  *
@@ -11,27 +10,26 @@ import { cwd } from 'node:process';
11
10
  * @returns The absolute path to the entry file.
12
11
  * @throws If the entry file cannot be determined.
13
12
  */
14
- export async function findFunctionEntryPoint(srcPath, displayName) {
15
- const absolutePath = resolve(cwd(), srcPath);
13
+ export async function findFunctionEntryPoint(functionPath, displayName) {
16
14
  let stats;
17
15
  try {
18
- stats = await stat(absolutePath);
16
+ stats = await stat(functionPath);
19
17
  }
20
18
  catch (err) {
21
- throw new Error(`Source path not found or inaccessible: ${srcPath}`, { cause: err });
19
+ throw new Error(`Source path not found or inaccessible: ${functionPath}`, { cause: err });
22
20
  }
23
21
  if (stats.isFile()) {
24
22
  // It's already an entry file path
25
- return absolutePath;
23
+ return functionPath;
26
24
  }
27
25
  if (stats.isDirectory()) {
28
26
  // 1. Check package.json#main
29
27
  try {
30
- const pkgJsonPath = join(absolutePath, 'package.json');
28
+ const pkgJsonPath = join(functionPath, 'package.json');
31
29
  const pkgJsonContent = await readFile(pkgJsonPath, 'utf8');
32
30
  const pkgJson = JSON.parse(pkgJsonContent);
33
31
  if (pkgJson.main) {
34
- const mainPath = resolve(absolutePath, pkgJson.main);
32
+ const mainPath = resolve(functionPath, pkgJson.main);
35
33
  if (await fileExists(mainPath)) {
36
34
  return mainPath;
37
35
  }
@@ -43,20 +41,20 @@ export async function findFunctionEntryPoint(srcPath, displayName) {
43
41
  // Consider warning the user on invalid JSON though?
44
42
  }
45
43
  // 2. Check index.ts
46
- const indexTs = join(absolutePath, 'index.ts');
44
+ const indexTs = join(functionPath, 'index.ts');
47
45
  if (await fileExists(indexTs)) {
48
46
  return indexTs;
49
47
  }
50
48
  // 3. Check index.js
51
- const indexJs = join(absolutePath, 'index.js');
49
+ const indexJs = join(functionPath, 'index.js');
52
50
  if (await fileExists(indexJs)) {
53
51
  return indexJs;
54
52
  }
55
53
  const nameHint = displayName ? ` for function "${displayName}"` : '';
56
- throw new Error(`Could not determine entry file${nameHint} in directory: ${srcPath}. Looked for package.json#main, index.ts, index.js.`);
54
+ throw new Error(`Could not determine entry file${nameHint} in directory: ${functionPath}. Looked for package.json#main, index.ts, index.js.`);
57
55
  }
58
56
  // Should not happen if stat succeeded, but defensively handle
59
- throw new Error(`Source path is neither a file nor a directory: ${srcPath}`);
57
+ throw new Error(`Source path is neither a file nor a directory: ${functionPath}`);
60
58
  }
61
59
  /**
62
60
  * Checks if a file exists and is a file.
@@ -1,4 +1,4 @@
1
- import { type FunctionGroqResource, type FunctionResource, type InvocationResponse, type InvokeContextOptions, type InvokeExecutionOptions, type InvokeGroqPayloadOptions, type InvokePayloadOptions } from '../types.js';
1
+ import { type FunctionGroqResource, type FunctionResource, type InvocationResponse, type InvokeContextOptions, type InvokeExecutionOptions, type InvokeGroqPayloadOptions, type InvokePayloadOptions } from '../../types.js';
2
2
  export declare function sanitizeLogs(logs: string): string;
3
3
  export declare function applyGroqRule(resource: FunctionGroqResource, payload: InvokeGroqPayloadOptions, projectId: string | undefined, dataset: string | undefined): Promise<any>;
4
4
  export default function invoke(resource: FunctionResource, payload: InvokePayloadOptions, context: InvokeContextOptions, options: InvokeExecutionOptions): Promise<InvocationResponse>;