@oomol-lab/open-flow 0.1.0-beta.87 → 0.1.0-beta.88

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.
@@ -12476,6 +12476,14 @@ function runEvents(value) {
12476
12476
  };
12477
12477
  }
12478
12478
  var segment = encodeURIComponent;
12479
+ async function responseJson(response, signal) {
12480
+ try {
12481
+ return await response.json();
12482
+ } catch (error) {
12483
+ if (signal?.aborted) throw signal.reason ?? error;
12484
+ return invalidResponse(`HTTP ${response.status} response body is not JSON.`);
12485
+ }
12486
+ }
12479
12487
  function operationKey(operation) {
12480
12488
  return `${operation}-${randomId()}`;
12481
12489
  }
@@ -12774,7 +12782,7 @@ var ControlClient = class {
12774
12782
  };
12775
12783
  return {
12776
12784
  modified: true,
12777
- data: query.decode(await response.json()),
12785
+ data: query.decode(await responseJson(response, signal)),
12778
12786
  etag: nextETag
12779
12787
  };
12780
12788
  }
@@ -12803,7 +12811,7 @@ var ControlClient = class {
12803
12811
  };
12804
12812
  }
12805
12813
  return {
12806
- data: decodeTriggerCatalog(await response.json()),
12814
+ data: decodeTriggerCatalog(await responseJson(response, signal)),
12807
12815
  etag: response.headers.get("etag")?.trim() || null
12808
12816
  };
12809
12817
  }
@@ -13312,7 +13320,7 @@ var ControlClient = class {
13312
13320
  try {
13313
13321
  value = await response.json();
13314
13322
  } catch {
13315
- return invalidResponse();
13323
+ return invalidResponse(`HTTP ${response.status} response did not include a JSON error body.`);
13316
13324
  }
13317
13325
  const error = record$1(value).error;
13318
13326
  const source = error == null ? void 0 : record$1(error);
@@ -13321,12 +13329,7 @@ var ControlClient = class {
13321
13329
  return response;
13322
13330
  }
13323
13331
  async request(path, init = {}) {
13324
- const response = await this.response(path, init);
13325
- try {
13326
- return await response.json();
13327
- } catch {
13328
- return invalidResponse();
13329
- }
13332
+ return await responseJson(await this.response(path, init), init.signal);
13330
13333
  }
13331
13334
  };
13332
13335
  //#endregion
@@ -13165,6 +13165,14 @@ function runEvents(value) {
13165
13165
  };
13166
13166
  }
13167
13167
  var segment = encodeURIComponent;
13168
+ async function responseJson(response, signal) {
13169
+ try {
13170
+ return await response.json();
13171
+ } catch (error) {
13172
+ if (signal?.aborted) throw signal.reason ?? error;
13173
+ return invalidResponse(`HTTP ${response.status} response body is not JSON.`);
13174
+ }
13175
+ }
13168
13176
  function operationKey(operation) {
13169
13177
  return `${operation}-${randomId()}`;
13170
13178
  }
@@ -13463,7 +13471,7 @@ var ControlClient = class {
13463
13471
  };
13464
13472
  return {
13465
13473
  modified: true,
13466
- data: query.decode(await response.json()),
13474
+ data: query.decode(await responseJson(response, signal)),
13467
13475
  etag: nextETag
13468
13476
  };
13469
13477
  }
@@ -13492,7 +13500,7 @@ var ControlClient = class {
13492
13500
  };
13493
13501
  }
13494
13502
  return {
13495
- data: decodeTriggerCatalog(await response.json()),
13503
+ data: decodeTriggerCatalog(await responseJson(response, signal)),
13496
13504
  etag: response.headers.get("etag")?.trim() || null
13497
13505
  };
13498
13506
  }
@@ -14001,7 +14009,7 @@ var ControlClient = class {
14001
14009
  try {
14002
14010
  value = await response.json();
14003
14011
  } catch {
14004
- return invalidResponse();
14012
+ return invalidResponse(`HTTP ${response.status} response did not include a JSON error body.`);
14005
14013
  }
14006
14014
  const error = record(value).error;
14007
14015
  const source = error == null ? void 0 : record(error);
@@ -14010,12 +14018,7 @@ var ControlClient = class {
14010
14018
  return response;
14011
14019
  }
14012
14020
  async request(path, init = {}) {
14013
- const response = await this.response(path, init);
14014
- try {
14015
- return await response.json();
14016
- } catch {
14017
- return invalidResponse();
14018
- }
14021
+ return await responseJson(await this.response(path, init), init.signal);
14019
14022
  }
14020
14023
  };
14021
14024
  //#endregion
@@ -16388,6 +16388,12 @@ function sourceOutputLabel(source) {
16388
16388
  function isResolutionNode(node) {
16389
16389
  return node?.kind == "approval" || node?.kind == "wait";
16390
16390
  }
16391
+ function keywordMismatchDetail(mismatch) {
16392
+ if (mismatch?.kind != "keyword") return "";
16393
+ const location = mismatch.path.length == 0 ? "" : ` at ${mismatch.path.join(".")}`;
16394
+ const declared = mismatch.source === void 0 ? "does not declare it" : `declares ${JSON.stringify(mismatch.source)}`;
16395
+ return ` The input requires ${mismatch.keyword} ${JSON.stringify(mismatch.target)}${location}; the output ${declared}.`;
16396
+ }
16391
16397
  function graphDiagnostic(code, message, path, values, mismatch) {
16392
16398
  return {
16393
16399
  code,
@@ -16610,7 +16616,7 @@ function checkSource(source, graph, document, targetInput, path, diagnostics) {
16610
16616
  }
16611
16617
  if (targetInput != null) {
16612
16618
  const comparison = comparePorts(selected, targetInput);
16613
- if (comparison.kind != "compatible") diagnostics.push(graphDiagnostic("graph.node-output-incompatible", `Upstream node "${source.nodeId}" output ${JSON.stringify(sourceOutputLabel(source))} is not compatible with this input.`, path, {
16619
+ if (comparison.kind != "compatible") diagnostics.push(graphDiagnostic("graph.node-output-incompatible", `Upstream node "${source.nodeId}" output ${JSON.stringify(sourceOutputLabel(source))} is not compatible with this input.${comparison.kind == "incompatible" ? keywordMismatchDetail(comparison.mismatch) : ""}`, path, {
16614
16620
  nodeId: source.nodeId,
16615
16621
  output: source.output,
16616
16622
  ...source.field === void 0 ? {} : { field: source.field }
@@ -18115,7 +18121,7 @@ async function compileAuthoring(base, request, host) {
18115
18121
  operations.push(...checked);
18116
18122
  }
18117
18123
  function resolve(ref) {
18118
- return ref.startsWith("$") ? (Object.hasOwn(aliases, ref.slice(1)) ? aliases[ref.slice(1)] : void 0) ?? fail("node.alias-missing", `Unknown alias ${ref}.`) : ref;
18124
+ return ref.startsWith("$") ? (Object.hasOwn(aliases, ref.slice(1)) ? aliases[ref.slice(1)] : void 0) ?? fail("node.alias-missing", `Unknown alias ${ref}. Set the as field to ${JSON.stringify(ref.slice(1))} on an earlier node.add in the same request.`) : ref;
18119
18125
  }
18120
18126
  function source(value) {
18121
18127
  if (value.kind == "output" || value.kind == "system") {
@@ -12879,6 +12879,12 @@ function sourceOutputLabel(source) {
12879
12879
  function isResolutionNode(node) {
12880
12880
  return node?.kind == "approval" || node?.kind == "wait";
12881
12881
  }
12882
+ function keywordMismatchDetail(mismatch) {
12883
+ if (mismatch?.kind != "keyword") return "";
12884
+ const location = mismatch.path.length == 0 ? "" : ` at ${mismatch.path.join(".")}`;
12885
+ const declared = mismatch.source === void 0 ? "does not declare it" : `declares ${JSON.stringify(mismatch.source)}`;
12886
+ return ` The input requires ${mismatch.keyword} ${JSON.stringify(mismatch.target)}${location}; the output ${declared}.`;
12887
+ }
12882
12888
  function graphDiagnostic(code, message, path, values, mismatch) {
12883
12889
  return {
12884
12890
  code,
@@ -13101,7 +13107,7 @@ function checkSource(source, graph, document, targetInput, path, diagnostics) {
13101
13107
  }
13102
13108
  if (targetInput != null) {
13103
13109
  const comparison = comparePorts(selected, targetInput);
13104
- if (comparison.kind != "compatible") diagnostics.push(graphDiagnostic("graph.node-output-incompatible", `Upstream node "${source.nodeId}" output ${JSON.stringify(sourceOutputLabel(source))} is not compatible with this input.`, path, {
13110
+ if (comparison.kind != "compatible") diagnostics.push(graphDiagnostic("graph.node-output-incompatible", `Upstream node "${source.nodeId}" output ${JSON.stringify(sourceOutputLabel(source))} is not compatible with this input.${comparison.kind == "incompatible" ? keywordMismatchDetail(comparison.mismatch) : ""}`, path, {
13105
13111
  nodeId: source.nodeId,
13106
13112
  output: source.output,
13107
13113
  ...source.field === void 0 ? {} : { field: source.field }
@@ -12666,6 +12666,14 @@ function runEvents(value) {
12666
12666
  };
12667
12667
  }
12668
12668
  var segment = encodeURIComponent;
12669
+ async function responseJson(response, signal) {
12670
+ try {
12671
+ return await response.json();
12672
+ } catch (error) {
12673
+ if (signal?.aborted) throw signal.reason ?? error;
12674
+ return invalidResponse(`HTTP ${response.status} response body is not JSON.`);
12675
+ }
12676
+ }
12669
12677
  function operationKey(operation) {
12670
12678
  return `${operation}-${randomId()}`;
12671
12679
  }
@@ -12964,7 +12972,7 @@ var ControlClient = class {
12964
12972
  };
12965
12973
  return {
12966
12974
  modified: true,
12967
- data: query.decode(await response.json()),
12975
+ data: query.decode(await responseJson(response, signal)),
12968
12976
  etag: nextETag
12969
12977
  };
12970
12978
  }
@@ -12993,7 +13001,7 @@ var ControlClient = class {
12993
13001
  };
12994
13002
  }
12995
13003
  return {
12996
- data: decodeTriggerCatalog(await response.json()),
13004
+ data: decodeTriggerCatalog(await responseJson(response, signal)),
12997
13005
  etag: response.headers.get("etag")?.trim() || null
12998
13006
  };
12999
13007
  }
@@ -13502,7 +13510,7 @@ var ControlClient = class {
13502
13510
  try {
13503
13511
  value = await response.json();
13504
13512
  } catch {
13505
- return invalidResponse();
13513
+ return invalidResponse(`HTTP ${response.status} response did not include a JSON error body.`);
13506
13514
  }
13507
13515
  const error = record(value).error;
13508
13516
  const source = error == null ? void 0 : record(error);
@@ -13511,12 +13519,7 @@ var ControlClient = class {
13511
13519
  return response;
13512
13520
  }
13513
13521
  async request(path, init = {}) {
13514
- const response = await this.response(path, init);
13515
- try {
13516
- return await response.json();
13517
- } catch {
13518
- return invalidResponse();
13519
- }
13522
+ return await responseJson(await this.response(path, init), init.signal);
13520
13523
  }
13521
13524
  };
13522
13525
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oomol-lab/open-flow",
3
- "version": "0.1.0-beta.87",
3
+ "version": "0.1.0-beta.88",
4
4
  "description": "TypeScript contracts and Browser runtime for Open Flow.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
@@ -857,6 +857,15 @@ function runEvents(value: unknown): RunEvents {
857
857
 
858
858
  const segment = encodeURIComponent
859
859
 
860
+ async function responseJson(response: Response, signal: AbortSignal | null | undefined): Promise<unknown> {
861
+ try {
862
+ return await response.json()
863
+ } catch (error) {
864
+ if (signal?.aborted) throw signal.reason ?? error
865
+ return invalidResponse(`HTTP ${response.status} response body is not JSON.`)
866
+ }
867
+ }
868
+
860
869
  function operationKey(operation: string): string {
861
870
  return `${operation}-${randomId()}`
862
871
  }
@@ -1158,7 +1167,7 @@ export class ControlClient {
1158
1167
  const response = await this.response(query.path, { headers, signal }, true)
1159
1168
  const nextETag = response.headers.get('etag')?.trim() || null
1160
1169
  if (response.status == 304) return { modified: false, etag: nextETag }
1161
- return { modified: true, data: query.decode(await response.json()), etag: nextETag }
1170
+ return { modified: true, data: query.decode(await responseJson(response, signal)), etag: nextETag }
1162
1171
  }
1163
1172
 
1164
1173
  async getTriggerCatalog(locale: string, cached?: TriggerCatalogCache, signal?: AbortSignal): Promise<TriggerCatalogCache> {
@@ -1177,7 +1186,7 @@ export class ControlClient {
1177
1186
  if (cached == null) return invalidResponse()
1178
1187
  return { ...cached, etag: response.headers.get('etag')?.trim() || cached.etag }
1179
1188
  }
1180
- return { data: decodeTriggerCatalog(await response.json()), etag: response.headers.get('etag')?.trim() || null }
1189
+ return { data: decodeTriggerCatalog(await responseJson(response, signal)), etag: response.headers.get('etag')?.trim() || null }
1181
1190
  }
1182
1191
 
1183
1192
  async getTriggerKey(key: string, signal?: AbortSignal): Promise<TriggerKeySnapshot> {
@@ -1746,7 +1755,7 @@ export class ControlClient {
1746
1755
  try {
1747
1756
  value = await response.json()
1748
1757
  } catch {
1749
- return invalidResponse()
1758
+ return invalidResponse(`HTTP ${response.status} response did not include a JSON error body.`)
1750
1759
  }
1751
1760
  const error = record(value).error
1752
1761
  const source = error == null ? undefined : record(error)
@@ -1761,11 +1770,6 @@ export class ControlClient {
1761
1770
  }
1762
1771
 
1763
1772
  protected async request<Value = unknown>(path: string, init: RequestInit = {}): Promise<Value> {
1764
- const response = await this.response(path, init)
1765
- try {
1766
- return (await response.json()) as Value
1767
- } catch {
1768
- return invalidResponse()
1769
- }
1773
+ return (await responseJson(await this.response(path, init), init.signal)) as Value
1770
1774
  }
1771
1775
  }
@@ -363,7 +363,8 @@ export async function compileAuthoring(base: RevisionContent, request: Authoring
363
363
  }
364
364
  function resolve(ref: string) {
365
365
  return ref.startsWith('$')
366
- ? ((Object.hasOwn(aliases, ref.slice(1)) ? aliases[ref.slice(1)] : undefined) ?? fail('node.alias-missing', `Unknown alias ${ref}.`))
366
+ ? ((Object.hasOwn(aliases, ref.slice(1)) ? aliases[ref.slice(1)] : undefined) ??
367
+ fail('node.alias-missing', `Unknown alias ${ref}. Set the as field to ${JSON.stringify(ref.slice(1))} on an earlier node.add in the same request.`))
367
368
  : ref
368
369
  }
369
370
  function source(
@@ -39,6 +39,13 @@ import {
39
39
  export function isResolutionNode(node: GraphNode | undefined): node is Extract<GraphNode, { readonly kind: 'approval' | 'wait' }> {
40
40
  return node?.kind == 'approval' || node?.kind == 'wait'
41
41
  }
42
+ function keywordMismatchDetail(mismatch: SchemaMismatch | undefined): string {
43
+ if (mismatch?.kind != 'keyword') return ''
44
+ const location = mismatch.path.length == 0 ? '' : ` at ${mismatch.path.join('.')}`
45
+ const declared = mismatch.source === undefined ? 'does not declare it' : `declares ${JSON.stringify(mismatch.source)}`
46
+ return ` The input requires ${mismatch.keyword} ${JSON.stringify(mismatch.target)}${location}; the output ${declared}.`
47
+ }
48
+
42
49
  function graphDiagnostic(
43
50
  code: string,
44
51
  message: string,
@@ -369,7 +376,9 @@ function checkSource(
369
376
  diagnostics.push(
370
377
  graphDiagnostic(
371
378
  'graph.node-output-incompatible',
372
- `Upstream node "${source.nodeId}" output ${JSON.stringify(sourceOutputLabel(source))} is not compatible with this input.`,
379
+ `Upstream node "${source.nodeId}" output ${JSON.stringify(sourceOutputLabel(source))} is not compatible with this input.${
380
+ comparison.kind == 'incompatible' ? keywordMismatchDetail(comparison.mismatch) : ''
381
+ }`,
373
382
  path,
374
383
  { nodeId: source.nodeId, output: source.output, ...(source.field === undefined ? {} : { field: source.field }) },
375
384
  comparison.kind == 'incompatible' ? comparison.mismatch : undefined,