@descryy/runtime-adapter-ruby 0.0.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.
Files changed (41) hide show
  1. package/dist/index.d.ts +14 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +10 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/rails-frame-parsing.d.ts +105 -0
  6. package/dist/rails-frame-parsing.d.ts.map +1 -0
  7. package/dist/rails-frame-parsing.js +183 -0
  8. package/dist/rails-frame-parsing.js.map +1 -0
  9. package/dist/rails-stack-trace-parser.d.ts +31 -0
  10. package/dist/rails-stack-trace-parser.d.ts.map +1 -0
  11. package/dist/rails-stack-trace-parser.js +63 -0
  12. package/dist/rails-stack-trace-parser.js.map +1 -0
  13. package/dist/ruby-frame-parsing.d.ts +78 -0
  14. package/dist/ruby-frame-parsing.d.ts.map +1 -0
  15. package/dist/ruby-frame-parsing.js +108 -0
  16. package/dist/ruby-frame-parsing.js.map +1 -0
  17. package/dist/ruby-log-envelopes.d.ts +101 -0
  18. package/dist/ruby-log-envelopes.d.ts.map +1 -0
  19. package/dist/ruby-log-envelopes.js +214 -0
  20. package/dist/ruby-log-envelopes.js.map +1 -0
  21. package/dist/ruby-runtime-adapter.d.ts +51 -0
  22. package/dist/ruby-runtime-adapter.d.ts.map +1 -0
  23. package/dist/ruby-runtime-adapter.js +56 -0
  24. package/dist/ruby-runtime-adapter.js.map +1 -0
  25. package/dist/ruby-source-location-resolver.d.ts +34 -0
  26. package/dist/ruby-source-location-resolver.d.ts.map +1 -0
  27. package/dist/ruby-source-location-resolver.js +61 -0
  28. package/dist/ruby-source-location-resolver.js.map +1 -0
  29. package/dist/ruby-stack-trace-parser.d.ts +24 -0
  30. package/dist/ruby-stack-trace-parser.d.ts.map +1 -0
  31. package/dist/ruby-stack-trace-parser.js +71 -0
  32. package/dist/ruby-stack-trace-parser.js.map +1 -0
  33. package/dist/sinatra-frame-parsing.d.ts +92 -0
  34. package/dist/sinatra-frame-parsing.d.ts.map +1 -0
  35. package/dist/sinatra-frame-parsing.js +142 -0
  36. package/dist/sinatra-frame-parsing.js.map +1 -0
  37. package/dist/sinatra-stack-trace-parser.d.ts +18 -0
  38. package/dist/sinatra-stack-trace-parser.d.ts.map +1 -0
  39. package/dist/sinatra-stack-trace-parser.js +50 -0
  40. package/dist/sinatra-stack-trace-parser.js.map +1 -0
  41. package/package.json +30 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruby-stack-trace-parser.js","sourceRoot":"","sources":["../src/ruby-stack-trace-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEnF,MAAM,UAAU,0BAA0B,CAAC,QAAgC;IACzE,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,OAAe;YACzB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAE1C,MAAM,MAAM,GAAiB,EAAE,CAAC;YAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,mEAAmE;gBACnE,kEAAkE;gBAClE,6DAA6D;gBAC7D,4DAA4D;gBAC5D,MAAM,GAAG,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;gBACnE,IAAI,GAAG,KAAK,IAAI;oBAAE,SAAS;gBAE3B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;oBACtC,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,IAAI;oBACZ,YAAY,EAAE,GAAG,CAAC,YAAY;iBAC/B,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,2DAA2D;gBAC3D,2DAA2D;gBAC3D,oEAAoE;gBACpE,OAAO,IAAI,CAAC;YACd,CAAC;YAED,kEAAkE;YAClE,mEAAmE;YACnE,oEAAoE;YACpE,qEAAqE;YACrE,sEAAsE;YACtE,mEAAmE;YACnE,oCAAoC;YACpC,EAAE;YACF,gEAAgE;YAChE,kEAAkE;YAClE,oBAAoB;YACpB,oEAAoE;YACpE,sEAAsE;YACtE,mEAAmE;YACnE,iEAAiE;YACjE,mEAAmE;YACnE,mEAAmE;YACnE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Sinatra's production-mode backtrace grammar, which is **not Ruby's** —
3
+ * the plan's 1C measurement, and Sinatra's own answer to the question
4
+ * `rails-frame-parsing.ts` asked of Rails.
5
+ *
6
+ * ## The measurement
7
+ *
8
+ * A real Sinatra 4.1.1 app, `set :environment, :production`, spawned
9
+ * through the managed lifecycle, failing through its own request pipeline:
10
+ *
11
+ * ```
12
+ * 2026-08-21 00:27:09 - RuntimeError - invoice 3 is corrupt (RuntimeError):
13
+ * sinatra_service.rb:44:in 'Object#charge_invoice'
14
+ * sinatra_service.rb:51:in 'Object#delete_invoice'
15
+ * ...
16
+ * ```
17
+ *
18
+ * against Ruby's own printer, which the plain `ruby-frame-parsing.ts`
19
+ * classifier expects:
20
+ *
21
+ * ```
22
+ * sinatra_service.rb:44:in 'Object#charge_invoice': invoice 3 is corrupt (RuntimeError)
23
+ * from sinatra_service.rb:51:in 'Object#delete_invoice'
24
+ * ```
25
+ *
26
+ * Read off `Sinatra::Base#dump_errors!` (`sinatra/base.rb`) before this was
27
+ * run, then confirmed against the live process, matching exactly:
28
+ *
29
+ * ```ruby
30
+ * msg = ["#{Time.now...} - #{boom.class} - #{msg}:", *additional_msg, *boom.backtrace].join("\n\t")
31
+ * @env['rack.errors'].puts(msg)
32
+ * ```
33
+ *
34
+ * - **The header carries no location.** It is
35
+ * `TIMESTAMP - ClassName - message:`, never `file:line:in 'name': message`,
36
+ * so `HEADER_PATTERN` never matches it.
37
+ * - **The frames have no `from` prefix.** `boom.backtrace` is the raw
38
+ * `Exception#backtrace` array — Ruby's own top-level printer is what adds
39
+ * `from `, not `Exception#backtrace` itself — so `FROM_FRAME_PATTERN`
40
+ * never matches them either.
41
+ *
42
+ * Result, measured against the live process rather than assumed:
43
+ * **0 headers, 0 frames** — RT-111's exact signature, on the framework
44
+ * built directly on Rack rather than on Rack itself. (Bare Rack — no
45
+ * framework at all — was also measured, in `rack-framework-lifecycle.test.ts`,
46
+ * and needed no new grammar: its dispatch frames print in Ruby's own
47
+ * `file:line:in 'name'` / `from ...` shape and the existing classifier
48
+ * reads them unchanged.)
49
+ *
50
+ * ## Why this is a third classifier, not a widened Rails one
51
+ *
52
+ * Sinatra's header shape (`TIMESTAMP - Class - message:`) and Rails'
53
+ * (`Class (message):`) are different enough that one pattern covering both
54
+ * would have to be loose enough to risk matching an application's own log
55
+ * line — the same rule that ruled out widening Ruby's `isFrame` for Rails
56
+ * (see `rails-frame-parsing.ts`). The bare `file:line:in 'name'` frame shape
57
+ * *is* identical to Rails' — both are literally `Exception#backtrace`
58
+ * entries with no `from` — but is kept as its own pattern here rather than
59
+ * imported from `rails-frame-parsing.ts`, so a change scoped to one
60
+ * framework's grammar can never silently reach the other's.
61
+ *
62
+ * `isFrame` is stateful for the same reason Rails' is: a bare
63
+ * `file:line:in 'name'` is confined to "after a header has been seen" so it
64
+ * can never open a block from idle on its own.
65
+ */
66
+ export interface RawSinatraFrame {
67
+ /** `Object#charge_invoice`, `block in Sinatra::Base#dispatch!` — kept verbatim, never rewritten. */
68
+ readonly functionName: string | null;
69
+ readonly file: string;
70
+ readonly line: number;
71
+ }
72
+ export declare function isSinatraHeaderLine(line: string): boolean;
73
+ export declare function isSinatraFrameLine(line: string): boolean;
74
+ /** `null` when the line is not `TIMESTAMP - Class - message:` shaped — never fabricated. */
75
+ export declare function parseSinatraHeader(line: string): {
76
+ readonly exceptionClass: string;
77
+ readonly message: string;
78
+ } | null;
79
+ /** `null` for anything not shaped like a bare `file:line:in 'name'` frame — never fabricated. */
80
+ export declare function parseSinatraFrame(line: string): RawSinatraFrame | null;
81
+ /**
82
+ * A stateful `LineClassifier` — see this file's header for why the loose
83
+ * frame pattern is safe only inside that state.
84
+ *
85
+ * A fresh classifier per collector keeps two processes' output from priming
86
+ * each other, the same construction rule every other adapter here follows.
87
+ */
88
+ export declare function createSinatraLineClassifier(): {
89
+ isHeader(line: string): boolean;
90
+ isFrame(line: string): boolean;
91
+ };
92
+ //# sourceMappingURL=sinatra-frame-parsing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinatra-frame-parsing.d.ts","sourceRoot":"","sources":["../src/sinatra-frame-parsing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AAEH,MAAM,WAAW,eAAe;IAC9B,oGAAoG;IACpG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAwBD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAMrH;AAED,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAOtE;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,IAAI;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC,CAqBA"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Sinatra's production-mode backtrace grammar, which is **not Ruby's** —
3
+ * the plan's 1C measurement, and Sinatra's own answer to the question
4
+ * `rails-frame-parsing.ts` asked of Rails.
5
+ *
6
+ * ## The measurement
7
+ *
8
+ * A real Sinatra 4.1.1 app, `set :environment, :production`, spawned
9
+ * through the managed lifecycle, failing through its own request pipeline:
10
+ *
11
+ * ```
12
+ * 2026-08-21 00:27:09 - RuntimeError - invoice 3 is corrupt (RuntimeError):
13
+ * sinatra_service.rb:44:in 'Object#charge_invoice'
14
+ * sinatra_service.rb:51:in 'Object#delete_invoice'
15
+ * ...
16
+ * ```
17
+ *
18
+ * against Ruby's own printer, which the plain `ruby-frame-parsing.ts`
19
+ * classifier expects:
20
+ *
21
+ * ```
22
+ * sinatra_service.rb:44:in 'Object#charge_invoice': invoice 3 is corrupt (RuntimeError)
23
+ * from sinatra_service.rb:51:in 'Object#delete_invoice'
24
+ * ```
25
+ *
26
+ * Read off `Sinatra::Base#dump_errors!` (`sinatra/base.rb`) before this was
27
+ * run, then confirmed against the live process, matching exactly:
28
+ *
29
+ * ```ruby
30
+ * msg = ["#{Time.now...} - #{boom.class} - #{msg}:", *additional_msg, *boom.backtrace].join("\n\t")
31
+ * @env['rack.errors'].puts(msg)
32
+ * ```
33
+ *
34
+ * - **The header carries no location.** It is
35
+ * `TIMESTAMP - ClassName - message:`, never `file:line:in 'name': message`,
36
+ * so `HEADER_PATTERN` never matches it.
37
+ * - **The frames have no `from` prefix.** `boom.backtrace` is the raw
38
+ * `Exception#backtrace` array — Ruby's own top-level printer is what adds
39
+ * `from `, not `Exception#backtrace` itself — so `FROM_FRAME_PATTERN`
40
+ * never matches them either.
41
+ *
42
+ * Result, measured against the live process rather than assumed:
43
+ * **0 headers, 0 frames** — RT-111's exact signature, on the framework
44
+ * built directly on Rack rather than on Rack itself. (Bare Rack — no
45
+ * framework at all — was also measured, in `rack-framework-lifecycle.test.ts`,
46
+ * and needed no new grammar: its dispatch frames print in Ruby's own
47
+ * `file:line:in 'name'` / `from ...` shape and the existing classifier
48
+ * reads them unchanged.)
49
+ *
50
+ * ## Why this is a third classifier, not a widened Rails one
51
+ *
52
+ * Sinatra's header shape (`TIMESTAMP - Class - message:`) and Rails'
53
+ * (`Class (message):`) are different enough that one pattern covering both
54
+ * would have to be loose enough to risk matching an application's own log
55
+ * line — the same rule that ruled out widening Ruby's `isFrame` for Rails
56
+ * (see `rails-frame-parsing.ts`). The bare `file:line:in 'name'` frame shape
57
+ * *is* identical to Rails' — both are literally `Exception#backtrace`
58
+ * entries with no `from` — but is kept as its own pattern here rather than
59
+ * imported from `rails-frame-parsing.ts`, so a change scoped to one
60
+ * framework's grammar can never silently reach the other's.
61
+ *
62
+ * `isFrame` is stateful for the same reason Rails' is: a bare
63
+ * `file:line:in 'name'` is confined to "after a header has been seen" so it
64
+ * can never open a block from idle on its own.
65
+ */
66
+ /**
67
+ * `2026-08-21 00:27:09 - RuntimeError - invoice 3 is corrupt (RuntimeError):`
68
+ *
69
+ * `Sinatra::Base#dump_errors!` composes
70
+ * `"#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{msg}:"`.
71
+ * Anchored at the start (the timestamp is always first — Sinatra never
72
+ * prefixes it, unlike Ruby's own header pattern which allows a leading
73
+ * logger prefix) and requiring the trailing `:`, because a partial match is
74
+ * evidence the line is not a header rather than a reason to guess at one.
75
+ * The class group allows `::` so a namespaced error class matches.
76
+ */
77
+ const SINATRA_HEADER = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} - (?<class>[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*) - (?<message>.*):\s*$/;
78
+ /**
79
+ * `sinatra_service.rb:44:in 'Object#charge_invoice'` — a raw
80
+ * `Exception#backtrace` entry, tab-indented by `dump_errors!`'s own
81
+ * `join("\n\t")`, no `from` prefix. The closing quote is always `'`; only
82
+ * the opening one varies by Ruby version (Feature #16495), matched the same
83
+ * way Ruby's and Rails' own patterns do.
84
+ */
85
+ const SINATRA_FRAME = /^\s*(?<file>.+):(?<line>\d+):in\s+[`'](?<fn>[^']*)'\s*$/;
86
+ export function isSinatraHeaderLine(line) {
87
+ return SINATRA_HEADER.test(line);
88
+ }
89
+ export function isSinatraFrameLine(line) {
90
+ return SINATRA_FRAME.test(line);
91
+ }
92
+ /** `null` when the line is not `TIMESTAMP - Class - message:` shaped — never fabricated. */
93
+ export function parseSinatraHeader(line) {
94
+ const match = SINATRA_HEADER.exec(line);
95
+ if (!match?.groups)
96
+ return null;
97
+ const exceptionClass = match.groups["class"];
98
+ if (exceptionClass === undefined)
99
+ return null;
100
+ return { exceptionClass, message: match.groups["message"] ?? "" };
101
+ }
102
+ /** `null` for anything not shaped like a bare `file:line:in 'name'` frame — never fabricated. */
103
+ export function parseSinatraFrame(line) {
104
+ const match = SINATRA_FRAME.exec(line);
105
+ if (!match?.groups)
106
+ return null;
107
+ const file = match.groups["file"];
108
+ const lineNumber = Number(match.groups["line"]);
109
+ if (file === undefined || !Number.isInteger(lineNumber))
110
+ return null;
111
+ return { functionName: match.groups["fn"] ?? null, file, line: lineNumber };
112
+ }
113
+ /**
114
+ * A stateful `LineClassifier` — see this file's header for why the loose
115
+ * frame pattern is safe only inside that state.
116
+ *
117
+ * A fresh classifier per collector keeps two processes' output from priming
118
+ * each other, the same construction rule every other adapter here follows.
119
+ */
120
+ export function createSinatraLineClassifier() {
121
+ let sawHeader = false;
122
+ return {
123
+ isHeader(line) {
124
+ if (isSinatraHeaderLine(line)) {
125
+ sawHeader = true;
126
+ return true;
127
+ }
128
+ return false;
129
+ },
130
+ isFrame(line) {
131
+ // Never from idle. A bare `x.rb:12:in 'foo'` is frame-shaped and is
132
+ // also an entirely ordinary thing for an application to log.
133
+ if (!sawHeader)
134
+ return false;
135
+ if (isSinatraFrameLine(line))
136
+ return true;
137
+ sawHeader = false;
138
+ return false;
139
+ },
140
+ };
141
+ }
142
+ //# sourceMappingURL=sinatra-frame-parsing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinatra-frame-parsing.js","sourceRoot":"","sources":["../src/sinatra-frame-parsing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AASH;;;;;;;;;;GAUG;AACH,MAAM,cAAc,GAAG,oHAAoH,CAAC;AAE5I;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,yDAAyD,CAAC;AAEhF,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;AACpE,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B;IAIzC,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,OAAO;QACL,QAAQ,CAAC,IAAY;YACnB,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,SAAS,GAAG,IAAI,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,IAAY;YAClB,oEAAoE;YACpE,6DAA6D;YAC7D,IAAI,CAAC,SAAS;gBAAE,OAAO,KAAK,CAAC;YAC7B,IAAI,kBAAkB,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC1C,SAAS,GAAG,KAAK,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Composes Sinatra's line-recognition functions with a
3
+ * `SourceLocationResolver` (plan 1C, mirroring `rails-stack-trace-parser.ts`).
4
+ *
5
+ * Sinatra's header carries **no location at all** —
6
+ * `TIMESTAMP - Class - message:` — so, exactly as for Rails, the raise site
7
+ * is the first backtrace line beneath the header rather than the header
8
+ * itself. `primaryFrameIndex` is `0` for the same reason Rails' is: the
9
+ * header contributes no frame, so index 0 is the first line Sinatra
10
+ * printed, and `Exception#backtrace` is innermost-first.
11
+ *
12
+ * `fidelity` is `"synchronous"` for the same reason every other Ruby
13
+ * parser's is: every frame is a genuine link in the call chain that was
14
+ * executing.
15
+ */
16
+ import type { SourceLocationResolver, StackTraceParser } from "@descryy/runtime-backend-observation";
17
+ export declare function createSinatraStackTraceParser(resolver: SourceLocationResolver): StackTraceParser;
18
+ //# sourceMappingURL=sinatra-stack-trace-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinatra-stack-trace-parser.d.ts","sourceRoot":"","sources":["../src/sinatra-stack-trace-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAIrG,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,sBAAsB,GAAG,gBAAgB,CAkChG"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Composes Sinatra's line-recognition functions with a
3
+ * `SourceLocationResolver` (plan 1C, mirroring `rails-stack-trace-parser.ts`).
4
+ *
5
+ * Sinatra's header carries **no location at all** —
6
+ * `TIMESTAMP - Class - message:` — so, exactly as for Rails, the raise site
7
+ * is the first backtrace line beneath the header rather than the header
8
+ * itself. `primaryFrameIndex` is `0` for the same reason Rails' is: the
9
+ * header contributes no frame, so index 0 is the first line Sinatra
10
+ * printed, and `Exception#backtrace` is innermost-first.
11
+ *
12
+ * `fidelity` is `"synchronous"` for the same reason every other Ruby
13
+ * parser's is: every frame is a genuine link in the call chain that was
14
+ * executing.
15
+ */
16
+ import { parseSinatraFrame, parseSinatraHeader } from "./sinatra-frame-parsing.js";
17
+ export function createSinatraStackTraceParser(resolver) {
18
+ return {
19
+ async parse(rawText) {
20
+ const lines = rawText.split(/\r\n|\r|\n/);
21
+ const frames = [];
22
+ for (const line of lines) {
23
+ // The header is tried first and produces no frame — it has no
24
+ // location to produce one from. Skipped explicitly rather than
25
+ // falling through, because `TIMESTAMP - Class - message:` can
26
+ // itself contain a colon-and-number substring that would otherwise
27
+ // be worth checking against the frame pattern.
28
+ if (parseSinatraHeader(line) !== null)
29
+ continue;
30
+ const raw = parseSinatraFrame(line);
31
+ if (raw === null)
32
+ continue;
33
+ const location = await resolver.resolve({
34
+ file: raw.file,
35
+ line: raw.line,
36
+ column: null,
37
+ functionName: raw.functionName,
38
+ });
39
+ frames.push({ location, raw: line });
40
+ }
41
+ // Null, never an empty-but-structured StackTrace standing in for
42
+ // "couldn't parse" — this interface's contract, and the reason a
43
+ // header-only block does not become a zero-frame trace.
44
+ if (frames.length === 0)
45
+ return null;
46
+ return { fidelity: "synchronous", frames, primaryFrameIndex: 0 };
47
+ },
48
+ };
49
+ }
50
+ //# sourceMappingURL=sinatra-stack-trace-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinatra-stack-trace-parser.js","sourceRoot":"","sources":["../src/sinatra-stack-trace-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEnF,MAAM,UAAU,6BAA6B,CAAC,QAAgC;IAC5E,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,OAAe;YACzB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAE1C,MAAM,MAAM,GAAiB,EAAE,CAAC;YAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,8DAA8D;gBAC9D,+DAA+D;gBAC/D,8DAA8D;gBAC9D,mEAAmE;gBACnE,+CAA+C;gBAC/C,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,IAAI;oBAAE,SAAS;gBAEhD,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACpC,IAAI,GAAG,KAAK,IAAI;oBAAE,SAAS;gBAE3B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;oBACtC,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,IAAI;oBACZ,YAAY,EAAE,GAAG,CAAC,YAAY;iBAC/B,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,CAAC;YAED,iEAAiE;YACjE,iEAAiE;YACjE,wDAAwD;YACxD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAErC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@descryy/runtime-adapter-ruby",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "description": "Ruby runtime adapter: backtrace parsing, self-contained source locations, the concrete RuntimeAdapter for Ruby.",
6
+ "license": "UNLICENSED",
7
+ "engines": {
8
+ "node": ">=22.5"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "registry": "https://registry.npmjs.org",
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc -b"
25
+ },
26
+ "dependencies": {
27
+ "@descryy/runtime-contracts": "*",
28
+ "@descryy/runtime-backend-observation": "*"
29
+ }
30
+ }