@xano/xanoscript-language-server 12.1.0 → 12.2.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.
@@ -0,0 +1,23 @@
1
+ import { Identifier } from "./identifier.js";
2
+ import { createTokenByName } from "./utils.js";
3
+
4
+ // "error_trigger"
5
+ export const ErrorTriggerToken = createTokenByName("error_trigger", {
6
+ longer_alt: Identifier,
7
+ categories: [Identifier], // could also be an identifier
8
+ });
9
+
10
+ export const ErrorTriggerTokens = [ErrorTriggerToken];
11
+
12
+ /**
13
+ * Maps a token name to a type
14
+ * @param {string} token the token name
15
+ */
16
+ export function mapTokenToType(token) {
17
+ switch (token) {
18
+ case ErrorTriggerToken.name:
19
+ return "keyword";
20
+ default:
21
+ return null;
22
+ }
23
+ }
package/lexer/tokens.js CHANGED
@@ -54,6 +54,10 @@ import {
54
54
  } from "./control.js";
55
55
  import { DbTokens, mapTokenToType as mapDbTokenToType } from "./db.js";
56
56
  import { DebugTokens, mapTokenToType as mapDebugTokenToType } from "./debug.js";
57
+ import {
58
+ ErrorTriggerTokens,
59
+ mapTokenToType as mapErrorTriggerTokenToType,
60
+ } from "./error_trigger.js";
57
61
  import {
58
62
  ExpectFnTokens,
59
63
  mapTokenToType as mapExpectTokenToType,
@@ -399,6 +403,7 @@ export const allTokens = uniq([
399
403
  ...UtilTokens,
400
404
  ...TableTriggerTokens,
401
405
  ...WorkspaceTriggerTokens,
406
+ ...ErrorTriggerTokens,
402
407
  ...TaskTokens,
403
408
  ...WorkflowTestTokens,
404
409
  ...ApiGroupTokens,
@@ -446,6 +451,7 @@ const tokenMappers = [
446
451
  mapControlsTokenToType,
447
452
  mapDbTokenToType,
448
453
  mapDebugTokenToType,
454
+ mapErrorTriggerTokenToType,
449
455
  mapExpectTokenToType,
450
456
  mapFunctionTokenToType,
451
457
  mapLiteralTokenToType,
@@ -287,6 +287,52 @@ A `task` file defines a scheduled job that runs automatically at specified times
287
287
 
288
288
  Tasks are ideal for automating recurring operations like generating reports or syncing data.
289
289
 
290
+ # error_trigger
291
+
292
+ ```xs
293
+ error_trigger "notify on errors" {
294
+ input {
295
+ enum event? {
296
+ values = ["new", "regression", "fixed"]
297
+ }
298
+ int id?
299
+ text signature?
300
+ object error? {
301
+ schema {
302
+ text code?
303
+ text message?
304
+ }
305
+ }
306
+ }
307
+
308
+ stack {
309
+ api.request {
310
+ url = "https://hooks.example.com/alerts"
311
+ method = "POST"
312
+ params = {
313
+ event : $input.event
314
+ message: $input.error.message
315
+ }
316
+ } as $api1
317
+ }
318
+ }
319
+ ```
320
+
321
+ An `error_trigger` file defines the workspace's error-notification handler, fired when error signatures are first captured, regress, or are marked fixed. Only one `error_trigger` exists per workspace. It includes:
322
+
323
+ - A name (e.g., `"notify on errors"` or `trigger_on_error`) to identify the trigger,
324
+
325
+ - An `input` block describing the payload the runtime delivers, including:
326
+ - `event`: which event fired the trigger — `"new"` (first capture or re-capture after the ~5 minute snapshot dedup window), `"regression"` (a previously-fixed signature re-occurred), or `"fixed"` (a user marked the signature as fixed),
327
+ - `signature`, `id`: stable identifiers for the error,
328
+ - `error`: the captured error `code` and `message`,
329
+ - `caller`, `statement`: where the error originated (null on `"fixed"` events),
330
+ - `actor`: the user who marked it fixed (only on `"fixed"` events),
331
+ - `count`, `first_seen`, `last_seen`, `fixed_at`: occurrence metadata.
332
+ - A `stack` block defining the actions to take — typically calling out to a webhook, sending an email, or otherwise notifying the team.
333
+
334
+ Use an `error_trigger` to wire workspace-wide alerting on top of the error-logs system without subscribing per object or per event source.
335
+
290
336
  # run.job
291
337
 
292
338
  ```xs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/xanoscript-language-server",
3
- "version": "12.1.0",
3
+ "version": "12.2.0",
4
4
  "description": "Language Server Protocol implementation for XanoScript",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -26,12 +26,12 @@ export function objectColumnDefinition($) {
26
26
  // object[]
27
27
  iterable = true;
28
28
  $.SUBRULE($.arraySlice);
29
+ });
29
30
 
30
- // object[]? (nullable array)
31
- $.OPTION3(() => {
32
- nullable = true;
33
- $.CONSUME(Question);
34
- });
31
+ // object? (nullable) or object[]? (nullable array)
32
+ $.OPTION3(() => {
33
+ nullable = true;
34
+ $.CONSUME(Question);
35
35
  });
36
36
 
37
37
  // Column name (e.g., "user_id", "optional_column", "required_column")
@@ -0,0 +1,88 @@
1
+ import { LCurly, RCurly } from "../lexer/control.js";
2
+ import { ErrorTriggerToken } from "../lexer/error_trigger.js";
3
+ import { StringLiteral } from "../lexer/literal.js";
4
+ import { Identifier, NewlineToken } from "../lexer/tokens.js";
5
+
6
+ export function errorTriggerDeclaration($) {
7
+ return () => {
8
+ let hasDescription = false;
9
+ let hasGuid = false;
10
+ let hasHistory = false;
11
+ let hasInput = false;
12
+ let hasStack = false;
13
+ let hasTags = false;
14
+
15
+ $.sectionStack.push("errorTriggerDeclaration");
16
+ // Allow leading comments and newlines before the error_trigger declaration
17
+ $.SUBRULE($.optionalCommentBlockFn);
18
+
19
+ const parent = $.CONSUME(ErrorTriggerToken); // error_trigger
20
+ const nameToken = $.OR([
21
+ { ALT: () => $.CONSUME(StringLiteral) },
22
+ { ALT: () => $.CONSUME(Identifier) },
23
+ ]);
24
+ $.validateDeclarationName(nameToken, "error_trigger");
25
+ $.CONSUME(LCurly); // "{"
26
+ $.MANY(() => {
27
+ $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
28
+ $.OR2([
29
+ { ALT: () => $.SUBRULE($.commentBlockFn) },
30
+ {
31
+ GATE: () => !hasDescription,
32
+ ALT: () => {
33
+ hasDescription = true;
34
+ $.SUBRULE($.descriptionFieldAttribute);
35
+ },
36
+ },
37
+ {
38
+ GATE: () => !hasGuid,
39
+ ALT: () => {
40
+ hasGuid = true;
41
+ $.SUBRULE($.guidFieldAttribute);
42
+ },
43
+ },
44
+ {
45
+ GATE: () => !hasHistory,
46
+ ALT: () => {
47
+ hasHistory = true;
48
+ $.SUBRULE($.historyClause);
49
+ },
50
+ },
51
+ {
52
+ GATE: () => !hasInput,
53
+ ALT: () => {
54
+ hasInput = true;
55
+ $.SUBRULE($.inputClause);
56
+ },
57
+ },
58
+ {
59
+ GATE: () => !hasStack,
60
+ ALT: () => {
61
+ hasStack = true;
62
+ $.SUBRULE($.stackClause);
63
+ },
64
+ },
65
+ {
66
+ GATE: () => !hasTags,
67
+ ALT: () => {
68
+ hasTags = true;
69
+ $.SUBRULE($.tagsAttribute);
70
+ },
71
+ },
72
+ ]);
73
+ });
74
+
75
+ if (!hasInput) {
76
+ $.addMissingError(parent, "{} is missing an input clause");
77
+ }
78
+
79
+ if (!hasStack) {
80
+ $.addMissingError(parent, "{} is missing a stack clause");
81
+ }
82
+
83
+ $.MANY1(() => $.CONSUME1(NewlineToken)); // optional new line
84
+ $.CONSUME(RCurly); // "}"
85
+ $.MANY2(() => $.CONSUME2(NewlineToken)); // optional new line
86
+ $.sectionStack.pop();
87
+ };
88
+ }
package/parser/parser.js CHANGED
@@ -36,6 +36,9 @@ export function xanoscriptParser(text, scheme, preTokenized = null) {
36
36
  case "branch":
37
37
  parser.branchDeclaration();
38
38
  return parser;
39
+ case "error_trigger":
40
+ parser.errorTriggerDeclaration();
41
+ return parser;
39
42
  case "db":
40
43
  parser.tableDeclaration();
41
44
  return parser;
@@ -6,6 +6,7 @@ import { register as register_attributes } from "./attributes/register.js";
6
6
  import { branchDeclaration } from "./branch_parser.js";
7
7
  import { register as register_clauses } from "./clauses/register.js";
8
8
  import { register as register_definitions } from "./definitions/register.js";
9
+ import { errorTriggerDeclaration } from "./error_trigger_parser.js";
9
10
  import { functionDeclaration } from "./function_parser.js";
10
11
  import { register as register_functions } from "./functions/register.js";
11
12
  import { register as register_generic } from "./generic/register.js";
@@ -50,6 +51,10 @@ export const register = ($) => {
50
51
  $.queryDeclaration = $.RULE("queryDeclaration", queryDeclaration($));
51
52
  $.apiGroupDeclaration = $.RULE("apiGroupDeclaration", apiGroupDeclaration($));
52
53
  $.branchDeclaration = $.RULE("branchDeclaration", branchDeclaration($));
54
+ $.errorTriggerDeclaration = $.RULE(
55
+ "errorTriggerDeclaration",
56
+ errorTriggerDeclaration($)
57
+ );
53
58
  $.tableDeclaration = $.RULE("tableDeclaration", tableDeclaration($));
54
59
  $.mcpServerDeclaration = $.RULE(
55
60
  "mcpServerDeclaration",
package/utils.js CHANGED
@@ -23,6 +23,7 @@ const schemeByFirstWord = {
23
23
  agent_trigger: "agent_trigger",
24
24
  api_group: "api_group",
25
25
  branch: "branch",
26
+ error_trigger: "error_trigger",
26
27
  function: "cfn",
27
28
  mcp_server: "mcp_server",
28
29
  mcp_server_trigger: "mcp_server_trigger",