diff --git a/graph/bundle/SCHEMA.md b/graph/bundle/SCHEMA.md index 6cd2c4bd2..3b54dcc71 100644 --- a/graph/bundle/SCHEMA.md +++ b/graph/bundle/SCHEMA.md @@ -566,6 +566,7 @@ THE GRAPH. One row per (site, resolved target). A site with N possible targets h | `fan_capped` | javascript, java, csharp | More targets than --dispatch-cap: the set was refused rather than emitted. JavaScript: callee is NULL. Java and C#: callee is the declared base method the fan would have started from; dispatch-capped-sites.csv carries the refused count. | | `callback_registered` | javascript, typescript | The site HANDS the callee this function (`xs.forEach(f)`, `p.then(f)`, `emitter.on('x', h)`, `setTimeout(f)`), which may invoke it. Not the site's own callee; a reachability edge, labelled so it is never read as a resolved call. | | `callback_registered` | python | A method or function named as a VALUE and handed over, stored or returned (`pool.submit(self.work)`, `Thread(target=svc.run)`, `sorted(xs, key=self.rank)`, `[h.on_event]`), always kind METHOD_REFERENCE. Its target is resolved the way a call on the same receiver would be; whoever receives the value calls it. A reachability edge, labelled so it is never read as a resolved call. | +| `callback_handed` | typescript | The site hands a function to a PROJECT function whose body can run it (`withRetry(2, () => load(id))`, `apply(upper, s)`). Not the site's own callee (that is the row for the called function); a reachability edge from the hand-over site, like callback_registered. Not emitted for a getter read, a parameter the body never reads or only compares, or a keyed registry's slot. | | `event_dispatch` | javascript | `x.emit('name')` reaching a handler registered by `x.on('name', h)` on a value x may hold — name-sensitive for literal names, every handler on that value for a computed one. | | `event_dispatch` | typescript | A publish on a project class's keyed registry reaching each function filed under the same key: `bus.publish('x', p)` where `publish` (or a method it passes the key to) calls what `this.handlers.get(name)` holds, to the function a `bus.subscribe('x', f)` stored there, or an entry `{ ['x']: f }` of a table a subscribe-all method files by key. A literal, a const or a const-object member key; a key only known at run time matches every key, and a constant the dispatch also looks up (a wildcard) matches every publish. The site is the publish call (call-edge-generation/keyed_registry.dl). | | `event_dispatch` | java | A Spring application event: `publishEvent(e)` reaching each listener (`@EventListener`, `@TransactionalEventListener`, `ApplicationListener.onApplicationEvent`) whose declared event type e's static type is, or is a subtype of. Added beside the publishEvent boundary row, never in place of it (call-edge-generation/event_dispatch.dl). Also a JPA entity write (`save`, `persist`, `merge`, `delete` on a repository or EntityManager) reaching the `@PrePersist`/`@PreUpdate`/`@PreRemove`-style callbacks of the written entity's type and of the listeners `@EntityListeners` names on it or a superclass (kind entity_callback; call-edge-generation/entity_lifecycle.dl). | @@ -588,7 +589,7 @@ THE GRAPH. One row per (site, resolved target). A site with N possible targets h - **python** — A `boundary_lib` edge may point at a builtin (callee_provenance builtin, callee_label `builtin:NAME`) or at an unstaged import path (callee_provenance external) — neither has a methods row. - **java** — A `boundary_lib` edge with callee_provenance external names a method of an ancestor type no staged IR declares (callee_label `external:.`, no methods row). A site whose receiver is declared as such a type is multi_inferred even with one client override: the platform method itself, and the platform's own subclasses, are the other possible targets. Stage the library to replace the label with the real method. - **python** — The reason a site is ambiguous_unknown is exported per site in ext_call_site_unresolved (site, caller, reason, detail). -- **all** — THE TRUST LINE, and it is not the same set of tiers in every language. RESOLVED (callee_method_id is set): known_edge and multi_inferred in every language, and boundary_lib where the library is staged (--library) — without it boundary_lib names the target in callee_label and leaves callee_method_id NULL; ALSO ambient_terminal in TypeScript, fan_capped in Java and C# (the declared base, the fan refused), and runtime_observed in C#. HANDED OVER (callee set, but the site passes the function rather than calling it): callback_registered and event_dispatch in JavaScript and TypeScript, callback_registered (kind METHOD_REFERENCE) in Python; event_dispatch in C# too, where a mediator Send or Publish runs the handler for the request type, beside the row for the site itself. CORRECT END (callee NULL, and nothing is missing): intrinsic_terminal in TypeScript; ambient_terminal, implicit_constructor and dynamic_terminal in JavaScript; known_implicit_ctor, known_builtin_operator and boundary_generated (callee_label set) in C#. BLIND SPOT (callee NULL; exactly the tiers named `ambiguous_*`, which are what unresolved_sites holds): ambiguous_unknown everywhere, ALSO ambiguous_anon in Java and ambiguous_dynamic in C#. CAPPED (callee NULL, not in unresolved_sites): fan_capped in JavaScript. Python emits the four shared tiers and callback_registered. A filter written as `tier IN (known_edge, multi_inferred)` therefore drops resolved edges in every language but Python — derive the set from this note or from unresolved_sites, never from a hardcoded list. +- **all** — THE TRUST LINE, and it is not the same set of tiers in every language. RESOLVED (callee_method_id is set): known_edge and multi_inferred in every language, and boundary_lib where the library is staged (--library) — without it boundary_lib names the target in callee_label and leaves callee_method_id NULL; ALSO ambient_terminal in TypeScript, fan_capped in Java and C# (the declared base, the fan refused), and runtime_observed in C#. HANDED OVER (callee set, but the site passes the function rather than calling it): callback_registered and event_dispatch in JavaScript and TypeScript, ALSO callback_handed in TypeScript, callback_registered (kind METHOD_REFERENCE) in Python; event_dispatch in C# too, where a mediator Send or Publish runs the handler for the request type, beside the row for the site itself. CORRECT END (callee NULL, and nothing is missing): intrinsic_terminal in TypeScript; ambient_terminal, implicit_constructor and dynamic_terminal in JavaScript; known_implicit_ctor, known_builtin_operator and boundary_generated (callee_label set) in C#. BLIND SPOT (callee NULL; exactly the tiers named `ambiguous_*`, which are what unresolved_sites holds): ambiguous_unknown everywhere, ALSO ambiguous_anon in Java and ambiguous_dynamic in C#. CAPPED (callee NULL, not in unresolved_sites): fan_capped in JavaScript. Python emits the four shared tiers and callback_registered. A filter written as `tier IN (known_edge, multi_inferred)` therefore drops resolved edges in every language but Python — derive the set from this note or from unresolved_sites, never from a hardcoded list. - **java** — A multi_inferred fan is CHA-wide: it is every override the hierarchy admits, bounded only by the dispatch cap. type_instantiated is computed and exported but NOT read by any rule, so the fan is not narrowed to types the program constructs. Narrow it yourself by joining dispatch_candidates to type_instantiated — see the dispatch_envelope_of query. A receiver is ALSO typed by what flows into it (a local's initializer, the arguments callers pass to a parameter, the receivers callers invoke a method on for its `this`), and each flow-in type resolves its member directly, outside the fan: that is why a `fan_capped` site still carries edges, and why they are the types the program was seen to hand over, not the whole hierarchy. - **typescript** — A multi_inferred fan is CHA-wide, as in Java: type_instantiated is computed and exported but NOT read by any rule. The fan also has sources that are not virtual dispatch at all — an overload set or a union-typed receiver produces one too. - **python** — A multi_inferred fan IS narrowed by the instantiation set: type_instantiated_reachable (the constructed classes and their bases) bounds dispatch in resolution/dispatch.dl. Python is the only front end where that narrowing is applied, so a fan here is tighter than the same shape would be in Java or TypeScript. diff --git a/graph/bundle/catalog.ts b/graph/bundle/catalog.ts index 9e216e7d6..036262536 100644 --- a/graph/bundle/catalog.ts +++ b/graph/bundle/catalog.ts @@ -24,11 +24,13 @@ export interface ExtRelation { */ export const EXT_QUERIED: ReadonlySet = new Set([ 'bean_def', 'call_runs_edge', 'call_site_unresolved', 'config_affects_method', 'config_binding', 'config_key_ref', - 'config_unresolved', 'ctor_implicit_type', 'decorated_name_target', 'di_edge', 'fn_value_call', 'framework_edge', + 'config_unresolved', 'ctor_implicit_type', 'ctx_key_flow', 'decorated_name_target', 'di_edge', 'fn_value_call', + 'framework_edge', 'framework_undetermined', 'http_mount', 'http_route', 'http_route_partial', 'http_served_by', 'inject_point', 'lib_callback_edge', 'lib_callback_site', 'library_receiver', 'method_returns_method', - 'method_returns_param', 'persistence_field', 'remote_edge', 'remote_unsent', 'remote_unserved', 'return_value', - 'state_call_alloc', 'state_call_open', 'state_gate', 'state_gate_alloc', 'state_world_of_gated', - 'type_base_unresolved', 'unresolved_value_callee', + 'method_returns_param', 'middleware_applies', 'middleware_may_apply', 'middleware_registered_at', 'middleware_site', + 'persistence_field', 'registration_conditional', 'remote_edge', 'remote_unsent', 'remote_unserved', 'return_value', + 'route_registered_by', 'route_schema', 'router_node_at', 'state_call_alloc', 'state_call_open', 'state_gate', + 'state_gate_alloc', 'state_world_of_gated', 'type_base_unresolved', 'unresolved_value_callee', 'valid_read', ]); /** relationfile per line; comments and blanks skipped. */ diff --git a/graph/bundle/schema.ts b/graph/bundle/schema.ts index 9d71c3906..906ca4eda 100644 --- a/graph/bundle/schema.ts +++ b/graph/bundle/schema.ts @@ -525,6 +525,7 @@ export const VOCAB: readonly VocabSpec[] = [ { table: 'call_edges', column: 'tier', value: 'fan_capped', languages: ['javascript', 'java', 'csharp'], meaning: 'More targets than --dispatch-cap: the set was refused rather than emitted. JavaScript: callee is NULL. Java and C#: callee is the declared base method the fan would have started from; dispatch-capped-sites.csv carries the refused count.' }, { table: 'call_edges', column: 'tier', value: 'callback_registered', languages: ['javascript', 'typescript'], meaning: 'The site HANDS the callee this function (`xs.forEach(f)`, `p.then(f)`, `emitter.on(\'x\', h)`, `setTimeout(f)`), which may invoke it. Not the site\'s own callee; a reachability edge, labelled so it is never read as a resolved call.' }, { table: 'call_edges', column: 'tier', value: 'callback_registered', languages: P, meaning: 'A method or function named as a VALUE and handed over, stored or returned (`pool.submit(self.work)`, `Thread(target=svc.run)`, `sorted(xs, key=self.rank)`, `[h.on_event]`), always kind METHOD_REFERENCE. Its target is resolved the way a call on the same receiver would be; whoever receives the value calls it. A reachability edge, labelled so it is never read as a resolved call.' }, + { table: 'call_edges', column: 'tier', value: 'callback_handed', languages: T, meaning: 'The site hands a function to a PROJECT function whose body can run it (`withRetry(2, () => load(id))`, `apply(upper, s)`). Not the site\'s own callee (that is the row for the called function); a reachability edge from the hand-over site, like callback_registered. Not emitted for a getter read, a parameter the body never reads or only compares, or a keyed registry\'s slot.' }, { table: 'call_edges', column: 'tier', value: 'event_dispatch', languages: S, meaning: '`x.emit(\'name\')` reaching a handler registered by `x.on(\'name\', h)` on a value x may hold — name-sensitive for literal names, every handler on that value for a computed one.' }, { table: 'call_edges', column: 'tier', value: 'event_dispatch', languages: T, meaning: 'A publish on a project class\'s keyed registry reaching each function filed under the same key: `bus.publish(\'x\', p)` where `publish` (or a method it passes the key to) calls what `this.handlers.get(name)` holds, to the function a `bus.subscribe(\'x\', f)` stored there, or an entry `{ [\'x\']: f }` of a table a subscribe-all method files by key. A literal, a const or a const-object member key; a key only known at run time matches every key, and a constant the dispatch also looks up (a wildcard) matches every publish. The site is the publish call (call-edge-generation/keyed_registry.dl).' }, { table: 'call_edges', column: 'tier', value: 'event_dispatch', languages: J, meaning: 'A Spring application event: `publishEvent(e)` reaching each listener (`@EventListener`, `@TransactionalEventListener`, `ApplicationListener.onApplicationEvent`) whose declared event type e\'s static type is, or is a subtype of. Added beside the publishEvent boundary row, never in place of it (call-edge-generation/event_dispatch.dl). Also a JPA entity write (`save`, `persist`, `merge`, `delete` on a repository or EntityManager) reaching the `@PrePersist`/`@PreUpdate`/`@PreRemove`-style callbacks of the written entity\'s type and of the listeners `@EntityListeners` names on it or a superclass (kind entity_callback; call-edge-generation/entity_lifecycle.dl).' }, @@ -773,7 +774,7 @@ export const NOTES: readonly NoteSpec[] = [ { language: 'python', table: 'entry_points', note: 'Framework entry points only: url, http, orm_hook, task, signal_receiver, fixture, di_provider and grpc_service. There is no test and no main reason: a pytest test is recognised by the query layer from its file and name, not here.' }, { language: 'python', table: 'overrides', note: 'EMPTY — this table is Java-shaped. The Python dispatch envelope is in dispatch_candidates with basis `mro`, and `value` for a function assigned onto an instance\'s member; the raw linearisation is in ext_mro_position.' }, { language: 'python', table: 'type_instantiated', note: 'Every row has how = `new`: the rule set records that some client call constructs the class, not which form.' }, - { language: 'all', table: 'call_edges', note: 'THE TRUST LINE, and it is not the same set of tiers in every language. RESOLVED (callee_method_id is set): known_edge and multi_inferred in every language, and boundary_lib where the library is staged (--library) — without it boundary_lib names the target in callee_label and leaves callee_method_id NULL; ALSO ambient_terminal in TypeScript, fan_capped in Java and C# (the declared base, the fan refused), and runtime_observed in C#. HANDED OVER (callee set, but the site passes the function rather than calling it): callback_registered and event_dispatch in JavaScript and TypeScript, callback_registered (kind METHOD_REFERENCE) in Python; event_dispatch in C# too, where a mediator Send or Publish runs the handler for the request type, beside the row for the site itself. CORRECT END (callee NULL, and nothing is missing): intrinsic_terminal in TypeScript; ambient_terminal, implicit_constructor and dynamic_terminal in JavaScript; known_implicit_ctor, known_builtin_operator and boundary_generated (callee_label set) in C#. BLIND SPOT (callee NULL; exactly the tiers named `ambiguous_*`, which are what unresolved_sites holds): ambiguous_unknown everywhere, ALSO ambiguous_anon in Java and ambiguous_dynamic in C#. CAPPED (callee NULL, not in unresolved_sites): fan_capped in JavaScript. Python emits the four shared tiers and callback_registered. A filter written as `tier IN (known_edge, multi_inferred)` therefore drops resolved edges in every language but Python — derive the set from this note or from unresolved_sites, never from a hardcoded list.' }, + { language: 'all', table: 'call_edges', note: 'THE TRUST LINE, and it is not the same set of tiers in every language. RESOLVED (callee_method_id is set): known_edge and multi_inferred in every language, and boundary_lib where the library is staged (--library) — without it boundary_lib names the target in callee_label and leaves callee_method_id NULL; ALSO ambient_terminal in TypeScript, fan_capped in Java and C# (the declared base, the fan refused), and runtime_observed in C#. HANDED OVER (callee set, but the site passes the function rather than calling it): callback_registered and event_dispatch in JavaScript and TypeScript, ALSO callback_handed in TypeScript, callback_registered (kind METHOD_REFERENCE) in Python; event_dispatch in C# too, where a mediator Send or Publish runs the handler for the request type, beside the row for the site itself. CORRECT END (callee NULL, and nothing is missing): intrinsic_terminal in TypeScript; ambient_terminal, implicit_constructor and dynamic_terminal in JavaScript; known_implicit_ctor, known_builtin_operator and boundary_generated (callee_label set) in C#. BLIND SPOT (callee NULL; exactly the tiers named `ambiguous_*`, which are what unresolved_sites holds): ambiguous_unknown everywhere, ALSO ambiguous_anon in Java and ambiguous_dynamic in C#. CAPPED (callee NULL, not in unresolved_sites): fan_capped in JavaScript. Python emits the four shared tiers and callback_registered. A filter written as `tier IN (known_edge, multi_inferred)` therefore drops resolved edges in every language but Python — derive the set from this note or from unresolved_sites, never from a hardcoded list.' }, { language: 'java', table: 'call_edges', note: 'A multi_inferred fan is CHA-wide: it is every override the hierarchy admits, bounded only by the dispatch cap. type_instantiated is computed and exported but NOT read by any rule, so the fan is not narrowed to types the program constructs. Narrow it yourself by joining dispatch_candidates to type_instantiated — see the dispatch_envelope_of query. A receiver is ALSO typed by what flows into it (a local\'s initializer, the arguments callers pass to a parameter, the receivers callers invoke a method on for its `this`), and each flow-in type resolves its member directly, outside the fan: that is why a `fan_capped` site still carries edges, and why they are the types the program was seen to hand over, not the whole hierarchy.' }, { language: 'typescript', table: 'call_edges', note: 'A multi_inferred fan is CHA-wide, as in Java: type_instantiated is computed and exported but NOT read by any rule. The fan also has sources that are not virtual dispatch at all — an overload set or a union-typed receiver produces one too.' }, { language: 'python', table: 'call_edges', note: 'A multi_inferred fan IS narrowed by the instantiation set: type_instantiated_reachable (the constructed classes and their bases) bounds dispatch in resolution/dispatch.dl. Python is the only front end where that narrowing is applied, so a fan here is tighter than the same shape would be in Java or TypeScript.' }, diff --git a/graph/javascript/engine/call-edge-generation/dispatch-envelope.dl b/graph/javascript/engine/call-edge-generation/dispatch-envelope.dl new file mode 100644 index 000000000..d5e7c9067 --- /dev/null +++ b/graph/javascript/engine/call-edge-generation/dispatch-envelope.dl @@ -0,0 +1,14 @@ +// ============================================================================ +// Call-edge generation · THE DISPATCH AND FUNCTION-VALUE ENVELOPE (exported, as TypeScript exports it) +// +// The flow engine resolves a call to the functions its receiver's VALUE may run, so a +// JavaScript call edge already names the override that runs. The two envelope relations +// TypeScript exports are kept here under the same names and columns, so a reader that widens +// a call to what may run (impact, the chain checks) reads one schema for both languages: +// +// method_dispatch_candidate(Base, Impl, Kind) Impl, in a subclass, overrides Base +// fn_value_call(Caller, Fn) Caller hands Fn over at a call that runs it +// ============================================================================ +method_dispatch_candidate(base, impl, "override") :- type_own_member(t, n, impl), type_ancestor(t, s), + type_own_member(s, n, base), base != impl. +fn_value_call(caller, m) :- call_chain_edge(_, caller, "-", m, "client", "callback_registered", _), caller != m. diff --git a/graph/javascript/engine/config-resolution/http-router-apps.dl b/graph/javascript/engine/config-resolution/http-router-apps.dl new file mode 100644 index 000000000..41dafd035 --- /dev/null +++ b/graph/javascript/engine/config-resolution/http-router-apps.dl @@ -0,0 +1,190 @@ +// ============================================================================ +// CONFIG-RESOLUTION · HTTP ROUTER APPLICATIONS (JavaScript: which values are apps) +// +// The JavaScript counterpart of typescript/engine/config-resolution/http-router-apps.dl. +// JavaScript has no declared types, but it has resolution/value-flow.dl: a value +// follows its binding through consts, imports and exports (ESM and CommonJS), +// parameters at resolved calls and returned values. So an application is one more +// VALUE KIND there, `router_app`, keyed by the `new X()` that built it, and the flow +// engine carries it wherever it goes. Rules here only say where the value starts and +// which calls hand it back (`app.get(...)` returns the app, `basePath` a value sharing +// its route list). +// +// LIMIT, stated: a function that builds and returns an app yields the SAME value at +// every call here (the flow engine has one allocation per `new`), so two sub-apps made +// by one factory share a list. The TypeScript engine splits them per call. +// +// Framework names live in config-resolution/knobs.dl only (router_*). +// ============================================================================ + +// ── a specifier as the package it names ───────────────────────────────────── +// `npm:x@4/sub` and `jsr:@s/x@^4/sub` are `x/sub` and `@s/x/sub`; a URL under a knob +// prefix is the package (`/mod.ts`) or its subpath; anything else is itself. +.decl jr_spec_raw(c0:symbol) +jr_spec_raw(raw) :- import_decl(_, raw, _, _, _, _, _, _, _). +.decl jr_unscheme(c0:symbol, c1:symbol) +jr_unscheme(raw, x) :- jr_spec_raw(raw), router_spec_scheme(s), strlen(raw) > strlen(s), + substr(raw, 0, strlen(s)) = s, x = substr(raw, strlen(s), strlen(raw) - strlen(s)). +.decl jr_ver_at(c0:symbol, c1:number) +jr_ver_at(x, i) :- jr_unscheme(_, x), i = range(1, strlen(x)), substr(x, i, 1) = "@". +.decl jr_slash_after(c0:symbol, c1:number, c2:number) +jr_slash_after(x, i, j) :- jr_ver_at(x, i), j = range(i, strlen(x)), substr(x, j, 1) = "/". +.decl jr_ver_end(c0:symbol, c1:number, c2:number) +jr_ver_end(x, i, j) :- jr_ver_at(x, i), j = min y : { jr_slash_after(x, i, y) }. +jr_ver_end(x, i, strlen(x)) :- jr_ver_at(x, i), !jr_slash_after(x, i, _). +.decl jr_spec(c0:symbol, c1:symbol) +jr_spec(raw, raw) :- jr_spec_raw(raw). +jr_spec(raw, x) :- jr_unscheme(raw, x), !jr_ver_at(x, _). +jr_spec(raw, y) :- jr_unscheme(raw, x), jr_ver_at(x, i), jr_ver_end(x, i, j), + y = cat(substr(x, 0, i), substr(x, j, strlen(x) - j)). +.decl jr_url_rest(c0:symbol, c1:symbol, c2:symbol) +jr_url_rest(raw, pkg, rest) :- jr_spec_raw(raw), router_spec_url(pre, pkg), strlen(raw) > strlen(pre), + substr(raw, 0, strlen(pre)) = pre, rest = substr(raw, strlen(pre), strlen(raw) - strlen(pre)). +.decl jr_url_path(c0:symbol, c1:symbol, c2:symbol) +jr_url_path(raw, pkg, rest) :- jr_url_rest(raw, pkg, rest), substr(rest, 0, 1) = "/". +jr_url_path(raw, pkg, r2) :- jr_url_rest(raw, pkg, rest), substr(rest, 0, 1) = "@", + j = min y : { y = range(0, strlen(rest)), substr(rest, y, 1) = "/" }, r2 = substr(rest, j, strlen(rest) - j). +jr_spec(raw, pkg) :- jr_url_path(raw, pkg, "/mod.ts"). + +.decl jr_module(c0:symbol) +jr_module(spec) :- router_app_class(spec, _). +jr_module(spec) :- router_mw_wrapper(spec, _). +jr_module(spec) :- router_mw_combinator(spec, _). +jr_module(spec) :- router_mw_except(spec, _). +jr_module(spec) :- router_rpc_client(spec, _). +jr_module(spec) :- router_test_client(spec, _). +jr_module(spec) :- router_route_def(spec, _). + +// jr_ref(Expr, Specifier, Name): Expr denotes export Name of a knob module ("" = the +// module itself), through an import, a require, a destructure or a member read +.decl jr_ref(c0:symbol, c1:symbol, c2:symbol) +jr_ref(e, spec, "") :- expr_kind(_, "MODULE_EDGE_CALL", _, e), expr_module_edge(_, imp, e), + import_decl(_, raw, _, _, _, _, _, _, imp), jr_spec(raw, spec), jr_module(spec). +jr_ref(e, spec, "") :- expr_kind(_, "IDENTIFIER", _, e), expr_binding(_, v, e), var_import(_, imp, v), + import_decl(_, raw, _, bf, _, _, _, _, imp), import_binds_whole_module(bf), jr_spec(raw, spec), jr_module(spec). +jr_ref(e, spec, n) :- expr_kind(_, "IDENTIFIER", _, e), expr_binding(_, v, e), var_import(_, imp, v), + import_decl(_, raw, _, bf, n, _, _, _, imp), import_binding_is_named(bf), n != "", jr_spec(raw, spec), jr_module(spec). +jr_ref(e, spec, n) :- expr_kind(_, "PROPERTY_ACCESS", _, e), expr_name(_, n, e), + expr_child(_, e, "ACCESS_TARGET", _, r), jr_ref(r, spec, ""). +jr_ref(e, spec, n) :- expr_kind(_, "IDENTIFIER", _, e), expr_binding(_, v, e), !var_import(_, _, v), + var_init(_, _, i, v), jr_ref(i, spec, n). + +.decl jr_new(c0:symbol) +jr_new(ne) :- expr_kind(_, "NEW", _, ne), expr_child(_, ne, "CALLEE", _, c), jr_ref(c, spec, n), + router_app_class(spec, n). + +// ── the value kind ────────────────────────────────────────────────────────── +expr_value(ne, "router_app", ne) :- jr_new(ne). +expr_value(ce, "router_app", a) :- call_site(_, "METHOD_CALL", cn, _, r, _, ce, _, _), + (router_returns_app(cn) ; router_base_path(cn)), expr_value(r, "router_app", a). + +// ── a registration: a call on an app value ────────────────────────────────── +.decl jr_registrar(c0:symbol) +jr_registrar(n) :- router_verb(n, _). +jr_registrar(n) :- router_use(n). +jr_registrar(n) :- router_on(n). +jr_registrar(n) :- router_mount_app(n). +jr_registrar(n) :- router_mount_foreign(n). +jr_registrar(n) :- router_fallback(n). +jr_registrar(n) :- router_openapi(n). +.decl jr_reg(c0:symbol, c1:symbol, c2:symbol) +jr_reg(ce, a, cn) :- call_site(_, "METHOD_CALL", cn, _, r, _, ce, _, _), jr_registrar(cn), + expr_value(r, "router_app", a). +.decl jr_recv(c0:symbol, c1:symbol) +jr_recv(ce, r) :- jr_reg(ce, _, _), call_site(_, "METHOD_CALL", _, _, r, _, ce, _, _). + +// ── strings: what the flow engine knows a value to be, else a hole ───────── +.decl jr_need_str(c0:symbol) +jr_need_str(p) :- jr_reg(ce, _, _), call_arg(ce, 0, p). +jr_need_str(p) :- jr_reg(ce, _, cn), router_on(cn), call_arg(ce, 1, p). +jr_need_str(el) :- jr_reg(ce, _, cn), router_on(cn), call_arg(ce, pos, x), pos <= 1, + expr_kind(_, "ARRAY_LITERAL", _, x), expr_child(_, x, _, _, el). +jr_need_str(p) :- call_site(_, "METHOD_CALL", cn, _, r, _, ce, _, _), router_base_path(cn), + expr_value(r, "router_app", _), call_arg(ce, 0, p). +.decl jr_has_str(c0:symbol) +jr_has_str(p) :- jr_need_str(p), expr_value(p, "str", _). +.decl jr_str(c0:symbol, c1:symbol) +jr_str(p, s) :- jr_need_str(p), expr_value(p, "str", s). +jr_str(p, "{}") :- jr_need_str(p), !jr_has_str(p). + +// ── the base each app value carries (basePath), where it can be followed ─── +// Same module, through consts and chains. A value reached any other way (an import, a +// parameter) is taken at the base of the list it belongs to, `/`; that misses a +// basePath applied in another module, and the routes come out without it. +.decl jr_base(c0:symbol, c1:symbol) +jr_base(ne, "/") :- jr_new(ne). +jr_base(ce, b) :- call_site(_, "METHOD_CALL", cn, _, r, _, ce, _, _), router_returns_app(cn), + expr_value(ce, "router_app", _), jr_base(r, b). +jr_base(ce, nb) :- call_site(_, "METHOD_CALL", cn, _, r, _, ce, _, _), router_base_path(cn), + jr_base(r, b), call_arg(ce, 0, p), jr_str(p, pv), jr_bmerge(b, pv, nb), strlen(nb) < 300. +jr_bmreq(b, pv) :- call_site(_, "METHOD_CALL", cn, _, r, _, ce, _, _), router_base_path(cn), + jr_base(r, b), call_arg(ce, 0, p), jr_str(p, pv). +jr_base(e, b) :- expr_kind(_, "IDENTIFIER", _, e), expr_value(e, "router_app", _), expr_binding(_, v, e), + !var_import(_, _, v), var_init(_, _, i, v), jr_base(i, b). +.decl jr_has_base(c0:symbol) +jr_has_base(e) :- jr_base(e, _). +.decl jr_val(c0:symbol, c1:symbol, c2:symbol) +jr_val(e, a, b) :- expr_value(e, "router_app", a), jr_base(e, b). +jr_val(e, a, "/") :- expr_value(e, "router_app", a), !jr_has_base(e). + +// ── mergePath, for basePath (a stratum of its own: the base decides which values +// have one, and the later merges depend on that) +.decl jr_bmreq(c0:symbol, c1:symbol) +.decl jr_bmerge(c0:symbol, c1:symbol, c2:symbol) +.decl jr_blead(c0:symbol, c1:symbol) +jr_blead(x, x) :- (jr_bmreq(x, _) ; jr_bmreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) = "/". +jr_blead(x, y) :- (jr_bmreq(x, _) ; jr_bmreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) != "/", y = cat("/", x). +jr_blead("", "/") :- (jr_bmreq("", _) ; jr_bmreq(_, "")). +jr_bmerge(a, b, a1) :- jr_bmreq(a, b), jr_blead(a, a1), jr_blead(b, "/"), + substr(a1, strlen(a1) - 1, 1) = "/". +jr_bmerge(a, b, r) :- jr_bmreq(a, b), jr_blead(a, a1), jr_blead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) = "/", r = cat(substr(a1, 0, strlen(a1) - 1), b1). +jr_bmerge(a, b, a1) :- jr_bmreq(a, b), jr_blead(a, a1), jr_blead(b, "/"), + substr(a1, strlen(a1) - 1, 1) != "/". +jr_bmerge(a, b, r) :- jr_bmreq(a, b), jr_blead(a, a1), jr_blead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) != "/", r = cat(a1, b1). + +// ── mergePath ─────────────────────────────────────────────────────────────── +.decl jr_mreq(c0:symbol, c1:symbol) +.decl jr_merge(c0:symbol, c1:symbol, c2:symbol) +.decl jr_lead(c0:symbol, c1:symbol) +jr_lead(x, x) :- (jr_mreq(x, _) ; jr_mreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) = "/". +jr_lead(x, y) :- (jr_mreq(x, _) ; jr_mreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) != "/", y = cat("/", x). +jr_lead("", "/") :- (jr_mreq("", _) ; jr_mreq(_, "")). +jr_merge(a, b, a1) :- jr_mreq(a, b), jr_lead(a, a1), jr_lead(b, "/"), + substr(a1, strlen(a1) - 1, 1) = "/". +jr_merge(a, b, r) :- jr_mreq(a, b), jr_lead(a, a1), jr_lead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) = "/", r = cat(substr(a1, 0, strlen(a1) - 1), b1). +jr_merge(a, b, a1) :- jr_mreq(a, b), jr_lead(a, a1), jr_lead(b, "/"), + substr(a1, strlen(a1) - 1, 1) != "/". +jr_merge(a, b, r) :- jr_mreq(a, b), jr_lead(a, a1), jr_lead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) != "/", r = cat(a1, b1). + +// ── mounts and roots ──────────────────────────────────────────────────────── +.decl jr_inc(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +jr_inc(a, s, ce, pre) :- jr_reg(ce, a, cn), router_mount_app(cn), jr_recv(ce, r), jr_val(r, a, b), + call_arg(ce, 1, sx), expr_value(sx, "router_app", s), s != a, + call_arg(ce, 0, px), jr_str(px, pv), jr_merge(b, pv, pre). +jr_mreq(b, pv) :- jr_reg(ce, a, cn), router_mount_app(cn), jr_recv(ce, r), jr_val(r, a, b), + call_arg(ce, 0, px), jr_str(px, pv). +.decl jr_included(c0:symbol) +jr_included(s) :- jr_reg(ce, a, cn), router_mount_app(cn), call_arg(ce, 1, sx), + expr_value(sx, "router_app", s), s != a. +.decl jr_root(c0:symbol) +jr_root(a) :- jr_new(a), !jr_included(a). + +// ── position keys ─────────────────────────────────────────────────────────── +// The first argument's position: a chain `app.get(…).post(…)` starts every call at +// the same receiver, and the arguments are what moves left to right. +.decl jr_need_key(c0:symbol) +jr_need_key(ce) :- jr_reg(ce, _, _). +.decl jr_key_expr(c0:symbol, c1:symbol) +jr_key_expr(ce, a) :- jr_need_key(ce), call_arg(ce, 0, a). +.decl jr_has_arg(c0:symbol) +jr_has_arg(ce) :- jr_key_expr(ce, _). +.decl jr_key_x(c0:symbol, c1:symbol) +jr_key_x(ce, a) :- jr_key_expr(ce, a). +jr_key_x(ce, ce) :- jr_need_key(ce), !jr_has_arg(ce). +.decl jr_key(c0:symbol, c1:symbol) +jr_key(ce, k) :- jr_key_x(ce, x), expr_span(_, l, c, _, _, x), strlen(l) <= 7, strlen(c) <= 5, + k = cat(cat(substr("0000000", 0, 7 - strlen(l)), l), cat(":", cat(substr("00000", 0, 5 - strlen(c)), c))). diff --git a/graph/javascript/engine/config-resolution/http-router-openapi.dl b/graph/javascript/engine/config-resolution/http-router-openapi.dl new file mode 100644 index 000000000..ad7eb77dd --- /dev/null +++ b/graph/javascript/engine/config-resolution/http-router-openapi.dl @@ -0,0 +1,104 @@ +// ============================================================================ +// CONFIG-RESOLUTION · HTTP ROUTER OPENAPI ROUTES (JavaScript) +// +// `app.openapi(def, handler, hook?)` registers the route `def` describes: verb = its `method`, path = its `path` with +// `{x}` written `:x`, the definition's `middleware` (one, or a list) running before the handler, in order. `def` is +// the object `createRoute({...})` was called with (a knob: router_route_def), reached through consts, imports and +// returns by the flow engine, or a call of a PROJECT function that returns such a definition +// (`scopedRoute(scope, { method, path })` returning `createRoute({ ...config, middleware: [..] })`). The flow engine +// has one value per object literal, so the wrapper's object would carry every caller's `method` and `path`; a +// wrapper call is read per call instead: its method and path are THAT call's argument object's, its middleware the +// wrapper's own. A registration whose definition gives no literal method and path is declared +// (dynamic_route_path), never dropped. Same contract as the TypeScript engine (SPEC 3.7). +// ============================================================================ + +// createRoute's result is its argument (the flow engine carries it through consts, imports, exports and returns) +.decl jo_root(c0:symbol, c1:symbol) +jo_root(x, o) :- jr_knob_call(x, spec, n), router_route_def(spec, n), call_arg(x, 0, a), expr_value(a, "obj", o). +expr_value(x, "obj", o) :- jo_root(x, o). +.decl jo_defobj(c0:symbol) +jo_defobj(o) :- jo_root(_, o). + +// a property written in the object itself (`key: v`, or the shorthand `key`), never one it spreads: of a definition, +// or of the object a wrapper call hands in (jo_callarg) +.decl jo_obj(c0:symbol) +jo_obj(o) :- jo_defobj(o). +jo_obj(o) :- jo_callarg(_, o). +.decl jo_own(c0:symbol, c1:symbol, c2:symbol) +jo_own(o, n, v) :- jo_obj(o), expr_child(_, o, "PROPERTY_KEY", idx, key), expr_name(_, n, key), expr_child(_, o, "PROPERTY_VALUE", idx, v). +jo_own(o, n, v) :- jo_obj(o), expr_child(_, o, "PROPERTY_VALUE", idx, v), !expr_child(_, o, "PROPERTY_KEY", idx, _), expr_name(_, n, v). + +// the registration's definition argument, followed to a call of a project wrapper: through consts in its module +.decl jo_reg(c0:symbol, c1:symbol) +jo_reg(ce, x) :- jr_reg(ce, _, cn), router_openapi(cn), call_arg(ce, 0, x). +.decl jo_at(c0:symbol, c1:symbol) +jo_at(ce, x) :- jo_reg(ce, x). +jo_at(ce, i) :- jo_at(ce, e), expr_kind(_, "IDENTIFIER", _, e), expr_binding(_, v, e), var_init(_, _, i, v), i != "". +// (registration, wrapper call, wrapper): a project function whose returned value is a createRoute call +.decl jo_wrap(c0:symbol, c1:symbol, c2:symbol) +jo_wrap(ce, x, w) :- jo_at(ce, x), expr_kind(_, "CALL", _, x), expr_resolves_to_method(x, w), + expr_root(_, "RETURN", e), expr_owner(_, w, _, e), jo_root(e, _). +.decl jo_wrapped(c0:symbol) +jo_wrapped(ce) :- jo_wrap(ce, _, _). +// the wrapper's own object, and the call's argument objects it spreads (`...config`, config a parameter) +.decl jo_inner(c0:symbol, c1:symbol, c2:symbol) +jo_inner(ce, x, o) :- jo_wrap(ce, x, w), expr_root(_, "RETURN", e), expr_owner(_, w, _, e), jo_root(e, o). +.decl jo_spread_ref(c0:symbol, c1:symbol) +jo_spread_ref(o, r) :- jo_defobj(o), expr_child(_, o, "SPREAD", _, s), expr_child(_, s, _, _, r). +jo_spread_ref(o, r) :- jo_defobj(o), expr_child(_, o, "SPREAD_OPERAND", _, r). +.decl jo_callarg(c0:symbol, c1:symbol) +jo_callarg(ce, o2) :- jo_wrap(ce, x, w), jo_inner(ce, x, o), jo_spread_ref(o, r), expr_param(_, p, r), + param_decl(_, _, pos, w, p), call_arg(x, to_number(pos), a), expr_value(a, "obj", o2). + +// (registration, object holding its method and path), (registration, object holding its middleware) +.decl jo_mp(c0:symbol, c1:symbol) +jo_mp(ce, o) :- jo_reg(ce, x), !jo_wrapped(ce), expr_value(x, "obj", o), jo_defobj(o). +jo_mp(ce, o2) :- jo_callarg(ce, o2). +.decl jo_mwobj(c0:symbol, c1:symbol) +jo_mwobj(ce, o) :- jo_reg(ce, x), !jo_wrapped(ce), expr_value(x, "obj", o), jo_defobj(o). +jo_mwobj(ce, o) :- jo_inner(ce, _, o). +.decl jo_inner_mw(c0:symbol) +jo_inner_mw(ce) :- jo_inner(ce, _, o), jo_own(o, k, _), router_def_key(k, "middleware"). +jo_mwobj(ce, o2) :- jo_callarg(ce, o2), !jo_inner_mw(ce). + +.decl jo_str(c0:symbol, c1:symbol, c2:symbol) +jo_str(ce, role, s) :- jo_mp(ce, o), jo_own(o, k, v), router_def_key(k, role), (role = "method" ; role = "path"), expr_value(v, "str", s). +.decl jo_verb(c0:symbol, c1:symbol) +jo_verb(ce, vv) :- jo_str(ce, "method", w), router_verb_name(w, vv). + +// an OpenAPI path writes a parameter `{id}`; the router registers `:id` +.decl jo_brace_step(c0:symbol, c1:number, c2:symbol) +jo_brace_step(raw, 0, "") :- jo_str(_, "path", raw). +jo_brace_step(raw, i + 1, cat(acc, ":")) :- jo_brace_step(raw, i, acc), i < strlen(raw), substr(raw, i, 1) = "{". +jo_brace_step(raw, i + 1, acc) :- jo_brace_step(raw, i, acc), i < strlen(raw), substr(raw, i, 1) = "}". +jo_brace_step(raw, i + 1, cat(acc, ch)) :- jo_brace_step(raw, i, acc), i < strlen(raw), ch = substr(raw, i, 1), + ch != "{", ch != "}". +.decl jo_path(c0:symbol, c1:symbol) +jo_path(ce, p) :- jo_str(ce, "path", raw), jo_brace_step(raw, strlen(raw), p). + +// the handler, and the definition's middleware before it (ordinals 10.. in list order) +jr_harg(ce, 100, a) :- jo_reg(ce, _), call_arg(ce, 1, a). +.decl jo_mw(c0:symbol, c1:symbol) +jo_mw(ce, v) :- jo_mwobj(ce, o), jo_own(o, k, v), router_def_key(k, "middleware"). +.decl jo_mw_arr(c0:symbol, c1:symbol) +jo_mw_arr(ce, v) :- jo_mw(ce, v), expr_kind(_, "ARRAY_LITERAL", _, v). +jo_mw_arr(ce, i) :- jo_mw(ce, v), expr_kind(_, "IDENTIFIER", _, v), expr_binding(_, d, v), var_init(_, _, i, d), i != "", + expr_kind(_, "ARRAY_LITERAL", _, i). +.decl jo_mw_listed(c0:symbol, c1:symbol) +jo_mw_listed(ce, v) :- jo_mw(ce, v), jo_mw_arr(ce, _). +jr_harg(ce, n, el) :- jo_mw_arr(ce, arr), expr_child(_, arr, _, epos, el), to_number(epos) < 90, n = 10 + to_number(epos), + !expr_kind(_, "SPREAD", _, el). +jr_harg(ce, 10, v) :- jo_mw(ce, v), !jo_mw_listed(ce, v). +// a spread in the list: decided at run time +framework_undetermined(m, "middleware", "dynamic_middleware_list") :- jo_mw_arr(ce, arr), expr_child(_, arr, _, _, el), + expr_kind(_, "SPREAD", _, el), call_site(_, _, _, _, _, m, ce, _, _). + +jr_entry_base(ce, a, "route", vv, lp, b) :- jr_reg(ce, a, cn), router_openapi(cn), jo_verb(ce, vv), jo_path(ce, lp), + jr_recv(ce, r), jr_val(r, a, b). + +// a definition this cannot read: the route exists, its verb and path are not known here +.decl jo_routed(c0:symbol) +jo_routed(ce) :- jo_verb(ce, _), jo_path(ce, _). +remote_undetermined(m, "http", "dynamic_route_path") :- jo_reg(ce, _), !jo_routed(ce), jr_node_fn(ce, 100, m). +remote_undetermined(m, "http", "dynamic_route_path") :- jo_reg(ce, _), !jo_routed(ce), !jr_has_fn(ce, 100), + call_site(_, _, _, _, _, m, ce, _, _). diff --git a/graph/javascript/engine/config-resolution/http-router-routes.dl b/graph/javascript/engine/config-resolution/http-router-routes.dl new file mode 100644 index 000000000..176eac992 --- /dev/null +++ b/graph/javascript/engine/config-resolution/http-router-routes.dl @@ -0,0 +1,330 @@ +// ============================================================================ +// CONFIG-RESOLUTION · HTTP ROUTER ROUTES (JavaScript: the route table, composed) +// +// The JavaScript counterpart of typescript/engine/config-resolution/http-router-routes.dl, +// same relations, same contract: +// +// http_route(Handler, Verb, FullPath, App, Order) +// http_route_partial(Handler, Verb, KnownPath, App, Reason) +// http_mount(ParentApp, ChildApp, Prefix, Order) +// middleware_applies(Mw, Handler, Verb, FullPath, Position, App) +// middleware_site(Mw, Kind, Callee, Specifier) +// framework_undetermined(Node, What, Reason) +// +// and every function handed to a registration is an `http` entry point. A registering +// call puts one entry per handler argument on its app's list (the last is the route's +// handler, earlier ones its own middleware); `use` puts middleware entries for every +// verb. A list no `route(prefix, list)` mounts is a root; flattening splices each +// mounted list at the mount, under its prefix. A path the flow engine cannot read as a +// string is a `{}` hole: http_route_partial with a reason, never http_route. +// ============================================================================ + +// ── where the handlers start ──────────────────────────────────────────────── +.decl jr_arg0_fnlike(c0:symbol) +jr_arg0_fnlike(ce) :- jr_reg(ce, _, _), call_arg(ce, 0, a), expr_kind(_, k, _, a), + (k = "FUNCTION_EXPRESSION" ; k = "CALL" ; k = "SPREAD"). +jr_arg0_fnlike(ce) :- jr_reg(ce, _, _), call_arg(ce, 0, a), expr_value(a, "func", _). +.decl jr_pathed(c0:symbol) +jr_pathed(ce) :- jr_reg(ce, _, cn), (router_verb(cn, _) ; router_use(cn)), call_arg(ce, 0, _), !jr_arg0_fnlike(ce). +.decl jr_pathless(c0:symbol) +jr_pathless(ce) :- jr_reg(ce, _, cn), (router_verb(cn, _) ; router_use(cn)), jr_arg0_fnlike(ce). +.decl jr_hstart(c0:symbol, c1:number) +jr_hstart(ce, 1) :- jr_pathed(ce). +jr_hstart(ce, 0) :- jr_pathless(ce). +jr_hstart(ce, 2) :- jr_reg(ce, _, cn), router_on(cn). +jr_hstart(ce, 0) :- jr_reg(ce, _, cn), router_fallback(cn). + +// ── handler arguments: (call, ordinal = position * 100 + element, expression) ── +.decl jr_harg(c0:symbol, c1:number, c2:symbol) +jr_harg(ce, n, a) :- jr_hstart(ce, s), call_arg(ce, p, a), p >= s, n = p * 100, !expr_kind(_, "SPREAD", _, a). +jr_harg(ce, 100, a) :- jr_reg(ce, _, cn), router_mount_foreign(cn), call_arg(ce, 1, a). +.decl jr_spread(c0:symbol, c1:number, c2:symbol) +jr_spread(ce, p, x) :- jr_hstart(ce, s), call_arg(ce, p, a), p >= s, expr_kind(_, "SPREAD", _, a), + expr_child(_, a, _, _, x). +.decl jr_spread_arr(c0:symbol, c1:number, c2:symbol) +jr_spread_arr(ce, p, x) :- jr_spread(ce, p, x), expr_kind(_, "ARRAY_LITERAL", _, x). +jr_spread_arr(ce, p, arr) :- jr_spread(ce, p, x), expr_binding(_, v, x), var_init(_, _, arr, v), + expr_kind(_, "ARRAY_LITERAL", _, arr). +jr_harg(ce, n, el) :- jr_spread_arr(ce, p, arr), expr_child(_, arr, _, epos, el), + n = p * 100 + to_number(epos), to_number(epos) < 100. +.decl jr_spread_call(c0:symbol, c1:number, c2:symbol) +jr_spread_call(ce, p, x) :- jr_spread(ce, p, x), call_site(_, _, sn, _, _, _, x, _, _), router_handler_spread(sn). +jr_harg(ce, n, el) :- jr_spread_call(ce, p, x), call_arg(x, ep, el), n = p * 100 + ep, ep < 100. +.decl jr_spread_known(c0:symbol, c1:number) +jr_spread_known(ce, p) :- jr_spread_arr(ce, p, _). +jr_spread_known(ce, p) :- jr_spread_call(ce, p, _). +framework_undetermined(m, "middleware", "dynamic_middleware_list") :- jr_spread(ce, p, _), + !jr_spread_known(ce, p), call_site(_, _, _, _, _, m, ce, _, _). + +.decl jr_last(c0:symbol, c1:number) +jr_last(ce, n) :- jr_harg(ce, _, _), n = max x : { jr_harg(ce, x, _) }. + +// ── the function each handler argument is ─────────────────────────────────── +// What the flow engine says the expression may be (written in place, named, imported, +// returned by a project function), or the argument of a knob wrapper. +.decl jr_wrapper_call(c0:symbol) +jr_wrapper_call(a) :- call_site(_, "FUNCTION_CALL", _, _, _, _, a, _, _), expr_child(_, a, "CALLEE", _, c), + jr_ref(c, spec, n), router_mw_wrapper(spec, n). +.decl jr_fn(c0:symbol, c1:symbol) +jr_fn(a, m) :- jr_harg(_, _, a), expr_value(a, "func", m). +// a project factory returning a knob wrapper's result (`function session(o) { return createMiddleware(fn) }`, +// called as `session(o)` directly or through a const): the middleware is `fn`, at every call +.decl jr_factory_wrap(c0:symbol, c1:symbol) +jr_factory_wrap(w, m) :- expr_root(_, "RETURN", e), expr_owner(_, w, _, e), jr_wrapper_call(e), call_arg(e, 0, x), + expr_value(x, "func", m). +jr_fn(a, m) :- jr_harg(_, _, a), expr_kind(_, "CALL", _, a), expr_resolves_to_method(a, w), jr_factory_wrap(w, m). +jr_fn(a, m) :- jr_harg(_, _, a), expr_binding(_, v, a), var_init(_, _, i, v), expr_kind(_, "CALL", _, i), + expr_resolves_to_method(i, w), jr_factory_wrap(w, m). +jr_fn(a, m) :- jr_harg(_, _, a), jr_wrapper_call(a), call_arg(a, 0, x), expr_value(x, "func", m). +jr_fn(a, m) :- jr_harg(_, _, a), expr_binding(_, v, a), var_init(_, _, i, v), jr_wrapper_call(i), + call_arg(i, 0, x), expr_value(x, "func", m). +.decl jr_node_fn(c0:symbol, c1:number, c2:symbol) +jr_node_fn(ce, n, m) :- jr_harg(ce, n, a), jr_fn(a, m), method_decl("client", _, _, _, _, _, _, m). +// a route's handler node: the project function, or a library call's result keyed at the call +.decl jr_route_node(c0:symbol, c1:number, c2:symbol) +jr_route_node(ce, n, m) :- jr_node_fn(ce, n, m). +jr_route_node(ce, n, a) :- jr_harg(ce, n, a), !jr_has_fn(ce, n), expr_kind(_, "CALL", _, a). +.decl jr_has_fn(c0:symbol, c1:number) +jr_has_fn(ce, n) :- jr_node_fn(ce, n, _). +.decl jr_node(c0:symbol, c1:number, c2:symbol) +jr_node(ce, n, m) :- jr_node_fn(ce, n, m). +jr_node(ce, n, a) :- jr_harg(ce, n, a), !jr_has_fn(ce, n). + +// a call of a knob function: (call, specifier, name) +.decl jr_knob_call(c0:symbol, c1:symbol, c2:symbol) +jr_knob_call(a, spec, n) :- call_site(_, "FUNCTION_CALL", _, _, _, _, a, _, _), expr_child(_, a, "CALLEE", _, c), + jr_ref(c, spec, n). +.decl jr_comb_arg(c0:symbol) +jr_comb_arg(x) :- jr_harg(_, _, a), jr_knob_call(a, spec, n), router_mw_combinator(spec, n), call_arg(a, _, x). +jr_comb_arg(x) :- jr_harg(_, _, a), jr_knob_call(a, spec, n), router_mw_except(spec, n), call_arg(a, 1, x). +entry_point(m, "http") :- jr_comb_arg(x), expr_value(x, "func", m), method_decl("client", _, _, _, _, _, _, m). +.decl jr_excepted(c0:symbol, c1:number, c2:symbol) +jr_excepted(ce, n, v) :- jr_harg(ce, n, a), jr_knob_call(a, spec, nm), router_mw_except(spec, nm), + call_arg(a, 0, x), expr_value(x, "str", v). +jr_excepted(ce, n, v) :- jr_harg(ce, n, a), jr_knob_call(a, spec, nm), router_mw_except(spec, nm), + call_arg(a, 0, arr), expr_kind(_, "ARRAY_LITERAL", _, arr), expr_child(_, arr, _, _, x), expr_value(x, "str", v). + +// http: every function a router calls, receiver-checked +entry_point(m, "http") :- jr_node_fn(_, _, m). + +// ── local paths ───────────────────────────────────────────────────────────── +.decl jr_local(c0:symbol, c1:symbol) +jr_local(ce, lp) :- jr_pathed(ce), call_arg(ce, 0, p), jr_str(p, lp). +jr_local(ce, "*") :- jr_pathless(ce), jr_reg(ce, _, cn), router_use(cn). +.decl jr_cont_src(c0:symbol) +jr_cont_src(r) :- jr_reg(r, _, rn), (router_verb(rn, _) ; router_use(rn)). +jr_cont_src(r) :- jr_new(r). +jr_cont_src(r) :- call_site(_, "METHOD_CALL", cn, _, _, _, r, _, _), router_base_path(cn). +jr_local(ce, lp) :- jr_pathless(ce), jr_reg(ce, _, cn), router_verb(cn, _), jr_recv(ce, r), + jr_local(r, lp), jr_reg(r, _, rn), (router_verb(rn, _) ; router_use(rn)). +jr_local(ce, "/") :- jr_pathless(ce), jr_reg(ce, _, cn), router_verb(cn, _), jr_recv(ce, r), + (jr_new(r) ; call_site(_, "METHOD_CALL", bn, _, _, _, r, _, _), router_base_path(bn)). +// on a variable: the path of the previous registration on that app in this module +.decl jr_pathless_var(c0:symbol) +jr_pathless_var(ce) :- jr_pathless(ce), jr_reg(ce, _, cn), router_verb(cn, _), jr_recv(ce, r), !jr_cont_src(r). +.decl jr_keyn(c0:symbol, c1:number) +jr_keyn(ce, n) :- jr_key_x(ce, x), expr_span(_, l, c, _, _, x), + to_number(l) < 200000, to_number(c) < 10000, n = to_number(l) * 10000 + to_number(c). +.decl jr_prev_cand(c0:symbol, c1:symbol, c2:number) +jr_prev_cand(ce, r2, n2) :- jr_pathless_var(ce), jr_reg(ce, a, _), jr_keyn(ce, n), call_site(_, _, _, _, _, _, ce, m, _), + jr_reg(r2, a, rn), (router_verb(rn, _) ; router_use(rn)), r2 != ce, call_site(_, _, _, _, _, _, r2, m, _), + jr_keyn(r2, n2), n2 < n. +.decl jr_prev(c0:symbol, c1:symbol) +jr_prev(ce, r2) :- jr_prev_cand(ce, _, _), b = max x : { jr_prev_cand(ce, _, x) }, jr_prev_cand(ce, r2, b). +.decl jr_has_prev(c0:symbol) +jr_has_prev(ce) :- jr_prev(ce, _). +jr_local(ce, lp) :- jr_prev(ce, r2), jr_local(r2, lp). +jr_local(ce, "/") :- jr_pathless_var(ce), !jr_has_prev(ce). +jr_local(ce, lp) :- jr_reg(ce, _, cn), router_mount_foreign(cn), call_arg(ce, 0, p), jr_str(p, pv), + jr_merge(pv, "*", lp). +jr_mreq(pv, "*") :- jr_reg(ce, _, cn), router_mount_foreign(cn), call_arg(ce, 0, p), jr_str(p, pv). + +.decl jr_on_piece(c0:symbol, c1:number, c2:symbol) +jr_on_piece(ce, pos, v) :- jr_reg(ce, _, cn), router_on(cn), call_arg(ce, pos, x), pos <= 1, + !expr_kind(_, "ARRAY_LITERAL", _, x), jr_str(x, v). +jr_on_piece(ce, pos, v) :- jr_reg(ce, _, cn), router_on(cn), call_arg(ce, pos, x), pos <= 1, + expr_kind(_, "ARRAY_LITERAL", _, x), expr_child(_, x, _, _, el), jr_str(el, v). +.decl jr_on_verb(c0:symbol, c1:symbol) +jr_on_verb(ce, vv) :- jr_on_piece(ce, 0, w), router_verb_name(w, vv). +jr_on_verb(ce, w) :- jr_on_piece(ce, 0, w), !router_verb_name(w, _). + +// ── entries: (list, key, kind, verb, path, call, ordinal) ─────────────────── +.decl jr_entry_base(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +jr_entry_base(ce, a, "route", vv, lp, b) :- jr_reg(ce, a, cn), router_verb(cn, vv), jr_local(ce, lp), + jr_recv(ce, r), jr_val(r, a, b). +jr_entry_base(ce, a, "mw", "ANY", lp, b) :- jr_reg(ce, a, cn), router_use(cn), jr_local(ce, lp), + jr_recv(ce, r), jr_val(r, a, b). +jr_entry_base(ce, a, "route", "ANY", lp, b) :- jr_reg(ce, a, cn), router_mount_foreign(cn), jr_local(ce, lp), + jr_recv(ce, r), jr_val(r, a, b). +jr_entry_base(ce, a, "route", vv, lp, b) :- jr_reg(ce, a, _), jr_on_verb(ce, vv), jr_on_piece(ce, 1, lp), + jr_recv(ce, r), jr_val(r, a, b). +jr_mreq(b, lp) :- jr_entry_base(_, _, _, _, lp, b). +.decl jr_entry(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:number) +jr_entry(a, k2, kind, vv, p, ce, n) :- jr_entry_base(ce, a, kind, vv, lp, b), jr_merge(b, lp, p), + jr_harg(ce, n, _), jr_key(ce, k), s = to_string(n), + k2 = cat(k, cat(",", cat(substr("00000", 0, 5 - strlen(s)), s))). +.decl jr_entry_own(c0:symbol, c1:symbol) +jr_entry_own(ce, p) :- jr_entry(_, _, _, _, p, ce, _). + +// ── flattening a root ─────────────────────────────────────────────────────── +.decl jr_flat(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +jr_flat(r, r, "/", "", "", "") :- jr_root(r). +.decl jr_cutoff(c0:symbol, c1:symbol, c2:symbol) +jr_cutoff(site, k, m) :- jr_inc(_, _, site, _), jr_key(site, k), call_site(_, _, _, _, _, _, site, m, _). +jr_flat(r, s, np, nk, cut, cm) :- jr_flat(r, a, p, kp, _, _), jr_inc(a, s, site, pre), + jr_merge(p, pre, np), jr_key(site, k), nk = cat(kp, cat(k, ".")), strlen(nk) < 160, + jr_cutoff(site, cut, cm). +jr_mreq(p, pre) :- jr_flat(_, a, p, _, _, _), jr_inc(a, _, _, pre). +.decl jr_fcand(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:number, c7:symbol) +jr_fcand(r, fk, kind, vv, p, ce, n, pre) :- jr_flat(r, a, pre, kp, "", _), jr_entry(a, k, kind, vv, p, ce, n), + fk = cat(kp, k). +jr_fcand(r, fk, kind, vv, p, ce, n, pre) :- jr_flat(r, a, pre, kp, cut, _), cut != "", + jr_entry(a, k, kind, vv, p, ce, n), k < cut, fk = cat(kp, k). +jr_fcand(r, fk, kind, vv, p, ce, n, pre) :- jr_flat(r, a, pre, kp, cut, cm), cut != "", + jr_entry(a, k, kind, vv, p, ce, n), call_site(_, _, _, _, _, _, ce, em, _), em != cm, fk = cat(kp, k). +jr_mreq(pre, p) :- jr_fcand(_, _, _, _, p, _, _, pre). +.decl jr_fentry(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:number) +jr_fentry(r, fk, kind, vv, fp, ce, n) :- jr_fcand(r, fk, kind, vv, p, ce, n, pre), jr_merge(pre, p, fp). + +// http_route(Handler, Verb, FullPath, App, Order) — a route a served app answers, its +// full path composed through every basePath and mount; App is the `new` that built +// the root app, Order its registration key there (compares as program order). +http_route(m, vv, fp, r, fk) :- jr_fentry(r, fk, "route", vv, fp, ce, n), jr_last(ce, n), + jr_route_node(ce, n, m), !contains("{}", fp). + +// route_registered_by(RegMethod, Handler, Verb, FullPath, App) — the function whose body makes the +// registering call (a registration function, an app factory, a module body) +route_registered_by(rm, m, vv, fp, r) :- jr_fentry(r, _, "route", vv, fp, ce, n), jr_last(ce, n), + jr_route_node(ce, n, m), !contains("{}", fp), call_site(_, _, _, _, _, rm, ce, _, _). + +.decl jr_partial(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +jr_partial(m, vv, fp, r, "dynamic_route_path") :- jr_fentry(r, _, "route", vv, fp, ce, n), jr_last(ce, n), + jr_route_node(ce, n, m), contains("{}", fp), jr_entry_own(ce, op), contains("{}", op). +jr_partial(m, vv, fp, r, "dynamic_mount_prefix") :- jr_fentry(r, _, "route", vv, fp, ce, n), jr_last(ce, n), + jr_route_node(ce, n, m), contains("{}", fp), jr_entry_own(ce, op), !contains("{}", op). +// http_route_partial(Handler, Verb, KnownPath, App, Reason) — a route whose path is +// not fully static: what is known, `{}` for each unknown piece, and why +http_route_partial(m, vv, fp, r, why) :- jr_partial(m, vv, fp, r, why). +remote_undetermined(m, "http", why) :- jr_partial(m, _, _, _, why). + +// http_mount(ParentApp, ChildApp, Prefix, Order) — `route(prefix, child)` +http_mount(a, s, pre, k) :- jr_inc(a, s, site, pre), jr_key(site, k). +framework_undetermined(m, "mount", "unresolved_mount") :- jr_reg(ce, _, cn), router_mount_app(cn), + call_arg(ce, 1, sx), !expr_value(sx, "router_app", _), call_site(_, _, _, _, _, m, ce, _, _). +framework_undetermined(m, "mount", "foreign_mount") :- jr_reg(ce, _, cn), router_mount_foreign(cn), + !jr_has_fn(ce, 100), call_site(_, _, _, _, _, m, ce, _, _). + +// ── middleware application ────────────────────────────────────────────────── +.decl jr_hent(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +jr_hent(r, hk, ce, vv, fp) :- jr_fentry(r, hk, "route", vv, fp, ce, n), jr_last(ce, n), !contains("{}", fp). +// (root, key, call, ordinal, scope, verb): `use` entries, and a verb registration whose +// function takes `next` and calls it +.decl jr_ment(c0:symbol, c1:symbol, c2:symbol, c3:number, c4:symbol, c5:symbol) +jr_ment(r, mk, ce, n, q, vv) :- jr_fentry(r, mk, "mw", vv, q, ce, n), !contains("{}", q). +jr_ment(r, mk, ce, n, q, vv) :- jr_fentry(r, mk, "route", vv, q, ce, n), !contains("{}", q), + jr_node_fn(ce, n, m), jr_calls_next(m). +.decl jr_calls_next(c0:symbol) +jr_calls_next(m) :- jr_node_fn(_, _, m), param_decl("client", _, "1", m, p), expr_param(_, p, f), + expr_child(_, ce, "CALLEE", _, f), call_site(_, _, _, _, _, _, ce, _, _). +.decl jr_verb_ok(c0:symbol, c1:symbol) +jr_verb_ok("ANY", v) :- jr_hent(_, _, _, v, _). +jr_verb_ok(v, v) :- jr_hent(_, _, _, v, _). +.decl jr_spair(c0:symbol, c1:symbol) +jr_spair(q, p) :- jr_ment(r, mk, _, _, q, _), jr_hent(r, hk, _, _, p), mk < hk. + +.decl jr_spath(c0:symbol) +jr_spath(q) :- jr_spair(q, _). +jr_spath(p) :- jr_spair(_, p). +.decl jr_slash(c0:symbol, c1:number) +jr_slash(p, i) :- jr_spath(p), i = range(0, strlen(p)), substr(p, i, 1) = "/". +.decl jr_next_slash(c0:symbol, c1:number, c2:number) +jr_next_slash(p, i, j) :- jr_slash(p, i), j = min x : { jr_slash(p, x), x > i }. +.decl jr_has_next(c0:symbol, c1:number) +jr_has_next(p, i) :- jr_next_slash(p, i, _). +.decl jr_seg_at(c0:symbol, c1:number, c2:symbol) +jr_seg_at(p, i, t) :- jr_next_slash(p, i, j), t = substr(p, i + 1, j - i - 1). +jr_seg_at(p, i, t) :- jr_slash(p, i), !jr_has_next(p, i), t = substr(p, i + 1, strlen(p) - i - 1). +.decl jr_seg_ne(c0:symbol, c1:number) +jr_seg_ne(p, i) :- jr_seg_at(p, i, t), t != "". +.decl jr_seg(c0:symbol, c1:number, c2:symbol) +jr_seg(p, k, t) :- jr_seg_at(p, i, t), t != "", k = count : { jr_seg_ne(p, x), x < i }. +.decl jr_nseg(c0:symbol, c1:number) +jr_nseg(p, n) :- jr_spath(p), n = count : { jr_seg(p, _, _) }. +.decl jr_lit(c0:symbol) +jr_lit(t) :- jr_seg(_, _, t), substr(t, 0, 1) != ":", t != "*". +.decl jr_qtail(c0:symbol) +jr_qtail(q) :- jr_nseg(q, n), n >= 1, jr_seg(q, n - 1, "*"). +.decl jr_qfix(c0:symbol, c1:number) +jr_qfix(q, n - 1) :- jr_qtail(q), jr_nseg(q, n). +jr_qfix(q, n) :- jr_nseg(q, n), !jr_qtail(q). +.decl jr_len_ok(c0:symbol, c1:symbol) +jr_len_ok(q, p) :- jr_spair(q, p), jr_qtail(q), jr_qfix(q, f), jr_nseg(p, np), np >= f. +jr_len_ok(q, p) :- jr_spair(q, p), !jr_qtail(q), jr_nseg(q, n), jr_nseg(p, n). +.decl jr_conflict(c0:symbol, c1:symbol) +jr_conflict(q, p) :- jr_spair(q, p), jr_qfix(q, f), jr_seg(q, i, x), i < f, jr_seg(p, i, y), + jr_lit(x), jr_lit(y), x != y. +.decl jr_undec(c0:symbol, c1:symbol) +jr_undec(q, p) :- jr_spair(q, p), jr_qfix(q, f), jr_seg(q, i, x), i < f, jr_seg(p, i, y), + jr_lit(x), !jr_lit(y). +.decl jr_scope_ok(c0:symbol, c1:symbol) +jr_scope_ok(q, p) :- jr_len_ok(q, p), !jr_conflict(q, p), !jr_undec(q, p). + +.decl jr_applies(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +jr_applies(r, hk, mk, mce, mn) :- jr_ment(r, mk, mce, mn, q, mv), jr_hent(r, hk, _, hv, p), mk < hk, + jr_verb_ok(mv, hv), jr_scope_ok(q, p), !jr_excepted(mce, mn, p). +jr_applies(r, hk, mk, ce, mn) :- jr_hent(r, hk, ce, vv, fp), jr_fentry(r, mk, "route", vv, fp, ce, mn), + jr_last(ce, n), mn < n. +framework_undetermined(mw, "middleware_scope", "param_vs_literal_scope") :- jr_ment(r, mk, mce, mn, q, mv), + jr_hent(r, hk, _, hv, p), mk < hk, jr_verb_ok(mv, hv), jr_len_ok(q, p), !jr_conflict(q, p), jr_undec(q, p), jr_node(mce, mn, mw). +.decl jr_applies_k(c0:symbol, c1:symbol, c2:symbol) +jr_applies_k(r, hk, mk) :- jr_applies(r, hk, mk, _, _). +.decl jr_rank(c0:symbol, c1:symbol, c2:symbol, c3:number) +jr_rank(r, hk, mk, pos) :- jr_applies_k(r, hk, mk), pos = count : { jr_applies_k(r, hk, k2), k2 < mk }. + +// middleware_applies(Mw, Handler, Verb, FullPath, Position, App) — in served app App, Mw runs before Handler on +// a request for Verb FullPath, at Position (0 first). Mw is the project function, or +// the registering argument expression for library middleware. +// a spread no rule could read stands in the chain: no position after it is claimed +.decl jr_dyn_key(c0:symbol, c1:symbol) +jr_dyn_key(a, k) :- jr_spread(ce, p, _), !jr_spread_known(ce, p), jr_reg(ce, a, _), jr_key(ce, k0), + s = to_string(p * 100), k = cat(k0, cat(",", cat(substr("00000", 0, 5 - strlen(s)), s))). +.decl jr_fdyn(c0:symbol, c1:symbol) +jr_fdyn(r, fk) :- jr_flat(r, a, _, kp, _, _), jr_dyn_key(a, k), fk = cat(kp, k). +.decl jr_after_dyn(c0:symbol, c1:symbol, c2:symbol) +jr_after_dyn(r, hk, mk) :- jr_applies_k(r, hk, mk), jr_fdyn(r, sk), sk < hk, sk < mk. +middleware_applies(mw, h, vv, fp, to_string(pos), r) :- jr_hent(r, hk, ce, vv, fp), jr_last(ce, n), + jr_route_node(ce, n, h), jr_applies(r, hk, mk, mce, mn), jr_node(mce, mn, mw), jr_rank(r, hk, mk, pos), + !jr_after_dyn(r, hk, mk). + +// middleware_registered_at(Mw, Handler, Verb, FullPath, App, RegCall) — the registering call that puts Mw in the +// chain of Handler on App: an app-level `use(..)` (or a verb registration that calls next), or the route's own +// call for its per-route middleware +middleware_registered_at(mw, h, vv, fp, r, mce) :- jr_hent(r, hk, ce, vv, fp), jr_last(ce, n), + jr_route_node(ce, n, h), jr_applies(r, hk, mk, mce, mn), jr_node(mce, mn, mw), !jr_after_dyn(r, hk, mk). + +// a registration inside a branch or a loop is still emitted, and said to be one: the block of the function +// that makes the call, whose span holds the call +.decl jr_in_block(c0:symbol, c1:symbol) +jr_in_block(ce, k) :- jr_reg(ce, _, _), expr_owner(_, h, mod, ce), expr_span(_, l, c, _, _, ce), + block_owner(k, h, b), block_span(_, mod, l1, c1, l2, c2, b), + (to_number(l) > to_number(l1) ; to_number(l) = to_number(l1), to_number(c) >= to_number(c1)), + (to_number(l) < to_number(l2) ; to_number(l) = to_number(l2), to_number(c) <= to_number(c2)). +.decl jr_cond_kind(c0:symbol) +jr_cond_kind("IF"). jr_cond_kind("ELSE"). jr_cond_kind("SWITCH"). jr_cond_kind("SWITCH_CASE"). jr_cond_kind("CATCH"). +.decl jr_loop_kind(c0:symbol) +jr_loop_kind("FOR"). jr_loop_kind("FOR_IN"). jr_loop_kind("FOR_OF"). jr_loop_kind("WHILE"). jr_loop_kind("DO"). +framework_undetermined(m, "registration", "conditional_registration") :- jr_in_block(ce, k), jr_cond_kind(k), + jr_last(ce, n), jr_node_fn(ce, n, m). +framework_undetermined(m, "registration", "loop_registration") :- jr_in_block(ce, k), jr_loop_kind(k), + jr_last(ce, n), jr_node_fn(ce, n, m). + +// middleware_site(Mw, Kind, Callee, Specifier) — what a middleware node is +.decl jr_mw_arg(c0:symbol, c1:number, c2:symbol) +jr_mw_arg(ce, n, a) :- jr_entry(_, _, "mw", _, _, ce, n), jr_harg(ce, n, a). +jr_mw_arg(ce, n, a) :- jr_harg(ce, n, a), jr_last(ce, l), n < l, jr_entry(_, _, "route", _, _, ce, n). +middleware_site(m, "project_fn", "", "") :- jr_mw_arg(ce, n, a), jr_node_fn(ce, n, m), !expr_kind(_, "CALL", _, a). +middleware_site(m, "factory_result", cn, "") :- jr_mw_arg(ce, n, a), jr_node_fn(ce, n, m), + call_site(_, _, cn, _, _, _, a, _, _). +middleware_site(a, "library_call", n, spec) :- jr_mw_arg(ce, k, a), !jr_has_fn(ce, k), + call_site(_, _, _, _, _, _, a, _, _), expr_child(_, a, "CALLEE", _, c), expr_binding(_, v, c), + var_import(_, imp, v), import_decl(_, spec, _, _, n, _, _, _, imp). diff --git a/graph/javascript/engine/config-resolution/knobs.dl b/graph/javascript/engine/config-resolution/knobs.dl new file mode 100644 index 000000000..8c9f20a34 --- /dev/null +++ b/graph/javascript/engine/config-resolution/knobs.dl @@ -0,0 +1,126 @@ +// ============================================================================ +// CONFIG-RESOLUTION · KNOBS (JavaScript: framework name lists) +// +// The JavaScript counterpart of typescript/engine/config-resolution/knobs.dl. Every +// framework-specific NAME the config-resolution and framework-behavior rules of this +// engine key on lives here and nowhere else; no rule mentions a framework by name. +// ============================================================================ + +// ── HTTP ROUTER APPLICATIONS (config-resolution/http-router-*.dl) ─────────── +// An application object a program builds and registers routes, middleware and +// sub-applications on. Recognised by the class it is constructed from and the module +// that class is imported (or required) from, never by a method name. The package need +// not be installed: the import specifier is the evidence. + +// router_app_class(Specifier, ExportedName): `new ()` of this import is an app +.decl router_app_class(c0:symbol, c1:symbol) +router_app_class("hono", "Hono"). +router_app_class("hono/tiny", "Hono"). +router_app_class("hono/quick", "Hono"). +router_app_class("@hono/zod-openapi", "OpenAPIHono"). +// ── how a module may be named: Deno specifiers and URLs ───────────────────── +// router_spec_scheme(Prefix): `npm:hono@4`, `jsr:@hono/hono@^4/logger` name the package +// after the prefix, a version after `@` dropped; router_spec_url(Prefix, Package): a URL +// import of the package's published module (`@v3/mod.ts` is the package itself) +.decl router_spec_scheme(c0:symbol) +router_spec_scheme("npm:"). +router_spec_scheme("jsr:"). +.decl router_spec_url(c0:symbol, c1:symbol) +router_spec_url("https://deno.land/x/hono", "hono"). +router_spec_url("https://esm.sh/hono", "hono"). +// the JSR name of the package +router_app_class("@hono/hono", "Hono"). +// router_verb(Method, Verb): a route registration and the verb it serves +.decl router_verb(c0:symbol, c1:symbol) +router_verb("get", "GET"). router_verb("post", "POST"). +router_verb("put", "PUT"). router_verb("delete", "DELETE"). +router_verb("patch", "PATCH"). router_verb("options", "OPTIONS"). +router_verb("all", "ANY"). +// a verb as `on(...)` may spell it +.decl router_verb_name(c0:symbol, c1:symbol) +router_verb_name("get", "GET"). router_verb_name("GET", "GET"). +router_verb_name("post", "POST"). router_verb_name("POST", "POST"). +router_verb_name("put", "PUT"). router_verb_name("PUT", "PUT"). +router_verb_name("delete", "DELETE"). router_verb_name("DELETE", "DELETE"). +router_verb_name("patch", "PATCH"). router_verb_name("PATCH", "PATCH"). +router_verb_name("options", "OPTIONS"). router_verb_name("OPTIONS", "OPTIONS"). +router_verb_name("head", "HEAD"). router_verb_name("HEAD", "HEAD"). +.decl router_use(c0:symbol) +router_use("use"). +.decl router_on(c0:symbol) +router_on("on"). +.decl router_mount_app(c0:symbol) +router_mount_app("route"). +.decl router_base_path(c0:symbol) +router_base_path("basePath"). +.decl router_mount_foreign(c0:symbol) +router_mount_foreign("mount"). +.decl router_fallback(c0:symbol) +router_fallback("notFound"). +router_fallback("onError"). +.decl router_returns_app(c0:symbol) +router_returns_app(n) :- router_verb(n, _). +router_returns_app(n) :- router_use(n). +router_returns_app(n) :- router_on(n). +router_returns_app(n) :- router_mount_app(n). +router_returns_app(n) :- router_mount_foreign(n). +router_returns_app(n) :- router_fallback(n). +// router_mw_wrapper(Specifier, Name): `name(fn)` is middleware whose body is `fn` +.decl router_mw_wrapper(c0:symbol, c1:symbol) +router_mw_wrapper("hono/factory", "createMiddleware"). +// router_mw_combinator(Specifier, Name): `name(mw, ...)` is one middleware running its +// function arguments; router_mw_except: `name(paths, mw)` runs mw but on those paths +.decl router_mw_combinator(c0:symbol, c1:symbol) +router_mw_combinator("hono/combine", "every"). +router_mw_combinator("hono/combine", "some"). +.decl router_mw_except(c0:symbol, c1:symbol) +router_mw_except("hono/combine", "except"). +// router_handler_spread(Name): `...x.name(a, b)` spreads its arguments as handlers +.decl router_handler_spread(c0:symbol) +router_handler_spread("createHandlers"). +// ── a client that sends to a route (framework-behavior/http-rpc-client.dl) ── +// router_rpc_client: `name(base)` is a client whose property path is a route path and +// whose router_rpc_verb methods send (JavaScript has no type argument naming the app, so +// it is matched against every route); router_test_client: `name(app)` is the same over +// one app; router_app_request: `app.(path, init)` sends to the app itself +.decl router_rpc_client(c0:symbol, c1:symbol) +router_rpc_client("hono/client", "hc"). +.decl router_test_client(c0:symbol, c1:symbol) +router_test_client("hono/testing", "testClient"). +.decl router_rpc_index(c0:symbol) +router_rpc_index("index"). +.decl router_rpc_verb(c0:symbol, c1:symbol) +router_rpc_verb("$get", "GET"). router_rpc_verb("$post", "POST"). +router_rpc_verb("$put", "PUT"). router_rpc_verb("$delete", "DELETE"). +router_rpc_verb("$patch", "PATCH"). router_rpc_verb("$options", "OPTIONS"). +.decl router_app_request(c0:symbol) +router_app_request("request"). +.decl router_init_method_key(c0:symbol) +router_init_method_key("method"). +// router_fetch_fn: the platform function a program sends a request with (`fetch(url, init)`); router_url_class: the +// URL class (`new URL(path, base)`); router_local_host: a host name that is this machine +.decl router_fetch_fn(c0:symbol) +router_fetch_fn("fetch"). +.decl router_url_class(c0:symbol) +router_url_class("URL"). +.decl router_local_host(c0:symbol) +router_local_host("localhost"). router_local_host("127.0.0.1"). router_local_host("0.0.0.0"). router_local_host("[::1]"). + +// ── OpenAPI routes (config-resolution/http-router-openapi.dl) ─────────────── +// router_openapi: `app.(def, handler, hook?)` registers the route a definition describes; router_route_def: the +// function a definition is made with (`createRoute({ method, path, middleware })`), which returns its argument; +// router_def_key(Written, Role): the definition's keys +.decl router_openapi(c0:symbol) +router_openapi("openapi"). +.decl router_route_def(c0:symbol, c1:symbol) +router_route_def("@hono/zod-openapi", "createRoute"). +.decl router_def_key(c0:symbol, c1:symbol) +router_def_key("method", "method"). router_def_key("path", "path"). router_def_key("middleware", "middleware"). + +// the context's keyed write and read, and its whole-store view (framework-behavior/http-router-ctx-value.dl) +.decl router_ctx_set(c0:symbol) +router_ctx_set("set"). +.decl router_ctx_get(c0:symbol) +router_ctx_get("get"). +.decl router_ctx_var(c0:symbol) +router_ctx_var("var"). diff --git a/graph/javascript/engine/framework-behavior/http-router-chain.dl b/graph/javascript/engine/framework-behavior/http-router-chain.dl new file mode 100644 index 000000000..b66361b24 --- /dev/null +++ b/graph/javascript/engine/framework-behavior/http-router-chain.dl @@ -0,0 +1,79 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP ROUTER CHAIN (JavaScript: what the router does at request time) +// +// The JavaScript counterpart of typescript/engine/framework-behavior/http-router-chain.dl: +// +// ctx_key_flow(Setter, Reader, Key) +// a function on a route's chain writes a context key (`c.set('user', u)`) and a +// later function on the same chain reads it (`c.get('user')`, `c.var.user`). +// +// The context is the first parameter of a function the router calls; a key is what +// the value flow knows a string to be. A dynamic key, and a read no earlier function +// on any of its chains serves, are declared in framework_undetermined. +// ============================================================================ + +.decl jb_ctx_ref(c0:symbol, c1:symbol) +jb_ctx_ref(e, m) :- jr_node_fn(_, _, m), param_decl("client", _, "0", m, p), expr_param(_, p, e). + +.decl jb_set_site(c0:symbol, c1:symbol, c2:symbol) +jb_set_site(m, ce, k) :- call_site(_, "METHOD_CALL", "set", _, r, _, ce, _, _), jb_ctx_ref(r, m), call_arg(ce, 0, k). +.decl jb_get_site(c0:symbol, c1:symbol, c2:symbol) +jb_get_site(m, ce, k) :- call_site(_, "METHOD_CALL", "get", _, r, _, ce, _, _), jb_ctx_ref(r, m), call_arg(ce, 0, k). +.decl jb_set_at(c0:symbol, c1:symbol, c2:symbol) +jb_set_at(m, key, ce) :- jb_set_site(m, ce, k), expr_value(k, "str", key). +.decl jb_get_at(c0:symbol, c1:symbol, c2:symbol) +jb_get_at(m, key, ce) :- jb_get_site(m, ce, k), expr_value(k, "str", key). +jb_get_at(m, key, e) :- expr_kind(_, "PROPERTY_ACCESS", _, e), expr_name(_, key, e), expr_child(_, e, "ACCESS_TARGET", _, v), + jb_var_expr(v, m). +// `const { K } = c.var`: each destructured name is a read of that key, at the `c.var`. The IR keeps +// the name a property is bound to, not the property: a renamed one (`{ K: x }`) reads x, which no +// setter writes, so it is declared (no_setter_on_chain), never linked to the wrong key. +jb_get_at(m, key, v) :- var_binding_form("client", "OBJECT_PATTERN", h), var_init("client", _, v, h), jb_var_expr(v, m), + var_decl("client", key, _, _, _, _, h). +// `c.var`, on a context +.decl jb_var_expr(c0:symbol, c1:symbol) +jb_var_expr(v, m) :- expr_kind(_, "PROPERTY_ACCESS", _, v), expr_name(_, "var", v), expr_child(_, v, "ACCESS_TARGET", _, c), jb_ctx_ref(c, m). +.decl jb_keyed(c0:symbol) +jb_keyed(k) :- jb_set_site(_, _, k), expr_value(k, "str", _). +jb_keyed(k) :- jb_get_site(_, _, k), expr_value(k, "str", _). +framework_undetermined(m, "ctx_key", "dynamic_ctx_key") :- jb_set_site(m, _, k), !jb_keyed(k). +framework_undetermined(m, "ctx_key", "dynamic_ctx_key") :- jb_get_site(m, _, k), !jb_keyed(k). +.decl jb_set(c0:symbol, c1:symbol) +jb_set(m, key) :- jb_set_at(m, key, _). +.decl jb_get(c0:symbol, c1:symbol) +jb_get(m, key) :- jb_get_at(m, key, _). +.decl jb_pos(c0:symbol, c1:number, c2:number) +jb_pos(e, to_number(l), to_number(c)) :- (jb_set_at(_, _, e) ; jb_get_at(_, _, e)), expr_span(_, l, c, _, _, e). +.decl jb_set_before_get(c0:symbol, c1:symbol) +jb_set_before_get(m, key) :- jb_set_at(m, key, s), jb_get_at(m, key, g), jb_pos(s, sl, sc), jb_pos(g, gl, gc), + (sl < gl ; sl = gl, sc < gc). + +.decl jb_chain(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +jb_chain(h, vv, p, mw, to_number(pos)) :- middleware_applies(mw, h, vv, p, pos, _). +jb_chain(h, vv, p, h, 100000) :- http_route(h, vv, p, _, _). + +// ctx_key_flow(Setter, Reader, Key) — on some route's chain, Setter runs before Reader +// (or is Reader, setting before it reads) and writes the context key Reader reads. +ctx_key_flow(s, r, key) :- jb_set_live(s, key), jb_get(r, key), jb_chain(h, vv, p, s, i), jb_chain(h, vv, p, r, j), i < j. +// a set a middleware makes after calling its `next` runs once every later function on the chain has +// returned: only the middleware itself reads it back (jb_set_before_get) +.decl jb_set_live(c0:symbol, c1:symbol) +jb_set_live(m, key) :- jb_set_at(m, key, ce), !jb_after_next(m, ce). +.decl jb_next_call(c0:symbol, c1:symbol) +jb_next_call(m, nc) :- jb_set_at(m, _, _), param_decl("client", _, "1", m, p), expr_param(_, p, n), + call_site(_, "FUNCTION_CALL", _, _, _, _, nc, _, _), expr_child(_, nc, "CALLEE", _, n). +.decl jb_after_next(c0:symbol, c1:symbol) +jb_after_next(m, ce) :- jb_set_at(m, _, ce), jb_next_call(m, nc), !jb_next_guarded(m, nc), expr_span(_, nl, nc0, _, _, nc), jb_pos(ce, sl, sc), + (to_number(nl) < sl ; to_number(nl) = sl, to_number(nc0) < sc). +// a `next()` in a branch, a loop or a try (`if (skip) return next()`) of the function itself may not have run +// before a later set: a block of m whose span holds the call +.decl jb_next_guarded(c0:symbol, c1:symbol) +jb_next_guarded(m, nc) :- jb_next_call(m, nc), expr_span(_, l, c, _, _, nc), block_owner(k, m, b), block_span(_, _, l1, c1, l2, c2, b), + (jr_cond_kind(k) ; jr_loop_kind(k) ; k = "TRY"), + (to_number(l) > to_number(l1) ; to_number(l) = to_number(l1), to_number(c) >= to_number(c1)), + (to_number(l) < to_number(l2) ; to_number(l) = to_number(l2), to_number(c) <= to_number(c2)). +ctx_key_flow(s, s, key) :- jb_set_before_get(s, key), jb_chain(_, _, _, s, _). +.decl jb_read_served(c0:symbol, c1:symbol) +jb_read_served(r, key) :- ctx_key_flow(_, r, key). +framework_undetermined(r, "ctx_key", "no_setter_on_chain") :- jb_get(r, key), jb_chain(_, _, _, r, _), + !jb_read_served(r, key). diff --git a/graph/javascript/engine/framework-behavior/http-router-ctx-value.dl b/graph/javascript/engine/framework-behavior/http-router-ctx-value.dl new file mode 100644 index 000000000..50f54d103 --- /dev/null +++ b/graph/javascript/engine/framework-behavior/http-router-ctx-value.dl @@ -0,0 +1,30 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP ROUTER CONTEXT VALUES (what `c.get(k)` holds, JavaScript) +// +// JavaScript has no Env type, so what a context read holds is what a function registered on +// the SAME app writes under that key: `c.set('services', { orders: new OrderService(db) })` +// in a middleware, `const { orders } = c.get('services')` / `c.var.services.orders` in a +// handler. The read takes the written value, so the flow engine follows it on like any other +// value (destructuring, members, calls). Keyed by the app the writer and the reader are +// registered on (jr_reg), never by the key alone. Positive, inside the expr_value fixpoint. +// Framework names live in knobs.dl. +// ============================================================================ +.decl jcx_fn_root(c0:symbol, c1:symbol) // (function, app) the function is registered on the app +// any argument of a registration that is a function value, or a knob wrapper's function (`use(p, createMiddleware(fn))`, +// or a const holding one); read off call_arg rather than the route table's handler arguments, which use negation +jcx_fn_root(m, a) :- jr_reg(ce, a, _), call_arg(ce, _, x), expr_value(x, "func", m). +jcx_fn_root(m, a) :- jr_reg(ce, a, _), call_arg(ce, _, x), jr_wrapper_call(x), call_arg(x, 0, y), expr_value(y, "func", m). +jcx_fn_root(m, a) :- jr_reg(ce, a, _), call_arg(ce, _, x), expr_binding(_, v, x), var_init(_, _, i, v), jr_wrapper_call(i), + call_arg(i, 0, y), expr_value(y, "func", m). +.decl jcx_ctx(c0:symbol, c1:symbol) // (context expression, app) +jcx_ctx(e, a) :- jcx_fn_root(m, a), param_decl("client", _, "0", m, p), expr_param(_, p, e). +.decl jcx_set(c0:symbol, c1:symbol, c2:symbol) // (app, key, written value) +jcx_set(a, key, v) :- call_site(_, "METHOD_CALL", sn, _, r, _, ce, _, _), router_ctx_set(sn), jcx_ctx(r, a), + call_arg(ce, 0, k), expr_value(k, "str", key), call_arg(ce, 1, v). +// `c.get(k)` +expr_value(g, k2, i2) :- call_site(_, "METHOD_CALL", gn, _, r, _, g, _, _), router_ctx_get(gn), jcx_ctx(r, a), + call_arg(g, 0, k), expr_value(k, "str", key), jcx_set(a, key, v), expr_value(v, k2, i2). +// `c.var.k` +expr_value(e, k2, i2) :- expr_kind(_, "PROPERTY_ACCESS", _, e), expr_name(_, key, e), expr_child(_, e, "ACCESS_TARGET", _, vx), + expr_kind(_, "PROPERTY_ACCESS", _, vx), expr_name(_, vn, vx), router_ctx_var(vn), expr_child(_, vx, "ACCESS_TARGET", _, r), + jcx_ctx(r, a), jcx_set(a, key, v), expr_value(v, k2, i2). diff --git a/graph/javascript/engine/framework-behavior/http-rpc-client.dl b/graph/javascript/engine/framework-behavior/http-rpc-client.dl new file mode 100644 index 000000000..5a056988c --- /dev/null +++ b/graph/javascript/engine/framework-behavior/http-rpc-client.dl @@ -0,0 +1,295 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP RPC CLIENT (JavaScript: a request that names a route) +// +// The JavaScript counterpart of typescript/engine/framework-behavior/http-rpc-client.dl. +// Three ways a program sends a request to a route this engine has in http_route: +// * `app.request('/items/42', { method })` the app value itself, in a test; +// * `testClient(app).items[':id'].$get()` a client over an app value; +// * `hc(base).items[':id'].$get()` a client with no app named: JavaScript +// has no type argument, so it is matched against every route in the graph. +// Each property is a path segment (`index` adds none, `[':id']` the written segment) and +// `$` sends. The send joins the route whose full path it fits: `exact` when every +// segment is equal, `route_shape` when a route parameter stood in; of several, the fewest +// stand-ins win. A client with no app named is never better than `route_shape`. +// +// remote_edge(Sender, Handler, "http", " ", Confidence) +// remote_unserved(Sender, "http", " ") +// ============================================================================ + +// (client root call, app list; "*" = every app) +.decl jc_root(c0:symbol, c1:symbol) +jc_root(ce, "*") :- jr_knob_call(ce, spec, n), router_rpc_client(spec, n). +jc_root(ce, a) :- jr_knob_call(ce, spec, n), router_test_client(spec, n), call_arg(ce, 0, x), + expr_value(x, "router_app", a). + +// the path a client expression has accumulated +.decl jc_cpath(c0:symbol, c1:symbol, c2:symbol) +jc_cpath(ce, a, "") :- jc_root(ce, a). +jc_cpath(e, a, p) :- expr_kind(_, "IDENTIFIER", _, e), expr_binding(_, v, e), var_init(_, _, i, v), jc_cpath(i, a, p). +jc_cpath(e, a, p) :- expr_kind(_, "PROPERTY_ACCESS", _, e), expr_name(_, n, e), router_rpc_index(n), + expr_child(_, e, "ACCESS_TARGET", _, r), jc_cpath(r, a, p). +jc_cpath(e, a, cat(p, cat("/", n))) :- expr_kind(_, "PROPERTY_ACCESS", _, e), expr_name(_, n, e), + !router_rpc_index(n), !router_rpc_verb(n, _), expr_child(_, e, "ACCESS_TARGET", _, r), jc_cpath(r, a, p), + strlen(p) < 300. +jc_cpath(e, a, cat(p, cat("/", k))) :- expr_kind(_, "ELEMENT_ACCESS", _, e), expr_child(_, e, "ACCESS_TARGET", _, r), + jc_cpath(r, a, p), expr_child(_, e, "COMPUTED_KEY", _, x), expr_value(x, "str", k), strlen(p) < 300. +// a function that returns a client: each call is that client +jc_cpath(ce, a, p) :- expr_kind(_, "CALL", _, ce), expr_resolves_to_method(ce, w), jc_return_expr(w, e), jc_cpath(e, a, p). +.decl jc_return_expr(c0:symbol, c1:symbol) +jc_return_expr(w, e) :- expr_root(_, "RETURN", e), expr_owner(_, w, _, e). + +// (site, sender, app, verb, path) +.decl jc_send(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +jc_send(ce, from, a, vv, p) :- call_site(_, "METHOD_CALL", cn, _, r, from, ce, _, _), router_rpc_verb(cn, vv), + jc_cpath(r, a, p0), p0 != "", p = p0. +jc_send(ce, from, a, vv, "/") :- call_site(_, "METHOD_CALL", cn, _, r, from, ce, _, _), router_rpc_verb(cn, vv), + jc_cpath(r, a, ""). +// `app.request(path, init?)`: GET unless the init names a method +.decl jc_req(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +jc_req(ce, from, a, p) :- jc_req_raw(ce, from, a, raw), jc_req_path(raw, p). +// the URL as written: a path, or an absolute URL whose path is taken (`http://localhost/x`); the query +// string and fragment are not part of the path (SPEC 3.5, ruling R9) +.decl jc_req_raw(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +jc_req_raw(ce, from, a, raw) :- call_site(_, "METHOD_CALL", cn, _, r, from, ce, _, _), router_app_request(cn), + expr_value(r, "router_app", a), call_arg(ce, 0, x), expr_value(x, "str", raw), strlen(raw) >= 1. +.decl jc_sch(c0:symbol, c1:number) +jc_sch(raw, i) :- jc_req_raw(_, _, _, raw), strlen(raw) >= 3, i = range(0, strlen(raw) - 2), substr(raw, i, 3) = "://". +.decl jc_after(c0:symbol, c1:symbol) +jc_after(raw, r) :- jc_sch(raw, _), i = min x : { jc_sch(raw, x) }, r = substr(raw, i + 3, strlen(raw) - i - 3). +.decl jc_aslash(c0:symbol, c1:number) +jc_aslash(r, i) :- jc_after(_, r), i = range(0, strlen(r)), substr(r, i, 1) = "/". +.decl jc_full(c0:symbol, c1:symbol) +jc_full(raw, raw) :- jc_req_raw(_, _, _, raw), substr(raw, 0, 1) = "/". +jc_full(raw, p) :- jc_after(raw, r), m = min x : { jc_aslash(r, x) }, p = substr(r, m, strlen(r) - m). +jc_full(raw, "/") :- jc_after(raw, r), !jc_aslash(r, _). +.decl jc_cut(c0:symbol, c1:number) +jc_cut(f, i) :- jc_full(_, f), i = range(0, strlen(f)), (substr(f, i, 1) = "?" ; substr(f, i, 1) = "#"). +.decl jc_req_path(c0:symbol, c1:symbol) +jc_req_path(raw, f) :- jc_full(raw, f), !jc_cut(f, _). +jc_req_path(raw, q) :- jc_full(raw, f), m = min i : { jc_cut(f, i) }, m > 0, q = substr(f, 0, m). +jc_req_path(raw, "/") :- jc_full(raw, f), jc_cut(f, 0). +.decl jc_req_method(c0:symbol, c1:symbol) +jc_req_method(ce, vv) :- jc_req(ce, _, _, _), call_arg(ce, 1, o), expr_value(o, k, i), prop_value(k, i, key, "str", w), + router_init_method_key(key), router_verb_name(w, vv). +.decl jc_req_has_method(c0:symbol) +jc_req_has_method(ce) :- jc_req_method(ce, _). +jc_send(ce, from, a, vv, p) :- jc_req(ce, from, a, p), jc_req_method(ce, vv), !jc_req_mu(ce). +jc_send(ce, from, a, "GET", p) :- jc_req(ce, from, a, p), !jc_req_has_method(ce), !jc_req_mu(ce). +// a request whose method is not decidable (SPEC ruling R17) stands for every verb (`*`), as a fetch does below: an +// init that is not an object the program shows, a method that is not a literal verb, or a method set only in a branch +jc_send(ce, from, a, "*", p) :- jc_req(ce, from, a, p), jc_req_mu(ce). +.decl jc_req_mu(c0:symbol) +jc_req_mu(ce) :- jc_req(ce, _, _, _), call_arg(ce, 1, o), !jc_req_init_obj(o). +jc_req_mu(ce) :- jc_req(ce, _, _, _), call_arg(ce, 1, o), expr_value(o, "obj", l), jf_lit_method(l), !jc_req_has_method(ce). +jc_req_mu(ce) :- jc_req(ce, _, _, _), call_arg(ce, 1, o), expr_value(o, "obj", l), jf_cond_method_write(l), !jf_lit_method(l). +.decl jc_req_init_obj(c0:symbol) +jc_req_init_obj(o) :- jc_req(ce, _, _, _), call_arg(ce, 1, o), expr_value(o, "obj", _). + +// the routes a send may reach: (app, verb, full path, handler) +.decl jc_app_route(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +jc_app_route(a, vv, fp, h) :- jc_send(_, _, a, _, _), a != "*", http_route(h, vv, fp, a, _). +jc_app_route(a, vv, fp, h) :- jc_send(_, _, a, _, _), a != "*", jr_flat(r, a, "/", _, _, _), http_route(h, vv, fp, r, _). +jc_app_route("*", vv, fp, h) :- jc_send(_, _, "*", _, _), http_route(h, vv, fp, _, _). + +.decl jc_path(c0:symbol) +jc_path(p) :- jc_send(_, _, _, _, p). +jc_path(p) :- jc_app_route(_, _, p, _). +.decl jc_slash(c0:symbol, c1:number) +jc_slash(p, i) :- jc_path(p), i = range(0, strlen(p)), substr(p, i, 1) = "/". +.decl jc_next(c0:symbol, c1:number, c2:number) +jc_next(p, i, j) :- jc_slash(p, i), j = min x : { jc_slash(p, x), x > i }. +.decl jc_has_next(c0:symbol, c1:number) +jc_has_next(p, i) :- jc_next(p, i, _). +.decl jc_seg_at(c0:symbol, c1:number, c2:symbol) +jc_seg_at(p, i, t) :- jc_next(p, i, j), t = substr(p, i + 1, j - i - 1). +jc_seg_at(p, i, t) :- jc_slash(p, i), !jc_has_next(p, i), t = substr(p, i + 1, strlen(p) - i - 1). +.decl jc_seg_ne(c0:symbol, c1:number) +jc_seg_ne(p, i) :- jc_seg_at(p, i, t), t != "". +.decl jc_seg(c0:symbol, c1:number, c2:symbol) +jc_seg(p, k, t) :- jc_seg_at(p, i, t), t != "", k = count : { jc_seg_ne(p, x), x < i }. +.decl jc_nseg(c0:symbol, c1:number) +jc_nseg(p, n) :- jc_path(p), n = count : { jc_seg(p, _, _) }. +.decl jc_param(c0:symbol) +jc_param(t) :- jc_seg(_, _, t), substr(t, 0, 1) = ":". +jc_param("*"). + +.decl jc_pair(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +jc_pair(ce, h, p, rp) :- jc_send(ce, _, a, sv, p), jc_app_route(a, rv, rp, h), (rv = sv ; rv = "ANY" ; sv = "*"), + jc_nseg(p, n), jc_nseg(rp, n). +.decl jc_conflict(c0:symbol, c1:symbol) +jc_conflict(p, rp) :- jc_pair(_, _, p, rp), jc_seg(p, k, x), jc_seg(rp, k, y), x != y, !jc_param(y). +.decl jc_ndiff(c0:symbol, c1:symbol, c2:number) +jc_ndiff(p, rp, n) :- jc_pair(_, _, p, rp), !jc_conflict(p, rp), n = count : { jc_seg(p, k, x), jc_seg(rp, k, y), x != y }. +.decl jc_best(c0:symbol, c1:number) +jc_best(ce, b) :- jc_pair(ce, _, p, _), jc_ndiff(p, _, _), b = min n : { jc_pair(ce, _, p2, rp2), jc_ndiff(p2, rp2, n) }. + +// remote_edge(Sender, Handler, "http", " ", Confidence) — a request this +// function sends that the handler serves, joined on the route path +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "exact") :- jc_send(ce, from, a, sv, p), a != "*", sv != "*", jc_pair(ce, h, p, rp), + jc_ndiff(p, rp, 0), jc_best(ce, 0), from != h. +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "route_shape") :- jc_send(ce, from, _, sv, p), sv != "*", jc_pair(ce, h, p, rp), + jc_ndiff(p, rp, n), jc_best(ce, n), from != h, (n > 0 ; jc_unbound(ce)). +// a send whose verb is not decidable: every route of any verb its path fits best, "may reach" (SPEC ruling R17) +remote_edge(from, h, "http", cat("* ", p), "method_unknown") :- jc_send(ce, from, _, "*", p), jc_pair(ce, h, p, rp), + jc_ndiff(p, rp, n), jc_best(ce, n), from != h. +.decl jc_unbound(c0:symbol) +jc_unbound(ce) :- jc_send(ce, _, "*", _, _). +.decl jc_served(c0:symbol) +jc_served(ce) :- jc_best(ce, _). +// remote_unserved(Sender, "http", " ") — a send no route fits +remote_unserved(from, "http", cat(sv, cat(" ", p))) :- jc_send(ce, from, _, sv, p), !jc_served(ce). + +// ── `fetch(url, init)`: a request to this machine, or to a base the program does not spell (SPEC R14, R14a) ── +// The URL as written, `{}` for every piece the program does not show: a literal, a template (each substitution its +// literal value when the flow engine knows exactly one, else a hole), `new URL(path, base)`. A request to localhost +// joins with the confidence of its match; one whose base is a hole (`${host}/x`, `new URL('/x', endpoint)`), whose +// host is computed, or whose literal host is a single label (`http://billing:9000`, a service of the same +// deployment) joins with confidence base_unknown; a relative path or a host with a dot names no app here. +.decl jf_call(c0:symbol, c1:symbol) +jf_call(ce, from) :- call_site(_, "FUNCTION_CALL", n, _, _, from, ce, _, _), router_fetch_fn(n), !expr_resolves_to_method(ce, _). +// the expressions whose text is needed: the URL argument, and the path argument of `new URL(path, base)` +.decl jf_need(c0:symbol) +jf_need(x) :- jf_call(ce, _), call_arg(ce, 0, x). +jf_need(pa) :- jf_need(x), expr_kind(_, "NEW", _, x), expr_child(_, x, "ARGUMENT", "1", pa). +.decl jf_txt(c0:symbol, c1:symbol) +jf_txt(x, s) :- jf_need(x), expr_value(x, "str", s). +.decl jf_tmpl(c0:symbol, c1:symbol, c2:symbol) +jf_tmpl(x, x, raw) :- jf_need(x), expr_kind(_, "TEMPLATE", _, x), expr_child(_, x, _, _, _), + expr_text(_, raw, x), strlen(raw) >= 2. +.decl jf_sub_n(c0:symbol, c1:symbol, c2:number) +jf_sub_n(x, idx, n) :- jf_tmpl(_, x, _), expr_child(_, x, "TEMPLATE_SUBSTITUTION", idx, c), n = count : { expr_value(c, "str", _) }. +.decl jf_sub(c0:symbol, c1:symbol, c2:symbol) +jf_sub(x, idx, s) :- jf_sub_n(x, idx, 1), expr_child(_, x, "TEMPLATE_SUBSTITUTION", idx, c), expr_value(c, "str", s). +jf_sub(x, idx, "{}") :- jf_sub_n(x, idx, n), n != 1. +// (template, index, text so far, brace depth inside a substitution, substitutions passed) +.decl jf_tstep(c0:symbol, c1:number, c2:symbol, c3:number, c4:number) +jf_tstep(x, 1, "", 0, 0) :- jf_tmpl(_, x, _). +jf_tstep(x, i + 2, cat(acc, s), 1, h) :- jf_tstep(x, i, acc, 0, h), jf_tmpl(_, x, raw), i + 2 < strlen(raw), + substr(raw, i, 2) = "${", jf_sub(x, to_string(h), s), strlen(acc) < 300. +jf_tstep(x, i + 1, cat(acc, c), 0, h) :- jf_tstep(x, i, acc, 0, h), jf_tmpl(_, x, raw), i + 1 < strlen(raw), + c = substr(raw, i, 1), (c != "$" ; substr(raw, i + 1, 1) != "{"), strlen(acc) < 300. +jf_tstep(x, i + 1, acc, d + 1, h) :- jf_tstep(x, i, acc, d, h), d > 0, jf_tmpl(_, x, raw), i + 1 < strlen(raw), substr(raw, i, 1) = "{", d < 20. +jf_tstep(x, i + 1, acc, d - 1, h) :- jf_tstep(x, i, acc, d, h), d > 1, jf_tmpl(_, x, raw), i + 1 < strlen(raw), substr(raw, i, 1) = "}". +jf_tstep(x, i + 1, acc, 0, h + 1) :- jf_tstep(x, i, acc, 1, h), jf_tmpl(_, x, raw), i + 1 < strlen(raw), substr(raw, i, 1) = "}". +jf_tstep(x, i + 1, acc, d, h) :- jf_tstep(x, i, acc, d, h), d > 0, jf_tmpl(_, x, raw), i + 1 < strlen(raw), + c = substr(raw, i, 1), c != "{", c != "}". +jf_txt(x, v) :- jf_tmpl(x, _, raw), jf_tstep(x, i, v, 0, _), i = strlen(raw) - 1. +.decl jf_url(c0:symbol, c1:symbol) +jf_url(ce, s) :- jf_call(ce, _), call_arg(ce, 0, x), jf_txt(x, s). +// `new URL(path, base)`: a literal absolute path under the base's origin, a hole when the base is not a literal +.decl jf_newurl(c0:symbol, c1:symbol, c2:symbol) +jf_newurl(ce, p, b) :- jf_call(ce, _), call_arg(ce, 0, x), expr_kind(_, "NEW", _, x), expr_child(_, x, "CALLEE", _, cc), + expr_text(_, cn, cc), router_url_class(cn), expr_child(_, x, "ARGUMENT", "1", pa), jf_txt(pa, p), + strlen(p) >= 1, substr(p, 0, 1) = "/", expr_child(_, x, "ARGUMENT", "2", b). +jf_url(ce, cat("{}", p)) :- jf_newurl(ce, p, b), !expr_value(b, "str", _). +// …its literal base's origin: `scheme://host` (a stratum of its own, before the URLs it completes) +.decl jf_origin_need(c0:symbol) +jf_origin_need(bs) :- jf_newurl(_, _, b), expr_value(b, "str", bs). +.decl jf_osch(c0:symbol, c1:number) +jf_osch(u, i) :- jf_origin_need(u), strlen(u) >= 3, i = range(0, strlen(u) - 2), substr(u, i, 3) = "://". +.decl jf_oend(c0:symbol, c1:number) +jf_oend(u, j) :- jf_osch(u, _), i = min y : { jf_osch(u, y) }, j = range(i + 3, strlen(u)), (substr(u, j, 1) = "/" ; substr(u, j, 1) = "?" ; substr(u, j, 1) = "#"). +.decl jf_origin(c0:symbol, c1:symbol) +jf_origin(u, substr(u, 0, j)) :- jf_oend(u, _), j = min y : { jf_oend(u, y) }. +jf_origin(u, u) :- jf_osch(u, _), !jf_oend(u, _). +.decl jf_url_all(c0:symbol, c1:symbol) +jf_url_all(ce, u) :- jf_url(ce, u). +jf_url_all(ce, cat(o, p)) :- jf_newurl(ce, p, b), expr_value(b, "str", bs), jf_origin(bs, o). +.decl jf_sch(c0:symbol, c1:number) +jf_sch(u, i) :- jf_url_all(_, u), strlen(u) >= 3, i = range(0, strlen(u) - 2), substr(u, i, 3) = "://". +.decl jf_after(c0:symbol, c1:symbol, c2:number) +jf_after(u, r, i) :- jf_sch(u, _), i = min y : { jf_sch(u, y) }, r = substr(u, i + 3, strlen(u) - i - 3). +.decl jf_rslash(c0:symbol, c1:number) +jf_rslash(r, j) :- jf_after(_, r, _), j = range(0, strlen(r)), (substr(r, j, 1) = "/" ; substr(r, j, 1) = "?" ; substr(r, j, 1) = "#"). +.decl jf_hostpath(c0:symbol, c1:symbol, c2:symbol) +jf_hostpath(u, h, p) :- jf_after(u, r, _), jf_rslash(r, _), j = min y : { jf_rslash(r, y) }, h = substr(r, 0, j), p = substr(r, j, strlen(r) - j). +jf_hostpath(u, r, "/") :- jf_after(u, r, _), !jf_rslash(r, _). +.decl jf_hostname(c0:symbol, c1:symbol) +jf_hostname(h, substr(h, 0, i)) :- jf_hostpath(_, h, _), substr(h, 0, 1) != "[", contains(":", h), + i = min y : { y = range(0, strlen(h)), substr(h, y, 1) = ":" }. +jf_hostname(h, h) :- jf_hostpath(_, h, _), (!contains(":", h) ; substr(h, 0, 1) = "["). +// (call, raw path, confidence) +.decl jf_raw(c0:symbol, c1:symbol, c2:symbol) +jf_raw(ce, p, "exact") :- jf_url_all(ce, u), jf_hostpath(u, h, p), jf_hostname(h, hn), router_local_host(hn). +jf_raw(ce, p, "base_unknown") :- jf_url_all(ce, u), jf_hostpath(u, h, p), jf_hostname(h, hn), contains("{}", hn). +jf_raw(ce, p, "base_unknown") :- jf_url_all(ce, u), jf_hostpath(u, h, p), jf_hostname(h, hn), hn != "", !contains("{}", hn), + !contains(".", hn), !router_local_host(hn), substr(hn, 0, 1) != "[". +// a leading hole (`${host}/x`, an optional `:port` after it) +jf_raw(ce, p, "base_unknown") :- jf_url_all(ce, u), !jf_sch(u, _), strlen(u) > 3, substr(u, 0, 2) = "{}", r = substr(u, 2, strlen(u) - 2), + substr(r, 0, 1) = "/", p = r. +jf_raw(ce, p, "base_unknown") :- jf_url_all(ce, u), jf_portrest(u, r), j = min y : { y = range(0, strlen(r)), substr(r, y, 1) = "/" }, + p = substr(r, j, strlen(r) - j). +.decl jf_portrest(c0:symbol, c1:symbol) +jf_portrest(u, r) :- jf_url_all(_, u), !jf_sch(u, _), strlen(u) > 3, substr(u, 0, 3) = "{}:", r = substr(u, 3, strlen(u) - 3), + contains("/", r). +// the query string and fragment are not the path (SPEC R9) +.decl jf_cut(c0:symbol, c1:number) +jf_cut(p, i) :- jf_raw(_, p, _), i = range(0, strlen(p)), (substr(p, i, 1) = "?" ; substr(p, i, 1) = "#"). +.decl jf_path(c0:symbol, c1:symbol) +jf_path(p, p) :- jf_raw(_, p, _), !jf_cut(p, _). +jf_path(p, q) :- jf_raw(_, p, _), m = min i : { jf_cut(p, i) }, m > 0, q = substr(p, 0, m). +jf_path(p, "/") :- jf_raw(_, p, _), jf_cut(p, 0). +.decl jf_method(c0:symbol, c1:symbol) +jf_method(ce, vv) :- jf_raw(ce, _, _), call_arg(ce, 1, o), expr_value(o, k, i), prop_value(k, i, key, "str", w), + router_init_method_key(key), router_verb_name(w, vv). +.decl jf_has_method(c0:symbol) +jf_has_method(ce) :- jf_method(ce, _). +// (call, sender, verb, path, confidence) +.decl jf_req(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +jf_req(ce, from, vv, p, cf) :- jf_raw(ce, raw, cf), jf_path(raw, p), jf_call(ce, from), jf_method(ce, vv), !jf_mu(ce). +jf_req(ce, from, "GET", p, cf) :- jf_raw(ce, raw, cf), jf_path(raw, p), jf_call(ce, from), !jf_has_method(ce), !jf_mu(ce). +// a request whose method is not decidable (SPEC ruling R17) stands for every verb (`*`): an init object whose OWN +// text names no method, given one only inside a branch (`if (push) init.method = 'POST'`, GET or POST at run +// time), an init that is not an object the program shows, or a method that is not a literal +jf_req(ce, from, "*", p, cf) :- jf_raw(ce, raw, cf), jf_path(raw, p), jf_call(ce, from), jf_mu(ce). +.decl jf_mu(c0:symbol) +jf_mu(ce) :- jf_raw(ce, _, _), call_arg(ce, 1, o), expr_value(o, "obj", l), jf_cond_method_write(l), !jf_lit_method(l). +jf_mu(ce) :- jf_raw(ce, _, _), call_arg(ce, 1, o), !jf_init_obj(o). +jf_mu(ce) :- jf_raw(ce, _, _), call_arg(ce, 1, o), expr_value(o, "obj", l), jf_lit_method(l), !jf_has_method(ce). +.decl jf_init_obj(c0:symbol) +jf_init_obj(o) :- jf_raw(ce, _, _), call_arg(ce, 1, o), expr_value(o, "obj", _). +.decl jf_lit_method(c0:symbol) +jf_lit_method(l) :- expr_child(_, l, "PROPERTY_KEY", _, key), expr_name(_, n, key), router_init_method_key(n). +.decl jf_cond_method_write(c0:symbol) +jf_cond_method_write(l) :- expr_kind(_, "ASSIGNMENT", _, a), expr_child(_, a, "ASSIGNMENT_TARGET", _, tgt), + expr_kind(_, "PROPERTY_ACCESS", _, tgt), expr_name(_, n, tgt), router_init_method_key(n), + expr_child(_, tgt, "ACCESS_TARGET", _, r), expr_value(r, "obj", l), expr_kind(_, "OBJECT_LITERAL", _, l), + expr_owner(_, h, mod, a), expr_span(_, ln, c, _, _, a), block_owner(k, h, b), jr_cond_kind(k), block_span(_, mod, l1, c1, l2, c2, b), + (to_number(ln) > to_number(l1) ; to_number(ln) = to_number(l1), to_number(c) >= to_number(c1)), + (to_number(ln) < to_number(l2) ; to_number(ln) = to_number(l2), to_number(c) <= to_number(c2)). +jc_path(p) :- jf_req(_, _, _, p, _). +jc_path(fp) :- jf_req(_, _, _, _, _), http_route(_, _, fp, _, _). +// a route fits when every segment is equal, or the route's is a parameter, or the request's is a hole +.decl jf_pair(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +jf_pair(ce, h, p, rp) :- jf_req(ce, _, sv, p, _), http_route(h, rv, rp, _, _), (rv = sv ; rv = "ANY" ; sv = "*"), jc_nseg(p, n), jc_nseg(rp, n). +.decl jf_conflict(c0:symbol, c1:symbol) +jf_conflict(p, rp) :- jf_pair(_, _, p, rp), jc_seg(p, k, x), jc_seg(rp, k, y), x != y, !jc_param(y), x != "{}". +.decl jf_ndiff(c0:symbol, c1:symbol, c2:number) +jf_ndiff(p, rp, n) :- jf_pair(_, _, p, rp), !jf_conflict(p, rp), n = count : { jc_seg(p, k, x), jc_seg(rp, k, y), x != y }. +.decl jf_best(c0:symbol, c1:number) +jf_best(ce, b) :- jf_pair(ce, _, p, _), jf_ndiff(p, _, _), b = min n : { jf_pair(ce, _, p2, rp2), jf_ndiff(p2, rp2, n) }. +// a path with a hole may be any request of its shape: every route it fits; a written path: the route that fits best +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "base_unknown") :- jf_req(ce, from, sv, p, "base_unknown"), jf_pair(ce, h, p, rp), + jf_ndiff(p, rp, n), (contains("{}", p) ; jf_best(ce, n)), from != h, jf_has_lit(p), !jf_catchall(rp), !jf_test_only(ce, h, rp). +// …nor, from code outside the tests, a route only an app built in a test file serves (that app is never deployed) +.decl jf_test_path(c0:symbol) +jf_test_path(fp) :- module_file("client", fp, _), + (contains(".test.", fp) ; contains(".spec.", fp) ; contains("__tests__/", fp) ; contains("/test/", fp) ; contains("/tests/", fp) ; + contains("/e2e/", fp) ; substr(fp, 0, 5) = "test/" ; substr(fp, 0, 6) = "tests/" ; substr(fp, 0, 4) = "e2e/"). +.decl jf_route_app_in_test(c0:symbol, c1:symbol, c2:number) +jf_route_app_in_test(h, rp, t) :- jf_pair(_, h, _, rp), http_route(h, _, rp, a, _), expr_owner(_, _, mod, a), module_file("client", fp, mod), + (jf_test_path(fp), t = 1 ; !jf_test_path(fp), t = 0). +.decl jf_test_only(c0:symbol, c1:symbol, c2:symbol) +jf_test_only(ce, h, rp) :- jf_pair(ce, h, _, rp), jf_route_app_in_test(h, rp, 1), !jf_route_app_in_test(h, rp, 0), + expr_owner(_, _, mod, ce), module_file("client", fp, mod), !jf_test_path(fp). +// a request whose base is unknown names a route only through a written segment, and never a catch-all (`*`) +.decl jf_has_lit(c0:symbol) +jf_has_lit(p) :- jf_req(_, _, _, p, _), jc_seg(p, _, x), x != "{}". +.decl jf_catchall(c0:symbol) +jf_catchall(rp) :- jf_pair(_, _, _, rp), jc_seg(rp, _, "*"). +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "exact") :- jf_req(ce, from, sv, p, "exact"), sv != "*", jf_pair(ce, h, p, rp), + jf_ndiff(p, rp, 0), jf_best(ce, 0), !contains("{}", p), from != h. +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "route_shape") :- jf_req(ce, from, sv, p, "exact"), sv != "*", jf_pair(ce, h, p, rp), + jf_ndiff(p, rp, n), n > 0, (contains("{}", p) ; jf_best(ce, n)), from != h. +remote_edge(from, h, "http", cat("* ", p), "method_unknown") :- jf_req(ce, from, "*", p, "exact"), jf_pair(ce, h, p, rp), + jf_ndiff(p, rp, n), (contains("{}", p) ; jf_best(ce, n)), from != h. diff --git a/graph/javascript/souffle/decls_all.dl b/graph/javascript/souffle/decls_all.dl index bc489cb6e..8ca24fb07 100644 --- a/graph/javascript/souffle/decls_all.dl +++ b/graph/javascript/souffle/decls_all.dl @@ -622,3 +622,17 @@ .decl state_call_alloc(c0:symbol, c1:symbol, c2:symbol) .decl state_call_open(c0:symbol, c1:symbol) .decl state_world_of_gated(c0:symbol, c1:symbol) +.decl http_route(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +.decl http_route_partial(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +.decl http_mount(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +.decl middleware_applies(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +.decl middleware_site(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +.decl middleware_registered_at(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +.decl framework_undetermined(c0:symbol, c1:symbol, c2:symbol) +.decl remote_undetermined(c0:symbol, c1:symbol, c2:symbol) +.decl ctx_key_flow(c0:symbol, c1:symbol, c2:symbol) +.decl remote_edge(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +.decl remote_unserved(c0:symbol, c1:symbol, c2:symbol) +.decl route_registered_by(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +.decl method_dispatch_candidate(c0:symbol, c1:symbol, c2:symbol) +.decl fn_value_call(c0:symbol, c1:symbol) diff --git a/graph/javascript/souffle/export_manifest.tsv b/graph/javascript/souffle/export_manifest.tsv index d62ccfa3a..a6e22cb03 100644 --- a/graph/javascript/souffle/export_manifest.tsv +++ b/graph/javascript/souffle/export_manifest.tsv @@ -49,3 +49,17 @@ state_call_alloc state-call-alloc.csv state_call_open state-call-open.csv state_world_of_gated state-world.csv field_access field-access.csv +http_route http-route.csv +http_route_partial http-route-partial.csv +http_mount http-mount.csv +middleware_applies middleware-applies.csv +middleware_site middleware-site.csv +middleware_registered_at middleware-registered-at.csv +framework_undetermined framework-undetermined.csv +remote_undetermined remote-undetermined.csv +ctx_key_flow ctx-key-flow.csv +remote_edge remote-edge.csv +remote_unserved remote-unserved.csv +route_registered_by route-registered-by.csv +method_dispatch_candidate dispatch-candidates.csv +fn_value_call function-value-call.csv diff --git a/graph/test/javascript/hono/.gitignore b/graph/test/javascript/hono/.gitignore new file mode 100644 index 000000000..ba004eff9 --- /dev/null +++ b/graph/test/javascript/hono/.gitignore @@ -0,0 +1,2 @@ +.work/ +*.draft diff --git a/graph/test/javascript/hono/cases/chains/esm-services-chain/src/index.js b/graph/test/javascript/hono/cases/chains/esm-services-chain/src/index.js new file mode 100644 index 000000000..2e69dc61b --- /dev/null +++ b/graph/test/javascript/hono/cases/chains/esm-services-chain/src/index.js @@ -0,0 +1,22 @@ +import { Hono } from 'hono' +import { createMiddleware } from 'hono/factory' +import { Db, OrderService } from './services.js' + +const provide = createMiddleware(async (c, next) => { + c.set('services', { orders: new OrderService(new Db()) }) + await next() +}) + +const app = new Hono() +app.use('/orders/*', provide) + +// destructured c.get(k), then a call on the member +app.get('/orders/:id', (c) => { + const { orders } = c.get('services') + return c.json(orders.find(c.req.param('id'))) +}) + +// c.var.k read inline, two members deep +app.get('/orders/:id/total', (c) => c.json({ total: c.var.services.orders.total(c.req.param('id')) })) + +export default app diff --git a/graph/test/javascript/hono/cases/chains/esm-services-chain/src/package.json b/graph/test/javascript/hono/cases/chains/esm-services-chain/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/chains/esm-services-chain/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/chains/esm-services-chain/src/services.js b/graph/test/javascript/hono/cases/chains/esm-services-chain/src/services.js new file mode 100644 index 000000000..7a42969fe --- /dev/null +++ b/graph/test/javascript/hono/cases/chains/esm-services-chain/src/services.js @@ -0,0 +1,37 @@ +// census: ctx_di (SPEC R18, the JavaScript form; call-chain break class 1) +// The JavaScript twin of the typed TypeScript chains: no types anywhere, so what `c.get('services')` holds is only +// the provider middleware's `c.set('services', ..)` on the chain (ctx_key_flow). The repository builds its own db +// handle from a constructor argument the compiler cannot type, so service -> repository resolves statically and +// repository -> db is observed at run time. +export class Db { + get(key) { + return [key] + } + sum(key) { + return key.length + } +} + +export class OrderRepo { + constructor(db) { + this.db = db + } + byId(id) { + return this.db.get(`order:${id}`) + } + total(id) { + return this.db.sum(`order:${id}`) + } +} + +export class OrderService { + constructor(db) { + this.repo = new OrderRepo(db) + } + find(id) { + return this.repo.byId(id) + } + total(id) { + return this.repo.total(id) + } +} diff --git a/graph/test/javascript/hono/cases/js/bun-websocket-destructure/src/index.js b/graph/test/javascript/hono/cases/js/bun-websocket-destructure/src/index.js new file mode 100644 index 000000000..57ea90d35 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/bun-websocket-destructure/src/index.js @@ -0,0 +1,10 @@ +// census: none (oracle gap O10, JavaScript): a library function taken by destructuring a library call's result +import { Hono } from 'hono' +import { createBunWebSocket } from 'hono/bun' + +const { upgradeWebSocket } = createBunWebSocket() + +const app = new Hono() +app.get('/ws', upgradeWebSocket(() => ({ onMessage() {} }))) + +export default app diff --git a/graph/test/javascript/hono/cases/js/bun-websocket-destructure/src/package.json b/graph/test/javascript/hono/cases/js/bun-websocket-destructure/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/bun-websocket-destructure/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/cjs-basic/src/index.js b/graph/test/javascript/hono/cases/js/cjs-basic/src/index.js new file mode 100644 index 000000000..623aa9bac --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-basic/src/index.js @@ -0,0 +1,13 @@ +// census: new_hono, route_mount_literal, builtin_mw_import (CommonJS JavaScript; SPEC 10 C2: no CJS project +// in the corpus, torture-only) +// require('hono') destructured, a library middleware by require, a sub-app from module.exports. +const { Hono } = require('hono') +const { cors } = require('hono/cors') +const users = require('./users') + +const app = new Hono() +app.use('/api/*', cors()) +app.route('/api/users', users) +app.get('/health', (c) => c.text('ok')) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-basic/src/package.json b/graph/test/javascript/hono/cases/js/cjs-basic/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-basic/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-basic/src/users.js b/graph/test/javascript/hono/cases/js/cjs-basic/src/users.js new file mode 100644 index 000000000..4bd75392c --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-basic/src/users.js @@ -0,0 +1,6 @@ +const { Hono } = require('hono') + +const users = new Hono() +users.get('/:id', (c) => c.json({ id: c.req.param('id') })) + +module.exports = users diff --git a/graph/test/javascript/hono/cases/js/cjs-context/src/index.js b/graph/test/javascript/hono/cases/js/cjs-context/src/index.js new file mode 100644 index 000000000..7c7bde6e1 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-context/src/index.js @@ -0,0 +1,16 @@ +// census: none for CommonJS (corpus gap); CJS twin of js/esm-context +const { Hono } = require('hono') +const { createMiddleware } = require('hono/factory') + +const withUser = createMiddleware(async (c, next) => { + c.set('user', { id: 'u1' }) + await next() +}) + +const app = new Hono() +app.use('/me/*', withUser) +app.get('/me/profile', (c) => c.json(c.get('user'))) +app.get('/me/id', (c) => c.text(c.var.user.id)) +app.get('/public', (c) => c.text(String(c.get('user')))) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-context/src/package.json b/graph/test/javascript/hono/cases/js/cjs-context/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-context/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-exports-members/src/app.js b/graph/test/javascript/hono/cases/js/cjs-exports-members/src/app.js new file mode 100644 index 000000000..659538b91 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-exports-members/src/app.js @@ -0,0 +1,14 @@ +// census: none for CommonJS (corpus gap in census; shape of a CJS-on-Bun project): oracle gap O7 +// Middleware exported as `module.exports.x = fn` and imported by destructured require; a library middleware +// from a package the program cannot resolve stays in the chain. +const { Hono } = require('hono') +const { authenticate, isAdmin } = require('./auth') +const { limiter } = require('acme-rate-limit') + +const app = new Hono() +app.use('/api/*', limiter({ max: 10 })) +app.use('/api/*', authenticate) +app.get('/api/me', (c) => c.json(c.get('user'))) +app.delete('/api/users/:id', isAdmin, (c) => c.body(null, 204)) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-exports-members/src/auth.js b/graph/test/javascript/hono/cases/js/cjs-exports-members/src/auth.js new file mode 100644 index 000000000..29ea6df9e --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-exports-members/src/auth.js @@ -0,0 +1,7 @@ +module.exports.authenticate = async (c, next) => { + c.set('user', { id: 'u' }) + await next() +} +module.exports.isAdmin = async (c, next) => { + await next() +} diff --git a/graph/test/javascript/hono/cases/js/cjs-exports-members/src/package.json b/graph/test/javascript/hono/cases/js/cjs-exports-members/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-exports-members/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/checks.js b/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/checks.js new file mode 100644 index 000000000..c351556f2 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/checks.js @@ -0,0 +1,16 @@ +// Two middleware in one returned object: each read must take its own property's function. +function makeChecks(realm) { + const auth = async (c, next) => { + if (!c.req.header('authorization')) return c.text(realm, 401) + await next() + } + return { + auth, + audit: async (c, next) => { + await next() + console.log(realm, c.req.path) + }, + } +} + +module.exports = { makeChecks } diff --git a/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/index.js b/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/index.js new file mode 100644 index 000000000..d39d3627e --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/index.js @@ -0,0 +1,15 @@ +// census: use_global, use_scoped, mw_factory_returning_fn, require_hono (violation hono-7-04; CommonJS) +// m.auth and m.audit are the two functions in checks.js, each on its own scope. Control: a cross-assignment +// would put audit on /admin/* only or auth on every route. +const { Hono } = require('hono') +const { makeChecks } = require('./checks') + +const m = makeChecks('ops') + +const app = new Hono() +app.use('/admin/*', m.auth) +app.use('*', m.audit) +app.get('/ping', (c) => c.text('pong')) +app.get('/admin/users', (c) => c.json([])) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/package.json b/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-factory-object-mw/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-negative/src/index.js b/graph/test/javascript/hono/cases/js/cjs-negative/src/index.js new file mode 100644 index 000000000..2b42b09a4 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-negative/src/index.js @@ -0,0 +1,19 @@ +// census: none for CommonJS (corpus gap); CJS twin of js/negative-js +const { Hono } = require('hono') + +const cache = new Map() +cache.set('/x', () => 'cached') +cache.get('/x') + +const router = { + get(path, fn) { return fn }, + use(fn) { return fn }, + route(path, other) { return other }, +} +router.get('/not-hono', () => 'nope') +router.use(() => {}) + +const app = new Hono() +app.get('/real', (c) => c.text('real')) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-negative/src/package.json b/graph/test/javascript/hono/cases/js/cjs-negative/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-negative/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/index.js b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/index.js new file mode 100644 index 000000000..c781b43da --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/index.js @@ -0,0 +1,13 @@ +// census: route_mount_literal, prop_receiver_route, require_hono (violation hono-7-01, P1 false_route; CommonJS) +// Sub-apps read as `rt.p` from the object a function returns. Control: distinct paths and handlers per sub-app, +// so a read that took the other property's value shows a route at the wrong prefix. +const { Hono } = require('hono') +const { createRuntime } = require('./runtime') + +const rt = createRuntime('eu') + +const app = new Hono() +app.route('/stock', rt.stockRoutes) +app.route('/orders', rt.orderRoutes) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/package.json b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/routes/orders.js b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/routes/orders.js new file mode 100644 index 000000000..9bbd1aa4f --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/routes/orders.js @@ -0,0 +1,10 @@ +const { Hono } = require('hono') + +function buildOrderRoutes(label) { + const orders = new Hono() + orders.get('/recent', (c) => c.text(label())) + orders.put('/:orderId', (c) => c.text('saved')) + return orders +} + +module.exports = { buildOrderRoutes } diff --git a/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/routes/stock.js b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/routes/stock.js new file mode 100644 index 000000000..2e45afa00 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/routes/stock.js @@ -0,0 +1,10 @@ +const { Hono } = require('hono') + +function buildStockRoutes(label) { + const stock = new Hono() + stock.get('/', (c) => c.text(label())) + stock.delete('/:sku', (c) => c.text('removed')) + return stock +} + +module.exports = { buildStockRoutes } diff --git a/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/runtime.js b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/runtime.js new file mode 100644 index 000000000..e3f14a625 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-returned-object-member/src/runtime.js @@ -0,0 +1,10 @@ +const { buildStockRoutes } = require('./routes/stock') +const { buildOrderRoutes } = require('./routes/orders') + +// One object literal of sub-apps, shorthand and written-out properties: each read takes only its own property. +function createRuntime(region) { + const stockRoutes = buildStockRoutes(() => region) + return { region, stockRoutes, orderRoutes: buildOrderRoutes(() => region) } +} + +module.exports = { createRuntime } diff --git a/graph/test/javascript/hono/cases/js/cjs-routes-mount/src/index.cjs b/graph/test/javascript/hono/cases/js/cjs-routes-mount/src/index.cjs new file mode 100644 index 000000000..4e2e435e7 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-routes-mount/src/index.cjs @@ -0,0 +1,16 @@ +// census: none for CommonJS (corpus gap: no CJS Hono app in the corpus); CJS twin of js/esm-basic +// The same routes, middleware and mount written with require / module.exports in .cjs files. +const { Hono } = require('hono') +const users = require('./users.cjs') + +const audit = async (c, next) => { + await next() +} + +const app = new Hono() +app.use(audit) +app.get('/', (c) => c.text('home')) +app.route('/users', users) +app.get('/items/:id', audit, (c) => c.text(c.req.param('id'))) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-routes-mount/src/users.cjs b/graph/test/javascript/hono/cases/js/cjs-routes-mount/src/users.cjs new file mode 100644 index 000000000..dd0c60c98 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-routes-mount/src/users.cjs @@ -0,0 +1,7 @@ +const { Hono } = require('hono') + +const users = new Hono() +users.get('/', (c) => c.json([])) +users.post('/', (c) => c.json({}, 201)) + +module.exports = users diff --git a/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/package.json b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/package.json new file mode 100644 index 000000000..729ac4d93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/routes/container.js b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/routes/container.js new file mode 100644 index 000000000..02c7d531d --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/routes/container.js @@ -0,0 +1,14 @@ +const { Hono } = require('hono') +const { upgradeWebSocket } = require('../utils/websocket') + +const app = new Hono() + +app.get('/:id', (c) => c.json({ id: c.req.param('id') })) + +app.get('/:id/logs/stream', upgradeWebSocket(async (c) => ({ + onOpen(_evt, ws) { + ws.send(c.req.param('id')) + }, +}))) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/server.js b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/server.js new file mode 100644 index 000000000..3e0169db6 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/server.js @@ -0,0 +1,10 @@ +// census: cjs_require_hono_destructure (oracle gap O10 residual, CommonJS) +// upgradeWebSocket comes from a PROJECT CommonJS module that destructures createBunWebSocket() and re-exports it in +// module.exports: the route's handler is the library call, keyed at the call. +const { Hono } = require('hono') +const containerRoutes = require('./routes/container') + +const app = new Hono() +app.route('/api/containers', containerRoutes) + +module.exports = app diff --git a/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/utils/websocket.js b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/utils/websocket.js new file mode 100644 index 000000000..e90f99d1e --- /dev/null +++ b/graph/test/javascript/hono/cases/js/cjs-websocket-module/src/utils/websocket.js @@ -0,0 +1,5 @@ +const { createBunWebSocket } = require('hono/bun') + +const { upgradeWebSocket, websocket } = createBunWebSocket() + +module.exports = { upgradeWebSocket, websocket } diff --git a/graph/test/javascript/hono/cases/js/create-middleware-factory/src/app.js b/graph/test/javascript/hono/cases/js/create-middleware-factory/src/app.js new file mode 100644 index 000000000..5e1507c57 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/create-middleware-factory/src/app.js @@ -0,0 +1,11 @@ +// census: create_middleware, mw_factory_returning_fn, ctx_set, ctx_get (violation hono-1-07, JavaScript) +// In JavaScript as in TypeScript the middleware is the function passed to createMiddleware inside the project +// factory: it is the http entry, it is on the chain, and its c.set reaches the handler's c.get. +import { Hono } from 'hono' +import { sessionMiddleware } from './session.js' + +const app = new Hono() +app.use(sessionMiddleware('k')) +app.get('/me', (c) => c.json(c.get('session'))) + +export default app diff --git a/graph/test/javascript/hono/cases/js/create-middleware-factory/src/package.json b/graph/test/javascript/hono/cases/js/create-middleware-factory/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/create-middleware-factory/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/create-middleware-factory/src/session.js b/graph/test/javascript/hono/cases/js/create-middleware-factory/src/session.js new file mode 100644 index 000000000..dd7383332 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/create-middleware-factory/src/session.js @@ -0,0 +1,8 @@ +import { createMiddleware } from 'hono/factory' + +export function sessionMiddleware(secret) { + return createMiddleware(async (c, next) => { + c.set('session', { secret }) + await next() + }) +} diff --git a/graph/test/javascript/hono/cases/js/esm-basic/src/index.js b/graph/test/javascript/hono/cases/js/esm-basic/src/index.js new file mode 100644 index 000000000..2f30f844d --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-basic/src/index.js @@ -0,0 +1,16 @@ +// census: import_hono_named, route_mount_literal, use_global, export_default_app (ESM JavaScript) +// The TypeScript routing and composition shapes, written in ESM .js and .mjs with no types at all. +import { Hono } from 'hono' +import users from './users.mjs' + +const audit = async (c, next) => { + await next() +} + +const app = new Hono() +app.use(audit) +app.get('/', (c) => c.text('home')) +app.route('/users', users) +app.get('/items/:id', audit, (c) => c.text(c.req.param('id'))) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-basic/src/package.json b/graph/test/javascript/hono/cases/js/esm-basic/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-basic/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/esm-basic/src/users.mjs b/graph/test/javascript/hono/cases/js/esm-basic/src/users.mjs new file mode 100644 index 000000000..8e7b49f8f --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-basic/src/users.mjs @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const users = new Hono() +users.get('/', (c) => c.json([])) +users.post('/', (c) => c.json({}, 201)) + +export default users diff --git a/graph/test/javascript/hono/cases/js/esm-context-closure-access/src/index.js b/graph/test/javascript/hono/cases/js/esm-context-closure-access/src/index.js new file mode 100644 index 000000000..dec047197 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-context-closure-access/src/index.js @@ -0,0 +1,19 @@ +// census: ctx_set_in_callback, ctx_get_in_callback +// A middleware writes a key, and a handler reads one, inside callbacks nested in them: the callbacks +// run during the request with the outer function's context, so the key still flows. +import { Hono } from 'hono' + +const app = new Hono() + +app.use(async (c, next) => { + await Promise.all([1].map(async () => c.set('user', 'u1'))) + c.set('role', 'admin') + await next() +}) +app.get('/', async (c) => { + const user = await Promise.resolve().then(() => c.get('user')) + const role = [0].map(() => c.var.role)[0] + return c.json({ user, role }) +}) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-context-destructure-after-next/src/index.js b/graph/test/javascript/hono/cases/js/esm-context-destructure-after-next/src/index.js new file mode 100644 index 000000000..b7917b867 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-context-destructure-after-next/src/index.js @@ -0,0 +1,18 @@ +// census: ctx_set, ctx_get_destructured, ctx_set_after_next +// Untyped JavaScript: a middleware sets a key before handing on and another after the chain has +// returned; the handler reads the first by destructuring and asks for the second by name. +import { Hono } from 'hono' + +const app = new Hono() + +app.use(async (c, next) => { + c.set('user', { id: 7 }) + await next() + c.set('done', true) +}) +app.get('/me', (c) => { + const { user } = c.var + return c.json({ id: user.id, done: c.get('done') }) +}) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-context-early-return-next/src/index.js b/graph/test/javascript/hono/cases/js/esm-context-early-return-next/src/index.js new file mode 100644 index 000000000..8b3b145a5 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-context-early-return-next/src/index.js @@ -0,0 +1,23 @@ +// census: ctx_set, ctx_get, ctx_next_in_branch +// A middleware that hands on early for some requests (`if (..) return next()`) and sets a key +// on the others: the set is before the `next()` that runs on its path, so the handler reads it. +import { Hono } from 'hono' + +const app = new Hono() + +app.use(async (c, next) => { + if (c.req.path === '/health') return next() + c.set('user', 'u1') + await next() +}) +app.use(async (c, next) => { + if (c.req.header('x-skip')) { + await next() + return + } + c.set('role', 'admin') + await next() +}) +app.get('/', (c) => c.json({ user: c.get('user'), role: c.var.role })) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-context/src/index.js b/graph/test/javascript/hono/cases/js/esm-context/src/index.js new file mode 100644 index 000000000..e638933e2 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-context/src/index.js @@ -0,0 +1,16 @@ +// census: ctx_set, ctx_get, ctx_var, create_middleware (ESM JavaScript) +import { Hono } from 'hono' +import { createMiddleware } from 'hono/factory' + +const withUser = createMiddleware(async (c, next) => { + c.set('user', { id: 'u1' }) + await next() +}) + +const app = new Hono() +app.use('/me/*', withUser) +app.get('/me/profile', (c) => c.json(c.get('user'))) +app.get('/me/id', (c) => c.text(c.var.user.id)) +app.get('/public', (c) => c.text(String(c.get('user')))) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-context/src/package.json b/graph/test/javascript/hono/cases/js/esm-context/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-context/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/index.js b/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/index.js new file mode 100644 index 000000000..6147af0aa --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/index.js @@ -0,0 +1,17 @@ +// census: create_route, openapi_register, new_openapihono (violation hono-7-03; ESM JavaScript) +// A route built through a project wrapper around createRoute is a route (or partial/unknown with a reason), never +// dropped. Control: listRoute comes from createRoute directly. +import { OpenAPIHono, createRoute } from '@hono/zod-openapi' +import { scopedRoute } from './openapi.js' + +const listRoute = createRoute({ method: 'get', path: '/', responses: { 200: { description: 'ok' } } }) +const removeRoute = scopedRoute('items:delete', { method: 'delete', path: '/{id}', responses: { 204: { description: 'gone' } } }) + +const items = new OpenAPIHono() +items.openapi(listRoute, (c) => c.json([], 200)) +items.openapi(removeRoute, (c) => c.body(null, 204)) + +const app = new OpenAPIHono() +app.route('/api/items', items) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/openapi.js b/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/openapi.js new file mode 100644 index 000000000..534166670 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/openapi.js @@ -0,0 +1,13 @@ +import { createRoute } from '@hono/zod-openapi' + +export function authorize(scope) { + return async (c, next) => { + if (!scope) return c.text('no', 403) + await next() + } +} + +// A project wrapper around createRoute that adds a scope check to the route's middleware. +export function scopedRoute(scope, config) { + return createRoute({ ...config, middleware: [authorize(scope)] }) +} diff --git a/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/package.json b/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-create-route-wrapper/src/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/api.js b/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/api.js new file mode 100644 index 000000000..334435f28 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/api.js @@ -0,0 +1,10 @@ +// census: request_fetch (violation hono-5-09, SPEC R14 / R14a in JavaScript) +// Requests whose base the program does not spell join on the composed full path as base_unknown; a single-label +// host joins as base_unknown; a dotted external host never joins. +import { Hono } from 'hono' + +const app = new Hono().basePath('/api') +app.post('/sessions', (c) => c.json({ ok: true }, 201)) +app.get('/sessions/:id', (c) => c.json({ id: c.req.param('id') })) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/client.js b/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/client.js new file mode 100644 index 000000000..3d2849a78 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/client.js @@ -0,0 +1,15 @@ +export async function open(host) { + return fetch(`${host}/api/sessions`, { method: 'POST' }) +} + +export async function read(base, id) { + return fetch(new URL(`/api/sessions/${id}`, base)) +} + +export async function viaService() { + return fetch('http://sessions:8080/api/sessions/1') +} + +export async function upstream() { + return fetch('https://example.org/api/sessions') +} diff --git a/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/package.json b/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-fetch-unknown-base/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/esm-hc-client/src/client.js b/graph/test/javascript/hono/cases/js/esm-hc-client/src/client.js new file mode 100644 index 000000000..7b2ca1463 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-hc-client/src/client.js @@ -0,0 +1,12 @@ +// census: hc_client, hc_dollar_call, hc_element_param (JavaScript: no type argument, SPEC 3.5 route_shape) +// A JS hc client has no AppType: it is matched by path against every served app in the JS graph. +import { hc } from 'hono/client' + +const client = hc('http://localhost:8787') + +export async function listTasks() { + return client.tasks.$get() +} +export async function finishTask(id) { + return client.tasks[':id'].done.$post({ param: { id } }) +} diff --git a/graph/test/javascript/hono/cases/js/esm-hc-client/src/package.json b/graph/test/javascript/hono/cases/js/esm-hc-client/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-hc-client/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/esm-hc-client/src/server.js b/graph/test/javascript/hono/cases/js/esm-hc-client/src/server.js new file mode 100644 index 000000000..ab8ccc782 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-hc-client/src/server.js @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const app = new Hono() +app.get('/tasks', (c) => c.json([])) +app.post('/tasks/:id/done', (c) => c.json({ id: c.req.param('id') })) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/auth.js b/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/auth.js new file mode 100644 index 000000000..1fa2918fe --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/auth.js @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +const authRoutes = new Hono() +authRoutes.get('/login', (c) => c.text('form')) +authRoutes.post('/login', (c) => c.json({ ok: true })) +authRoutes.post('/login/form', (c) => c.text('ok')) + +export default authRoutes diff --git a/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/package.json b/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/test/auth.test.js b/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/test/auth.test.js new file mode 100644 index 000000000..5a57ae199 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-helper-request-method/src/test/auth.test.js @@ -0,0 +1,24 @@ +// census: app_request_test (violation hono-7-02; ESM JavaScript) +// `post` sends with `method: 'POST'`: each call joins the POST route on its path, never GET. Control: `get` +// passes no init, so its call joins GET on the same path. +import { Hono } from 'hono' +import authRoutes from '../auth.js' + +async function post(path, body) { + const app = new Hono() + app.route('/auth', authRoutes) + const headers = { 'Content-Type': 'application/json' } + return app.request(path, { method: 'POST', headers, body: JSON.stringify(body) }) +} + +async function get(path) { + const app = new Hono() + app.route('/auth', authRoutes) + return app.request(path) +} + +it('logs in and reads the form', async () => { + await post('/auth/login', { user: 'a' }) + await post('/auth/login/form', { user: 'a' }) + await get('/auth/login') +}) diff --git a/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/index.js b/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/index.js new file mode 100644 index 000000000..29d4de692 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/index.js @@ -0,0 +1,19 @@ +// census: create_route, openapi_register, new_openapihono (ESM JavaScript; found with violation hono-7-03: the +// JavaScript engine registers no `.openapi(route, handler)` route at all) +// The TypeScript openapi/create-route shape without types: route objects from another module, {id} registers as +// :id, the third argument is a validation hook, not the handler. +import { OpenAPIHono } from '@hono/zod-openapi' +import { listNotes, getNote } from './routes.js' + +const app = new OpenAPIHono() + +app.openapi(listNotes, (c) => c.json([], 200)) +app.openapi( + getNote, + (c) => c.json({ id: c.req.param('id') }, 200), + (result, c) => { + if (!result.success) return c.text('bad', 400) + } +) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/package.json b/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/routes.js b/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/routes.js new file mode 100644 index 000000000..840eaa44b --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-openapi-create-route/src/routes.js @@ -0,0 +1,4 @@ +import { createRoute } from '@hono/zod-openapi' + +export const listNotes = createRoute({ method: 'get', path: '/notes', responses: { 200: { description: 'notes' } } }) +export const getNote = createRoute({ method: 'get', path: '/notes/{id}', responses: { 200: { description: 'note' } } }) diff --git a/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/index.js b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/index.js new file mode 100644 index 000000000..f2573a95d --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/index.js @@ -0,0 +1,13 @@ +// census: route_mount_literal, app_factory_fn (violation hono-7-01, P1 false_route; ESM JavaScript) +// Sub-apps destructured from the object a function returns. Control: distinct paths and handlers per sub-app, +// so a name that took the other property's value shows a route at the wrong prefix. +import { Hono } from 'hono' +import { createRuntime } from './runtime.js' + +const { stockRoutes, orderRoutes } = createRuntime('eu') + +const app = new Hono() +app.route('/stock', stockRoutes) +app.route('/orders', orderRoutes) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/package.json b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/routes/orders.js b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/routes/orders.js new file mode 100644 index 000000000..ae6f9d4c1 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/routes/orders.js @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function buildOrderRoutes(label) { + const orders = new Hono() + orders.get('/recent', (c) => c.text(label())) + orders.put('/:orderId', (c) => c.text('saved')) + return orders +} diff --git a/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/routes/stock.js b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/routes/stock.js new file mode 100644 index 000000000..755f1acbe --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/routes/stock.js @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function buildStockRoutes(label) { + const stock = new Hono() + stock.get('/', (c) => c.text(label())) + stock.delete('/:sku', (c) => c.text('removed')) + return stock +} diff --git a/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/runtime.js b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/runtime.js new file mode 100644 index 000000000..3e505ff93 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-returned-object-destructure/src/runtime.js @@ -0,0 +1,8 @@ +import { buildStockRoutes } from './routes/stock.js' +import { buildOrderRoutes } from './routes/orders.js' + +// One object literal of sub-apps, shorthand and written-out properties: each read takes only its own property. +export function createRuntime(region) { + const stockRoutes = buildStockRoutes(() => region) + return { region, stockRoutes, orderRoutes: buildOrderRoutes(() => region) } +} diff --git a/graph/test/javascript/hono/cases/js/esm-twin-of-cjs-basic/src/index.mjs b/graph/test/javascript/hono/cases/js/esm-twin-of-cjs-basic/src/index.mjs new file mode 100644 index 000000000..1343bd660 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-twin-of-cjs-basic/src/index.mjs @@ -0,0 +1,11 @@ +// census: new_hono, route_mount_literal, builtin_mw_import; ESM .mjs twin of js/cjs-basic +import { Hono } from 'hono' +import { cors } from 'hono/cors' +import users from './users.mjs' + +const app = new Hono() +app.use('/api/*', cors()) +app.route('/api/users', users) +app.get('/health', (c) => c.text('ok')) + +export default app diff --git a/graph/test/javascript/hono/cases/js/esm-twin-of-cjs-basic/src/users.mjs b/graph/test/javascript/hono/cases/js/esm-twin-of-cjs-basic/src/users.mjs new file mode 100644 index 000000000..85476052b --- /dev/null +++ b/graph/test/javascript/hono/cases/js/esm-twin-of-cjs-basic/src/users.mjs @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const users = new Hono() +users.get('/:id', (c) => c.json({ id: c.req.param('id') })) + +export default users diff --git a/graph/test/javascript/hono/cases/js/negative-js/src/index.js b/graph/test/javascript/hono/cases/js/negative-js/src/index.js new file mode 100644 index 000000000..d698dc135 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/negative-js/src/index.js @@ -0,0 +1,20 @@ +// census: neg_map_get_in_hono_file, neg_route_on_nonhono (JavaScript) +// A Map, a cache object, and a router-shaped object beside one real app: only the app's route. +import { Hono } from 'hono' + +const cache = new Map() +cache.set('/x', () => 'cached') +cache.get('/x') + +const router = { + get(path, fn) { return fn }, + use(fn) { return fn }, + route(path, other) { return other }, +} +router.get('/not-hono', () => 'nope') +router.use(() => {}) + +const app = new Hono() +app.get('/real', (c) => c.text('real')) + +export default app diff --git a/graph/test/javascript/hono/cases/js/negative-js/src/package.json b/graph/test/javascript/hono/cases/js/negative-js/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/negative-js/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/cases/js/unresolved-lib-mw/src/index.js b/graph/test/javascript/hono/cases/js/unresolved-lib-mw/src/index.js new file mode 100644 index 000000000..c08ee1d29 --- /dev/null +++ b/graph/test/javascript/hono/cases/js/unresolved-lib-mw/src/index.js @@ -0,0 +1,15 @@ +// census: builtin_mw_import (oracle gap O6: a library middleware whose package cannot be resolved) +// It is still a middleware node at its registering call, ahead of the project middleware, in its place. +import { Hono } from 'hono' +import { authSdk } from 'acme-auth-sdk' + +const tag = async (c, next) => { + await next() +} + +const app = new Hono() +app.use(authSdk.middleware({ project: 'p' })) +app.use(tag) +app.get('/secure', (c) => c.text('secure')) + +export default app diff --git a/graph/test/javascript/hono/cases/js/unresolved-lib-mw/src/package.json b/graph/test/javascript/hono/cases/js/unresolved-lib-mw/src/package.json new file mode 100644 index 000000000..089153bcb --- /dev/null +++ b/graph/test/javascript/hono/cases/js/unresolved-lib-mw/src/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/graph/test/javascript/hono/expected/chains/esm-services-chain.chains b/graph/test/javascript/hono/expected/chains/esm-services-chain.chains new file mode 100644 index 000000000..ca94beeb8 --- /dev/null +++ b/graph/test/javascript/hono/expected/chains/esm-services-chain.chains @@ -0,0 +1,23 @@ +# hand-reviewed 2026-10-28 against the fixture, the compiler call-chain oracle and the runtime trace: the JavaScript twin of the R18 chains: the compiler types c.get(k) / c.var.k as any and the repository db as any, so handler -> service and repository -> db are run-time edges (rt); service -> repository resolves statically through the field the constructor builds +# census: ctx_di (SPEC R18, the JavaScript form; call-chain break class 1) +fn index.js:14:24 +fn index.js:20:30 +fn index.js:5:34 +fn services.js:10:3 +fn services.js:16:3 +fn services.js:19:3 +fn services.js:22:3 +fn services.js:28:3 +fn services.js:31:3 +fn services.js:34:3 +fn services.js:7:3 +edge index.js:5:34 services.js:28:3 +edge services.js:28:3 services.js:16:3 +edge services.js:31:3 services.js:19:3 +edge services.js:34:3 services.js:22:3 +edge index.js:14:24 services.js:31:3 rt +edge index.js:20:30 services.js:34:3 rt +edge services.js:19:3 services.js:7:3 rt +edge services.js:22:3 services.js:10:3 rt +chain order-find GET /orders/x1 index.js:5:34 index.js:14:24 services.js:31:3 services.js:19:3 services.js:7:3 +chain order-total GET /orders/x1/total index.js:5:34 index.js:20:30 services.js:34:3 services.js:22:3 services.js:10:3 diff --git a/graph/test/javascript/hono/expected/chains/esm-services-chain.entries b/graph/test/javascript/hono/expected/chains/esm-services-chain.entries new file mode 100644 index 000000000..a0efade66 --- /dev/null +++ b/graph/test/javascript/hono/expected/chains/esm-services-chain.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: chains fixture, ESM JavaScript (createMiddleware provider, c.get destructured, c.var two members deep): routes, middleware chains, ctx flows +# census: ctx_di (SPEC R18, the JavaScript form; call-chain break class 1) +entry index.js:14:24 http +entry index.js:20:30 http +entry index.js:5:34 http diff --git a/graph/test/javascript/hono/expected/chains/esm-services-chain.tsv b/graph/test/javascript/hono/expected/chains/esm-services-chain.tsv new file mode 100644 index 000000000..0d27a7130 --- /dev/null +++ b/graph/test/javascript/hono/expected/chains/esm-services-chain.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: chains fixture, ESM JavaScript (createMiddleware provider, c.get destructured, c.var two members deep): routes, middleware chains, ctx flows +# census: ctx_di (SPEC R18, the JavaScript form; call-chain break class 1) +route GET /orders/:id index.js:14:24 index.js:10:13 1 +route GET /orders/:id/total index.js:20:30 index.js:10:13 2 +mw index.js:5:34 index.js:14:24 GET /orders/:id 0 index.js:10:13 +mw index.js:5:34 index.js:20:30 GET /orders/:id/total 0 index.js:10:13 +ctx index.js:5:34 index.js:14:24 services +ctx index.js:5:34 index.js:20:30 services +regby index.js:1:1 index.js:14:24 GET /orders/:id index.js:10:13 +regby index.js:1:1 index.js:20:30 GET /orders/:id/total index.js:10:13 diff --git a/graph/test/javascript/hono/expected/js/bun-websocket-destructure.entries b/graph/test/javascript/hono/expected/js/bun-websocket-destructure.entries new file mode 100644 index 000000000..9ff240ceb --- /dev/null +++ b/graph/test/javascript/hono/expected/js/bun-websocket-destructure.entries @@ -0,0 +1,2 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O10: upgradeWebSocket destructured from createBunWebSocket() is a library-call handler +# census: none (oracle gap O10, JavaScript): a library function taken by destructuring a library call's result diff --git a/graph/test/javascript/hono/expected/js/bun-websocket-destructure.tsv b/graph/test/javascript/hono/expected/js/bun-websocket-destructure.tsv new file mode 100644 index 000000000..f792ad75b --- /dev/null +++ b/graph/test/javascript/hono/expected/js/bun-websocket-destructure.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O10: upgradeWebSocket destructured from createBunWebSocket() is a library-call handler +# census: none (oracle gap O10, JavaScript): a library function taken by destructuring a library call's result +route GET /ws lib:hono/bun.createBunWebSocket().upgradeWebSocket@index.js:8:16 index.js:7:13 0 +regby index.js:1:1 lib:hono/bun.createBunWebSocket().upgradeWebSocket@index.js:8:16 GET /ws index.js:7:13 diff --git a/graph/test/javascript/hono/expected/js/cjs-basic.entries b/graph/test/javascript/hono/expected/js/cjs-basic.entries new file mode 100644 index 000000000..0fcaf5146 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-basic.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: require-destructured Hono and cors; sub-app from module.exports mounted at /api/users; cors reaches it, not /health +# census: new_hono, route_mount_literal, builtin_mw_import (CommonJS JavaScript; SPEC 10 C2: no CJS project +entry index.js:11:20 http +entry users.js:4:19 http diff --git a/graph/test/javascript/hono/expected/js/cjs-basic.tsv b/graph/test/javascript/hono/expected/js/cjs-basic.tsv new file mode 100644 index 000000000..3e297197d --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-basic.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: require-destructured Hono and cors; sub-app from module.exports mounted at /api/users; cors reaches it, not /health +# census: new_hono, route_mount_literal, builtin_mw_import (CommonJS JavaScript; SPEC 10 C2: no CJS project +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/users/:id users.js:4:19 index.js:8:13 1 +route GET /health index.js:11:20 index.js:8:13 2 +mw lib:hono/cors.cors@index.js:9:19 users.js:4:19 GET /api/users/:id 0 index.js:8:13 +submount /api/users index.js:10:5 +regby index.js:1:1 index.js:11:20 GET /health index.js:8:13 +regby users.js:1:1 users.js:4:19 GET /api/users/:id index.js:8:13 diff --git a/graph/test/javascript/hono/expected/js/cjs-context.entries b/graph/test/javascript/hono/expected/js/cjs-context.entries new file mode 100644 index 000000000..a462075c8 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-context.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: CJS twin of esm-context: user flows to both /me routes; /public has no setter +# census: none for CommonJS (corpus gap); CJS twin of js/esm-context +entry index.js:12:24 http +entry index.js:13:19 http +entry index.js:14:20 http +entry index.js:5:35 http diff --git a/graph/test/javascript/hono/expected/js/cjs-context.tsv b/graph/test/javascript/hono/expected/js/cjs-context.tsv new file mode 100644 index 000000000..b7993f148 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-context.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: CJS twin of esm-context: user flows to both /me routes; /public has no setter +# census: none for CommonJS (corpus gap); CJS twin of js/esm-context +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /me/profile index.js:12:24 index.js:10:13 1 +route GET /me/id index.js:13:19 index.js:10:13 2 +route GET /public index.js:14:20 index.js:10:13 3 +mw index.js:5:35 index.js:12:24 GET /me/profile 0 index.js:10:13 +mw index.js:5:35 index.js:13:19 GET /me/id 0 index.js:10:13 +ctx index.js:5:35 index.js:12:24 user +ctx index.js:5:35 index.js:13:19 user +regby index.js:1:1 index.js:12:24 GET /me/profile index.js:10:13 +regby index.js:1:1 index.js:13:19 GET /me/id index.js:10:13 +regby index.js:1:1 index.js:14:20 GET /public index.js:10:13 +unknown index.js:14:20 no_setter_on_chain index.js:14:20 diff --git a/graph/test/javascript/hono/expected/js/cjs-exports-members.entries b/graph/test/javascript/hono/expected/js/cjs-exports-members.entries new file mode 100644 index 000000000..1acc3a28e --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-exports-members.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O7: module.exports members through destructured require: authenticate (sets user) and isAdmin on the chain after the unresolvable limiter; user flows to /api/me +# census: none for CommonJS (corpus gap in census; shape of a CJS-on-Bun project): oracle gap O7 +entry app.js:11:20 http +entry app.js:12:39 http +entry auth.js:1:31 http +entry auth.js:5:26 http diff --git a/graph/test/javascript/hono/expected/js/cjs-exports-members.tsv b/graph/test/javascript/hono/expected/js/cjs-exports-members.tsv new file mode 100644 index 000000000..c63c2b3a8 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-exports-members.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O7: module.exports members through destructured require: authenticate (sets user) and isAdmin on the chain after the unresolvable limiter; user flows to /api/me +# census: none for CommonJS (corpus gap in census; shape of a CJS-on-Bun project): oracle gap O7 +route GET /api/me app.js:11:20 app.js:8:13 2 +route DELETE /api/users/:id app.js:12:39 app.js:8:13 4 +mw lib:acme-rate-limit.limiter@app.js:9:19 app.js:11:20 GET /api/me 0 app.js:8:13 +mw auth.js:1:31 app.js:11:20 GET /api/me 1 app.js:8:13 +mw lib:acme-rate-limit.limiter@app.js:9:19 app.js:12:39 DELETE /api/users/:id 0 app.js:8:13 +mw auth.js:1:31 app.js:12:39 DELETE /api/users/:id 1 app.js:8:13 +mw auth.js:5:26 app.js:12:39 DELETE /api/users/:id 2 app.js:8:13 +ctx auth.js:1:31 app.js:11:20 user +regby app.js:1:1 app.js:11:20 GET /api/me app.js:8:13 +regby app.js:1:1 app.js:12:39 DELETE /api/users/:id app.js:8:13 diff --git a/graph/test/javascript/hono/expected/js/cjs-factory-object-mw.entries b/graph/test/javascript/hono/expected/js/cjs-factory-object-mw.entries new file mode 100644 index 000000000..9b9778ea6 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-factory-object-mw.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-04 (CommonJS): m.auth checks.js:3 on /admin/* only, m.audit checks.js:9 on every route +# census: use_global, use_scoped, mw_factory_returning_fn, require_hono (violation hono-7-04; CommonJS) +entry checks.js:3:16 http +entry checks.js:9:12 http +entry index.js:12:18 http +entry index.js:13:25 http diff --git a/graph/test/javascript/hono/expected/js/cjs-factory-object-mw.tsv b/graph/test/javascript/hono/expected/js/cjs-factory-object-mw.tsv new file mode 100644 index 000000000..ca212801e --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-factory-object-mw.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-04 (CommonJS): m.auth checks.js:3 on /admin/* only, m.audit checks.js:9 on every route +# census: use_global, use_scoped, mw_factory_returning_fn, require_hono (violation hono-7-04; CommonJS) +route GET /ping index.js:12:18 index.js:9:13 2 +route GET /admin/users index.js:13:25 index.js:9:13 3 +mw checks.js:9:12 index.js:12:18 GET /ping 0 index.js:9:13 +mw checks.js:3:16 index.js:13:25 GET /admin/users 0 index.js:9:13 +mw checks.js:9:12 index.js:13:25 GET /admin/users 1 index.js:9:13 +regby index.js:1:1 index.js:12:18 GET /ping index.js:9:13 +regby index.js:1:1 index.js:13:25 GET /admin/users index.js:9:13 diff --git a/graph/test/javascript/hono/expected/js/cjs-negative.entries b/graph/test/javascript/hono/expected/js/cjs-negative.entries new file mode 100644 index 000000000..dc0deacbe --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-negative.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: CJS twin of negative-js: only /real; Map and router callbacks absent +# census: none for CommonJS (corpus gap); CJS twin of js/negative-js +entry index.js:17:18 http diff --git a/graph/test/javascript/hono/expected/js/cjs-negative.tsv b/graph/test/javascript/hono/expected/js/cjs-negative.tsv new file mode 100644 index 000000000..8b0af86ac --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-negative.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: CJS twin of negative-js: only /real; Map and router callbacks absent +# census: none for CommonJS (corpus gap); CJS twin of js/negative-js +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /real index.js:17:18 index.js:16:13 0 +regby index.js:1:1 index.js:17:18 GET /real index.js:16:13 +absent index.js:5:17 +absent index.js:13:25 +absent index.js:14:12 +absent index.js:9:3 +absent index.js:10:3 diff --git a/graph/test/javascript/hono/expected/js/cjs-returned-object-member.entries b/graph/test/javascript/hono/expected/js/cjs-returned-object-member.entries new file mode 100644 index 000000000..34b56d90d --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-returned-object-member.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01 (CommonJS): each rt.p read takes only its own property: stock and orders with their own handlers +# census: route_mount_literal, prop_receiver_route, require_hono (violation hono-7-01, P1 false_route; CommonJS) +entry routes/orders.js:5:25 http +entry routes/orders.js:6:27 http +entry routes/stock.js:5:18 http +entry routes/stock.js:6:25 http diff --git a/graph/test/javascript/hono/expected/js/cjs-returned-object-member.tsv b/graph/test/javascript/hono/expected/js/cjs-returned-object-member.tsv new file mode 100644 index 000000000..fe8f83271 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-returned-object-member.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01 (CommonJS): each rt.p read takes only its own property: stock and orders with their own handlers +# census: route_mount_literal, prop_receiver_route, require_hono (violation hono-7-01, P1 false_route; CommonJS) +route GET /stock routes/stock.js:5:18 index.js:9:13 0 +route DELETE /stock/:sku routes/stock.js:6:25 index.js:9:13 1 +route GET /orders/recent routes/orders.js:5:25 index.js:9:13 2 +route PUT /orders/:orderId routes/orders.js:6:27 index.js:9:13 3 +submount /stock index.js:10:5 +submount /orders index.js:11:5 +regby routes/orders.js:3:1 routes/orders.js:5:25 GET /orders/recent index.js:9:13 +regby routes/orders.js:3:1 routes/orders.js:6:27 PUT /orders/:orderId index.js:9:13 +regby routes/stock.js:3:1 routes/stock.js:5:18 GET /stock index.js:9:13 +regby routes/stock.js:3:1 routes/stock.js:6:25 DELETE /stock/:sku index.js:9:13 diff --git a/graph/test/javascript/hono/expected/js/cjs-routes-mount.entries b/graph/test/javascript/hono/expected/js/cjs-routes-mount.entries new file mode 100644 index 000000000..e14e2dc57 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-routes-mount.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: CJS twin of esm-basic: identical rows in .cjs files +# census: none for CommonJS (corpus gap: no CJS Hono app in the corpus); CJS twin of js/esm-basic +entry index.cjs:12:14 http +entry index.cjs:14:30 http +entry index.cjs:6:15 http +entry users.cjs:4:16 http +entry users.cjs:5:17 http diff --git a/graph/test/javascript/hono/expected/js/cjs-routes-mount.tsv b/graph/test/javascript/hono/expected/js/cjs-routes-mount.tsv new file mode 100644 index 000000000..ae34e8f19 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-routes-mount.tsv @@ -0,0 +1,18 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: CJS twin of esm-basic: identical rows in .cjs files +# census: none for CommonJS (corpus gap: no CJS Hono app in the corpus); CJS twin of js/esm-basic +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.cjs:12:14 index.cjs:10:13 1 +route GET /users users.cjs:4:16 index.cjs:10:13 2 +route POST /users users.cjs:5:17 index.cjs:10:13 3 +route GET /items/:id index.cjs:14:30 index.cjs:10:13 5 +mw index.cjs:6:15 index.cjs:12:14 GET / 0 index.cjs:10:13 +mw index.cjs:6:15 users.cjs:4:16 GET /users 0 index.cjs:10:13 +mw index.cjs:6:15 users.cjs:5:17 POST /users 0 index.cjs:10:13 +mw index.cjs:6:15 index.cjs:14:30 GET /items/:id 0 index.cjs:10:13 +mw index.cjs:6:15 index.cjs:14:30 GET /items/:id 1 index.cjs:10:13 +submount /users index.cjs:13:5 +regby index.cjs:1:1 index.cjs:12:14 GET / index.cjs:10:13 +regby index.cjs:1:1 index.cjs:14:30 GET /items/:id index.cjs:10:13 +regby users.cjs:1:1 users.cjs:4:16 GET /users index.cjs:10:13 +regby users.cjs:1:1 users.cjs:5:17 POST /users index.cjs:10:13 diff --git a/graph/test/javascript/hono/expected/js/cjs-websocket-module.entries b/graph/test/javascript/hono/expected/js/cjs-websocket-module.entries new file mode 100644 index 000000000..2e573802a --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-websocket-module.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O10 residual (CommonJS): upgradeWebSocket from a project module's module.exports is a library-call handler keyed at the call; its callback is no entry +# census: cjs_require_hono_destructure (oracle gap O10 residual, CommonJS) +entry routes/container.js:6:17 http diff --git a/graph/test/javascript/hono/expected/js/cjs-websocket-module.tsv b/graph/test/javascript/hono/expected/js/cjs-websocket-module.tsv new file mode 100644 index 000000000..d53623465 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/cjs-websocket-module.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O10 residual (CommonJS): upgradeWebSocket from a project module's module.exports is a library-call handler keyed at the call; its callback is no entry +# census: cjs_require_hono_destructure (oracle gap O10 residual, CommonJS) +route GET /api/containers/:id routes/container.js:6:17 server.js:7:13 0 +route GET /api/containers/:id/logs/stream lib:hono/bun.createBunWebSocket().upgradeWebSocket@routes/container.js:8:29 server.js:7:13 1 +submount /api/containers server.js:8:5 +regby routes/container.js:1:1 lib:hono/bun.createBunWebSocket().upgradeWebSocket@routes/container.js:8:29 GET /api/containers/:id/logs/stream server.js:7:13 +regby routes/container.js:1:1 routes/container.js:6:17 GET /api/containers/:id server.js:7:13 diff --git a/graph/test/javascript/hono/expected/js/create-middleware-factory.entries b/graph/test/javascript/hono/expected/js/create-middleware-factory.entries new file mode 100644 index 000000000..efc96e3b2 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/create-middleware-factory.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-07: the createMiddleware arg inside the project factory is the middleware, the entry, and the session setter for /me +# census: create_middleware, mw_factory_returning_fn, ctx_set, ctx_get (violation hono-1-07, JavaScript) +entry app.js:9:16 http +entry session.js:4:27 http diff --git a/graph/test/javascript/hono/expected/js/create-middleware-factory.tsv b/graph/test/javascript/hono/expected/js/create-middleware-factory.tsv new file mode 100644 index 000000000..cb7b03e00 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/create-middleware-factory.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-07: the createMiddleware arg inside the project factory is the middleware, the entry, and the session setter for /me +# census: create_middleware, mw_factory_returning_fn, ctx_set, ctx_get (violation hono-1-07, JavaScript) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /me app.js:9:16 app.js:7:13 1 +mw session.js:4:27 app.js:9:16 GET /me 0 app.js:7:13 +ctx session.js:4:27 app.js:9:16 session +regby app.js:1:1 app.js:9:16 GET /me app.js:7:13 diff --git a/graph/test/javascript/hono/expected/js/esm-basic.entries b/graph/test/javascript/hono/expected/js/esm-basic.entries new file mode 100644 index 000000000..6a5560891 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-basic.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ESM .js/.mjs: audit app-level on every route incl. the mounted ones, and again per-route on /items/:id (positions 0 and 1) +# census: import_hono_named, route_mount_literal, use_global, export_default_app (ESM JavaScript) +entry index.js:12:14 http +entry index.js:14:30 http +entry index.js:6:15 http +entry users.mjs:4:16 http +entry users.mjs:5:17 http diff --git a/graph/test/javascript/hono/expected/js/esm-basic.tsv b/graph/test/javascript/hono/expected/js/esm-basic.tsv new file mode 100644 index 000000000..85974fe78 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-basic.tsv @@ -0,0 +1,18 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ESM .js/.mjs: audit app-level on every route incl. the mounted ones, and again per-route on /items/:id (positions 0 and 1) +# census: import_hono_named, route_mount_literal, use_global, export_default_app (ESM JavaScript) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.js:12:14 index.js:10:13 1 +route GET /users users.mjs:4:16 index.js:10:13 2 +route POST /users users.mjs:5:17 index.js:10:13 3 +route GET /items/:id index.js:14:30 index.js:10:13 5 +mw index.js:6:15 index.js:12:14 GET / 0 index.js:10:13 +mw index.js:6:15 users.mjs:4:16 GET /users 0 index.js:10:13 +mw index.js:6:15 users.mjs:5:17 POST /users 0 index.js:10:13 +mw index.js:6:15 index.js:14:30 GET /items/:id 0 index.js:10:13 +mw index.js:6:15 index.js:14:30 GET /items/:id 1 index.js:10:13 +submount /users index.js:13:5 +regby index.js:1:1 index.js:12:14 GET / index.js:10:13 +regby index.js:1:1 index.js:14:30 GET /items/:id index.js:10:13 +regby users.mjs:1:1 users.mjs:4:16 GET /users index.js:10:13 +regby users.mjs:1:1 users.mjs:5:17 POST /users index.js:10:13 diff --git a/graph/test/javascript/hono/expected/js/esm-context-closure-access.entries b/graph/test/javascript/hono/expected/js/esm-context-closure-access.entries new file mode 100644 index 000000000..39e105359 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context-closure-access.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user is set, and both keys are read, in callbacks nested in the middleware and the handler; they run during the request, so both keys reach the handler +# census: ctx_set_in_callback, ctx_get_in_callback +entry index.js:13:14 http +entry index.js:8:9 http diff --git a/graph/test/javascript/hono/expected/js/esm-context-closure-access.tsv b/graph/test/javascript/hono/expected/js/esm-context-closure-access.tsv new file mode 100644 index 000000000..66916cb82 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context-closure-access.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user is set, and both keys are read, in callbacks nested in the middleware and the handler; they run during the request, so both keys reach the handler +# census: ctx_set_in_callback, ctx_get_in_callback +route GET / index.js:13:14 index.js:6:13 1 +mw index.js:8:9 index.js:13:14 GET / 0 index.js:6:13 +ctx index.js:8:9 index.js:13:14 role +ctx index.js:8:9 index.js:13:14 user +regby index.js:1:1 index.js:13:14 GET / index.js:6:13 diff --git a/graph/test/javascript/hono/expected/js/esm-context-destructure-after-next.entries b/graph/test/javascript/hono/expected/js/esm-context-destructure-after-next.entries new file mode 100644 index 000000000..ab420b090 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context-destructure-after-next.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user flows to the handler through a destructured c.var; done is set after next() and nothing downstream reads it +# census: ctx_set, ctx_get_destructured, ctx_set_after_next +entry index.js:13:16 http +entry index.js:8:9 http diff --git a/graph/test/javascript/hono/expected/js/esm-context-destructure-after-next.tsv b/graph/test/javascript/hono/expected/js/esm-context-destructure-after-next.tsv new file mode 100644 index 000000000..d07ba613c --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context-destructure-after-next.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user flows to the handler through a destructured c.var; done is set after next() and nothing downstream reads it +# census: ctx_set, ctx_get_destructured, ctx_set_after_next +route GET /me index.js:13:16 index.js:6:13 1 +mw index.js:8:9 index.js:13:16 GET /me 0 index.js:6:13 +ctx index.js:8:9 index.js:13:16 user +regby index.js:1:1 index.js:13:16 GET /me index.js:6:13 +unknown index.js:13:16 no_setter_on_chain index.js:13:16 diff --git a/graph/test/javascript/hono/expected/js/esm-context-early-return-next.entries b/graph/test/javascript/hono/expected/js/esm-context-early-return-next.entries new file mode 100644 index 000000000..f82d4f463 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context-early-return-next.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user and role are set before the next() that runs on their path (the early next() is in a branch), so both reach the handler +# census: ctx_set, ctx_get, ctx_next_in_branch +entry index.js:13:9 http +entry index.js:21:14 http +entry index.js:8:9 http diff --git a/graph/test/javascript/hono/expected/js/esm-context-early-return-next.tsv b/graph/test/javascript/hono/expected/js/esm-context-early-return-next.tsv new file mode 100644 index 000000000..1a8c61582 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context-early-return-next.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user and role are set before the next() that runs on their path (the early next() is in a branch), so both reach the handler +# census: ctx_set, ctx_get, ctx_next_in_branch +route GET / index.js:21:14 index.js:6:13 2 +mw index.js:8:9 index.js:21:14 GET / 0 index.js:6:13 +mw index.js:13:9 index.js:21:14 GET / 1 index.js:6:13 +ctx index.js:13:9 index.js:21:14 role +ctx index.js:8:9 index.js:21:14 user +regby index.js:1:1 index.js:21:14 GET / index.js:6:13 diff --git a/graph/test/javascript/hono/expected/js/esm-context.entries b/graph/test/javascript/hono/expected/js/esm-context.entries new file mode 100644 index 000000000..1f43af757 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: user flows from withUser to both /me routes; /public outside the scope has no setter +# census: ctx_set, ctx_get, ctx_var, create_middleware (ESM JavaScript) +entry index.js:12:24 http +entry index.js:13:19 http +entry index.js:14:20 http +entry index.js:5:35 http diff --git a/graph/test/javascript/hono/expected/js/esm-context.tsv b/graph/test/javascript/hono/expected/js/esm-context.tsv new file mode 100644 index 000000000..c457099c9 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-context.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: user flows from withUser to both /me routes; /public outside the scope has no setter +# census: ctx_set, ctx_get, ctx_var, create_middleware (ESM JavaScript) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /me/profile index.js:12:24 index.js:10:13 1 +route GET /me/id index.js:13:19 index.js:10:13 2 +route GET /public index.js:14:20 index.js:10:13 3 +mw index.js:5:35 index.js:12:24 GET /me/profile 0 index.js:10:13 +mw index.js:5:35 index.js:13:19 GET /me/id 0 index.js:10:13 +ctx index.js:5:35 index.js:12:24 user +ctx index.js:5:35 index.js:13:19 user +regby index.js:1:1 index.js:12:24 GET /me/profile index.js:10:13 +regby index.js:1:1 index.js:13:19 GET /me/id index.js:10:13 +regby index.js:1:1 index.js:14:20 GET /public index.js:10:13 +unknown index.js:14:20 no_setter_on_chain index.js:14:20 diff --git a/graph/test/javascript/hono/expected/js/esm-create-route-wrapper.entries b/graph/test/javascript/hono/expected/js/esm-create-route-wrapper.entries new file mode 100644 index 000000000..1b46f5903 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-create-route-wrapper.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-03 (ESM): the wrapped DELETE route is a route with authorize's inner arrow at position 0; GET / from createRoute directly +# census: create_route, openapi_register, new_openapihono (violation hono-7-03; ESM JavaScript) +entry index.js:11:26 http +entry index.js:12:28 http +entry openapi.js:4:10 http diff --git a/graph/test/javascript/hono/expected/js/esm-create-route-wrapper.tsv b/graph/test/javascript/hono/expected/js/esm-create-route-wrapper.tsv new file mode 100644 index 000000000..90353191b --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-create-route-wrapper.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-03 (ESM): the wrapped DELETE route is a route with authorize's inner arrow at position 0; GET / from createRoute directly +# census: create_route, openapi_register, new_openapihono (violation hono-7-03; ESM JavaScript) +route GET /api/items index.js:11:26 index.js:14:13 0 +route DELETE /api/items/:id index.js:12:28 index.js:14:13 2 +mw openapi.js:4:10 index.js:12:28 DELETE /api/items/:id 0 index.js:14:13 +submount /api/items index.js:15:5 +regby index.js:1:1 index.js:11:26 GET /api/items index.js:14:13 +regby index.js:1:1 index.js:12:28 DELETE /api/items/:id index.js:14:13 diff --git a/graph/test/javascript/hono/expected/js/esm-fetch-unknown-base.entries b/graph/test/javascript/hono/expected/js/esm-fetch-unknown-base.entries new file mode 100644 index 000000000..33d562704 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-fetch-unknown-base.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-5-09: R14/R14a in JavaScript: parameter and URL bases and a single-label host join as base_unknown; a dotted external host never joins +# census: request_fetch (violation hono-5-09, SPEC R14 / R14a in JavaScript) +entry api.js:7:23 http +entry api.js:8:26 http diff --git a/graph/test/javascript/hono/expected/js/esm-fetch-unknown-base.tsv b/graph/test/javascript/hono/expected/js/esm-fetch-unknown-base.tsv new file mode 100644 index 000000000..85e1f7bd8 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-fetch-unknown-base.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-5-09: R14/R14a in JavaScript: parameter and URL bases and a single-label host join as base_unknown; a dotted external host never joins +# census: request_fetch (violation hono-5-09, SPEC R14 / R14a in JavaScript) +route POST /api/sessions api.js:7:23 api.js:6:13 0 +route GET /api/sessions/:id api.js:8:26 api.js:6:13 1 +request client.js:1:1 POST /api/sessions api.js:7:23 base_unknown +request client.js:5:1 GET /api/sessions/${} api.js:8:26 base_unknown +request client.js:9:1 GET /api/sessions/1 api.js:8:26 base_unknown +regby api.js:1:1 api.js:7:23 POST /api/sessions api.js:6:13 +regby api.js:1:1 api.js:8:26 GET /api/sessions/:id api.js:6:13 diff --git a/graph/test/javascript/hono/expected/js/esm-hc-client.entries b/graph/test/javascript/hono/expected/js/esm-hc-client.entries new file mode 100644 index 000000000..8b0c9038d --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-hc-client.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a typed-less JS hc client: both calls reach the only served app's routes by path (route_shape) +# census: hc_client, hc_dollar_call, hc_element_param (JavaScript: no type argument, SPEC 3.5 route_shape) +entry server.js:4:19 http +entry server.js:5:29 http diff --git a/graph/test/javascript/hono/expected/js/esm-hc-client.tsv b/graph/test/javascript/hono/expected/js/esm-hc-client.tsv new file mode 100644 index 000000000..33596efe9 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-hc-client.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a typed-less JS hc client: both calls reach the only served app's routes by path (route_shape) +# census: hc_client, hc_dollar_call, hc_element_param (JavaScript: no type argument, SPEC 3.5 route_shape) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /tasks server.js:4:19 server.js:3:13 0 +route POST /tasks/:id/done server.js:5:29 server.js:3:13 1 +rpc client.js:10:1 POST /tasks/:id/done server.js:5:29 +rpc client.js:7:1 GET /tasks server.js:4:19 +regby server.js:1:1 server.js:4:19 GET /tasks server.js:3:13 +regby server.js:1:1 server.js:5:29 POST /tasks/:id/done server.js:3:13 diff --git a/graph/test/javascript/hono/expected/js/esm-helper-request-method.entries b/graph/test/javascript/hono/expected/js/esm-helper-request-method.entries new file mode 100644 index 000000000..082ab99b4 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-helper-request-method.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-02 (ESM): the post helper's literal POST joins the two POST routes; the get helper (no init) joins GET /auth/login +# census: app_request_test (violation hono-7-02; ESM JavaScript) +entry auth.js:4:26 http +entry auth.js:5:27 http +entry auth.js:6:32 http diff --git a/graph/test/javascript/hono/expected/js/esm-helper-request-method.tsv b/graph/test/javascript/hono/expected/js/esm-helper-request-method.tsv new file mode 100644 index 000000000..28101f521 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-helper-request-method.tsv @@ -0,0 +1,19 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-02 (ESM): the post helper's literal POST joins the two POST routes; the get helper (no init) joins GET /auth/login +# census: app_request_test (violation hono-7-02; ESM JavaScript) +route GET /auth/login auth.js:4:26 test/auth.test.js:8:15 0 +route POST /auth/login auth.js:5:27 test/auth.test.js:8:15 1 +route POST /auth/login/form auth.js:6:32 test/auth.test.js:8:15 2 +route GET /auth/login auth.js:4:26 test/auth.test.js:15:15 0 +route POST /auth/login auth.js:5:27 test/auth.test.js:15:15 1 +route POST /auth/login/form auth.js:6:32 test/auth.test.js:15:15 2 +request test/auth.test.js:14:1 GET /auth/login auth.js:4:26 +request test/auth.test.js:7:1 POST /auth/login auth.js:5:27 +request test/auth.test.js:7:1 POST /auth/login/form auth.js:6:32 +submount /auth test/auth.test.js:9:7 +submount /auth test/auth.test.js:16:7 +regby auth.js:1:1 auth.js:4:26 GET /auth/login test/auth.test.js:15:15 +regby auth.js:1:1 auth.js:4:26 GET /auth/login test/auth.test.js:8:15 +regby auth.js:1:1 auth.js:5:27 POST /auth/login test/auth.test.js:15:15 +regby auth.js:1:1 auth.js:5:27 POST /auth/login test/auth.test.js:8:15 +regby auth.js:1:1 auth.js:6:32 POST /auth/login/form test/auth.test.js:15:15 +regby auth.js:1:1 auth.js:6:32 POST /auth/login/form test/auth.test.js:8:15 diff --git a/graph/test/javascript/hono/expected/js/esm-openapi-create-route.entries b/graph/test/javascript/hono/expected/js/esm-openapi-create-route.entries new file mode 100644 index 000000000..cadcafdd6 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-openapi-create-route.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: createRoute + .openapi in ESM JavaScript: GET /notes and GET /notes/:id ({id} as :id), the handler is arg 1 not the hook +# census: create_route, openapi_register, new_openapihono (ESM JavaScript; found with violation hono-7-03: the +entry index.js:10:24 http +entry index.js:13:3 http diff --git a/graph/test/javascript/hono/expected/js/esm-openapi-create-route.tsv b/graph/test/javascript/hono/expected/js/esm-openapi-create-route.tsv new file mode 100644 index 000000000..e3a63b51a --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-openapi-create-route.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: createRoute + .openapi in ESM JavaScript: GET /notes and GET /notes/:id ({id} as :id), the handler is arg 1 not the hook +# census: create_route, openapi_register, new_openapihono (ESM JavaScript; found with violation hono-7-03: the +route GET /notes index.js:10:24 index.js:8:13 0 +route GET /notes/:id index.js:13:3 index.js:8:13 1 +regby index.js:1:1 index.js:10:24 GET /notes index.js:8:13 +regby index.js:1:1 index.js:13:3 GET /notes/:id index.js:8:13 diff --git a/graph/test/javascript/hono/expected/js/esm-returned-object-destructure.entries b/graph/test/javascript/hono/expected/js/esm-returned-object-destructure.entries new file mode 100644 index 000000000..233716936 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-returned-object-destructure.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01 (ESM): each destructured name takes only its own property: stock and orders with their own handlers +# census: route_mount_literal, app_factory_fn (violation hono-7-01, P1 false_route; ESM JavaScript) +entry routes/orders.js:5:25 http +entry routes/orders.js:6:27 http +entry routes/stock.js:5:18 http +entry routes/stock.js:6:25 http diff --git a/graph/test/javascript/hono/expected/js/esm-returned-object-destructure.tsv b/graph/test/javascript/hono/expected/js/esm-returned-object-destructure.tsv new file mode 100644 index 000000000..4e3a44a0d --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-returned-object-destructure.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01 (ESM): each destructured name takes only its own property: stock and orders with their own handlers +# census: route_mount_literal, app_factory_fn (violation hono-7-01, P1 false_route; ESM JavaScript) +route GET /stock routes/stock.js:5:18 index.js:9:13 0 +route DELETE /stock/:sku routes/stock.js:6:25 index.js:9:13 1 +route GET /orders/recent routes/orders.js:5:25 index.js:9:13 2 +route PUT /orders/:orderId routes/orders.js:6:27 index.js:9:13 3 +submount /stock index.js:10:5 +submount /orders index.js:11:5 +regby routes/orders.js:3:1 routes/orders.js:5:25 GET /orders/recent index.js:9:13 +regby routes/orders.js:3:1 routes/orders.js:6:27 PUT /orders/:orderId index.js:9:13 +regby routes/stock.js:3:1 routes/stock.js:5:18 GET /stock index.js:9:13 +regby routes/stock.js:3:1 routes/stock.js:6:25 DELETE /stock/:sku index.js:9:13 diff --git a/graph/test/javascript/hono/expected/js/esm-twin-of-cjs-basic.entries b/graph/test/javascript/hono/expected/js/esm-twin-of-cjs-basic.entries new file mode 100644 index 000000000..f5ff7b719 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-twin-of-cjs-basic.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ESM .mjs twin of cjs-basic: same routes and cors scope +# census: new_hono, route_mount_literal, builtin_mw_import; ESM .mjs twin of js/cjs-basic +entry index.mjs:9:20 http +entry users.mjs:4:19 http diff --git a/graph/test/javascript/hono/expected/js/esm-twin-of-cjs-basic.tsv b/graph/test/javascript/hono/expected/js/esm-twin-of-cjs-basic.tsv new file mode 100644 index 000000000..daf57edb5 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/esm-twin-of-cjs-basic.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ESM .mjs twin of cjs-basic: same routes and cors scope +# census: new_hono, route_mount_literal, builtin_mw_import; ESM .mjs twin of js/cjs-basic +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/users/:id users.mjs:4:19 index.mjs:6:13 1 +route GET /health index.mjs:9:20 index.mjs:6:13 2 +mw lib:hono/cors.cors@index.mjs:7:19 users.mjs:4:19 GET /api/users/:id 0 index.mjs:6:13 +submount /api/users index.mjs:8:5 +regby index.mjs:1:1 index.mjs:9:20 GET /health index.mjs:6:13 +regby users.mjs:1:1 users.mjs:4:19 GET /api/users/:id index.mjs:6:13 diff --git a/graph/test/javascript/hono/expected/js/negative-js.entries b/graph/test/javascript/hono/expected/js/negative-js.entries new file mode 100644 index 000000000..3c6de27fc --- /dev/null +++ b/graph/test/javascript/hono/expected/js/negative-js.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Map and a router-shaped object beside one app: only /real +# census: neg_map_get_in_hono_file, neg_route_on_nonhono (JavaScript) +entry index.js:18:18 http diff --git a/graph/test/javascript/hono/expected/js/negative-js.tsv b/graph/test/javascript/hono/expected/js/negative-js.tsv new file mode 100644 index 000000000..4de824664 --- /dev/null +++ b/graph/test/javascript/hono/expected/js/negative-js.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Map and a router-shaped object beside one app: only /real +# census: neg_map_get_in_hono_file, neg_route_on_nonhono (JavaScript) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /real index.js:18:18 index.js:17:13 0 +regby index.js:1:1 index.js:18:18 GET /real index.js:17:13 +absent index.js:6:17 +absent index.js:14:25 +absent index.js:15:12 +absent index.js:10:3 +absent index.js:11:3 diff --git a/graph/test/javascript/hono/expected/js/unresolved-lib-mw.entries b/graph/test/javascript/hono/expected/js/unresolved-lib-mw.entries new file mode 100644 index 000000000..ccfa27b7a --- /dev/null +++ b/graph/test/javascript/hono/expected/js/unresolved-lib-mw.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O6: authSdk.middleware() from an unresolvable package stays at position 0 ahead of tag +# census: builtin_mw_import (oracle gap O6: a library middleware whose package cannot be resolved) +entry index.js:13:20 http +entry index.js:6:13 http diff --git a/graph/test/javascript/hono/expected/js/unresolved-lib-mw.tsv b/graph/test/javascript/hono/expected/js/unresolved-lib-mw.tsv new file mode 100644 index 000000000..6b68d328a --- /dev/null +++ b/graph/test/javascript/hono/expected/js/unresolved-lib-mw.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O6: authSdk.middleware() from an unresolvable package stays at position 0 ahead of tag +# census: builtin_mw_import (oracle gap O6: a library middleware whose package cannot be resolved) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /secure index.js:13:20 index.js:10:13 2 +mw lib:acme-auth-sdk.authSdk.middleware@index.js:11:9 index.js:13:20 GET /secure 0 index.js:10:13 +mw index.js:6:13 index.js:13:20 GET /secure 1 index.js:10:13 +regby index.js:1:1 index.js:13:20 GET /secure index.js:10:13 diff --git a/graph/test/javascript/hono/run-tests.sh b/graph/test/javascript/hono/run-tests.sh new file mode 100755 index 000000000..03fe76490 --- /dev/null +++ b/graph/test/javascript/hono/run-tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# axiom-code-graph: Hono torture suites, JavaScript twin. +# The same runner, oracle and compare as graph/test/typescript/hono (see its header), over this +# directory's cases/ and expected/, solved with the JavaScript engine. The oracle reads .js/.mjs/.cjs +# with allowJs, so the truth comes from the same compiler and the same pinned hono. +set -uo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +HONO_LANG=javascript HONO_SUITE_DIR="$HERE" exec bash "$HERE/../../typescript/hono/run-tests.sh" "$@" diff --git a/graph/test/typescript/cases/78-callable-collections/src/pipeline.ts b/graph/test/typescript/cases/78-callable-collections/src/pipeline.ts index 729b63fef..0a5fc05ee 100644 --- a/graph/test/typescript/cases/78-callable-collections/src/pipeline.ts +++ b/graph/test/typescript/cases/78-callable-collections/src/pipeline.ts @@ -30,7 +30,7 @@ export function runIndexed(node: Node, i: number): Node { return pick(steps[0](node)) } -// a table read under a computed key reaches every entry; under a written key, only that entry +// a table read under a computed key is a declared unknown (SPEC R21a); under a written key, only that entry export function runByKey(node: Node, k: 'grow' | 'shrink'): Node { return table[k](node) } diff --git a/graph/test/typescript/cases/87-handed-parameter-property/src/app.ts b/graph/test/typescript/cases/87-handed-parameter-property/src/app.ts new file mode 100644 index 000000000..e499eba4f --- /dev/null +++ b/graph/test/typescript/cases/87-handed-parameter-property/src/app.ts @@ -0,0 +1,15 @@ +import { Watchdog, Ticker, Silent, Ignores } from "./timers"; + +function reportTimeout(): void {} +function countTick(): void {} +function finishQuietly(): void {} +function finishIgnored(): void {} + +export function start(): string { + const dog = new Watchdog(reportTimeout, "dog"); + const ticker = new Ticker(countTick, 10); + ticker.start(); + const quiet = new Silent(finishQuietly); + new Ignores(finishIgnored); + return dog.expire() + quiet.name(); +} diff --git a/graph/test/typescript/cases/87-handed-parameter-property/src/timers.ts b/graph/test/typescript/cases/87-handed-parameter-property/src/timers.ts new file mode 100644 index 000000000..85b6a9da1 --- /dev/null +++ b/graph/test/typescript/cases/87-handed-parameter-property/src/timers.ts @@ -0,0 +1,37 @@ +// A function handed to a constructor lands in a parameter PROPERTY. The constructor +// body never reads the parameter; a method of the class runs it through the field. + +export class Watchdog { + constructor(private readonly onTimeout: () => void, private readonly label: string) {} + + expire(): string { + this.onTimeout(); + return this.label; + } +} + +// The field is read and handed on to a timer, not invoked on the spot. +export class Ticker { + private handle: ReturnType | undefined; + + constructor(private readonly onTick: () => void, private readonly ms: number) {} + + start(): void { + clearTimeout(this.handle); + this.handle = setTimeout(this.onTick, this.ms); + } +} + +// Control: the parameter property is never read, so nothing the class does can run it. +export class Silent { + constructor(private readonly onDone: () => void) {} + + name(): string { + return "silent"; + } +} + +// Control: a plain constructor parameter that the body never reads. +export class Ignores { + constructor(_onDone: () => void) {} +} diff --git a/graph/test/typescript/expected/08-function-values-and-callbacks.edges b/graph/test/typescript/expected/08-function-values-and-callbacks.edges index c0aeef314..aab049882 100644 --- a/graph/test/typescript/expected/08-function-values-and-callbacks.edges +++ b/graph/test/typescript/expected/08-function-values-and-callbacks.edges @@ -1,5 +1,7 @@ ambiguous_unknown FUNCTION_CALL values#useLibrary() @L40 -> - ambiguous_unknown METHOD_CALL values#drive() @L29 -> - +callback_handed FUNCTION_CALL values#drive() @L30 -> values#lower(?) +callback_handed FUNCTION_CALL values#drive() @L30 -> values#upper(?) callback_registered FUNCTION_CALL values#useLibrary() @L40 -> values#local(?) known_edge CONSTRUCTOR_CALL values#drive() @L27 -> Pipeline#() known_edge FUNCTION_CALL values#apply(Transform,string) @L12 -> values#(string) diff --git a/graph/test/typescript/expected/08-function-values-and-callbacks.lib.edges b/graph/test/typescript/expected/08-function-values-and-callbacks.lib.edges index 20caf154d..51c52f545 100644 --- a/graph/test/typescript/expected/08-function-values-and-callbacks.lib.edges +++ b/graph/test/typescript/expected/08-function-values-and-callbacks.lib.edges @@ -2,6 +2,8 @@ ambiguous_unknown METHOD_CALL values#drive() @L29 -> - boundary_lib FUNCTION_CALL values#useLibrary() @L40 -> hooks#(string) boundary_lib FUNCTION_CALL values#useLibrary() @L40 -> hooks#identity(?) boundary_lib FUNCTION_CALL values#useLibrary() @L40 -> hooks#withHook(Hook,string) +callback_handed FUNCTION_CALL values#drive() @L30 -> values#lower(?) +callback_handed FUNCTION_CALL values#drive() @L30 -> values#upper(?) callback_registered FUNCTION_CALL values#useLibrary() @L40 -> values#local(?) known_edge CONSTRUCTOR_CALL values#drive() @L27 -> Pipeline#() known_edge FUNCTION_CALL values#apply(Transform,string) @L12 -> values#(string) diff --git a/graph/test/typescript/expected/09-generics-substitution.edges b/graph/test/typescript/expected/09-generics-substitution.edges index 944a266cf..60c46ee6d 100644 --- a/graph/test/typescript/expected/09-generics-substitution.edges +++ b/graph/test/typescript/expected/09-generics-substitution.edges @@ -2,6 +2,7 @@ ambiguous_unknown CONSTRUCTOR_CALL generic#useLibrary() @L42 -> - ambiguous_unknown FUNCTION_CALL generic#useLibrary() @L45 -> - ambiguous_unknown METHOD_CALL generic#inferredFromArgument() @L35 -> - ambiguous_unknown METHOD_CALL generic#useLibrary() @L45 -> - +callback_handed FUNCTION_CALL generic#inferredFromArgument() @L35 -> generic#(?) known_edge CONSTRUCTOR_CALL Box#map((t: T) =) @L16 -> Box#(T) known_edge CONSTRUCTOR_CALL generic#fromReceiver() @L21 -> Box#(T) known_edge CONSTRUCTOR_CALL generic#fromReceiver() @L21 -> Item#() diff --git a/graph/test/typescript/expected/09-generics-substitution.lib.edges b/graph/test/typescript/expected/09-generics-substitution.lib.edges index b1235c884..ce3aa6b96 100644 --- a/graph/test/typescript/expected/09-generics-substitution.lib.edges +++ b/graph/test/typescript/expected/09-generics-substitution.lib.edges @@ -3,6 +3,7 @@ ambiguous_unknown METHOD_CALL generic#useLibrary() @L45 -> - boundary_lib CONSTRUCTOR_CALL generic#useLibrary() @L42 -> Cell#(T) boundary_lib FUNCTION_CALL generic#useLibrary() @L45 -> container#unwrap(Cell) boundary_lib METHOD_CALL generic#useLibrary() @L45 -> Cell#value() +callback_handed FUNCTION_CALL generic#inferredFromArgument() @L35 -> generic#(?) known_edge CONSTRUCTOR_CALL Box#map((t: T) =) @L16 -> Box#(T) known_edge CONSTRUCTOR_CALL generic#fromReceiver() @L21 -> Box#(T) known_edge CONSTRUCTOR_CALL generic#fromReceiver() @L21 -> Item#() diff --git a/graph/test/typescript/expected/34-callback-of-callback.edges b/graph/test/typescript/expected/34-callback-of-callback.edges index d2ff99be3..c8f6aff26 100644 --- a/graph/test/typescript/expected/34-callback-of-callback.edges +++ b/graph/test/typescript/expected/34-callback-of-callback.edges @@ -1,3 +1,4 @@ +callback_handed FUNCTION_CALL exec#viaClientCallbackOfCallback() @L32 -> exec#(?) callback_registered CONSTRUCTOR_CALL exec#viaExecutor() @L12 -> exec#(?,?) callback_registered CONSTRUCTOR_CALL exec#viaRenamedExecutor() @L20 -> exec#(?,?) callback_registered FUNCTION_CALL exec#withSink((emit: Sink) =) @L29 -> exec#() diff --git a/graph/test/typescript/expected/59-merged-export-through-namespace.edges b/graph/test/typescript/expected/59-merged-export-through-namespace.edges index ec737c759..f2f171898 100644 --- a/graph/test/typescript/expected/59-merged-export-through-namespace.edges +++ b/graph/test/typescript/expected/59-merged-export-through-namespace.edges @@ -1,3 +1,6 @@ +callback_handed FUNCTION_CALL classic/schemas#() @L5 -> classic/schemas#() +callback_handed METHOD_CALL classic/schemas#() @L4 -> classic/schemas#(?) +callback_handed METHOD_CALL core/schemas#() @L3 -> core/schemas#(?) known_edge FUNCTION_CALL classic/schemas#() @L5 -> core/core#$constructor(string,(inst: object) =) known_edge FUNCTION_CALL core/core#$constructor(string,(inst: object) =) @L3 -> core/core#(object) known_edge METHOD_CALL classic/schemas#(?) @L4 -> core/core#helper() diff --git a/graph/test/typescript/expected/75-jsx-wrapper-guards.edges b/graph/test/typescript/expected/75-jsx-wrapper-guards.edges index 78ebdfe74..684930deb 100644 --- a/graph/test/typescript/expected/75-jsx-wrapper-guards.edges +++ b/graph/test/typescript/expected/75-jsx-wrapper-guards.edges @@ -19,6 +19,8 @@ ambiguous_unknown METHOD_CALL app#() @L15 -> - ambiguous_unknown METHOD_CALL app#() @L16 -> - ambiguous_unknown METHOD_CALL app#() @L18 -> - ambiguous_unknown METHOD_CALL app#ArrowRenameTag({ icon: Fc }[]) @L57 -> - +callback_handed FUNCTION_CALL app#() @L25 -> app#() +callback_handed FUNCTION_CALL app#() @L26 -> app#() callback_registered FUNCTION_CALL app#() @L15 -> app#() callback_registered FUNCTION_CALL app#() @L16 -> app#() callback_registered FUNCTION_CALL app#() @L18 -> app#() diff --git a/graph/test/typescript/expected/78-callable-collections.envelope b/graph/test/typescript/expected/78-callable-collections.envelope index 90d7c9ee5..a0cc7f8d0 100644 --- a/graph/test/typescript/expected/78-callable-collections.envelope +++ b/graph/test/typescript/expected/78-callable-collections.envelope @@ -2,8 +2,6 @@ value pipeline#@10:23 -> steps#pushed value_call pipeline#@43 -> steps#narrow value_call pipeline#@43 -> steps#widen value_call pipeline#@46 -> steps#square -value_call pipeline#runByKey -> steps#narrow -value_call pipeline#runByKey -> steps#widen value_call pipeline#runFrozen -> steps#square value_call pipeline#runImported -> steps#halve value_call pipeline#runIndexed -> steps#narrow diff --git a/graph/test/typescript/expected/78-hof-callback-at-library-boundary.edges b/graph/test/typescript/expected/78-hof-callback-at-library-boundary.edges index 7159e17d1..9e0d19af6 100644 --- a/graph/test/typescript/expected/78-hof-callback-at-library-boundary.edges +++ b/graph/test/typescript/expected/78-hof-callback-at-library-boundary.edges @@ -7,6 +7,7 @@ ambiguous_unknown CONSTRUCTOR_CALL store#() @L9 -> - ambiguous_unknown METHOD_CALL store#known() @L17 -> - ambiguous_unknown METHOD_CALL store#store() @L12 -> - ambiguous_unknown METHOD_CALL store#store() @L13 -> - +callback_handed FUNCTION_CALL app#useEach(number[]) @L48 -> app#(?) callback_registered FUNCTION_CALL app#atStartup() @L38 -> app#() callback_registered FUNCTION_CALL plugin#() @L7 -> plugin#() callback_registered FUNCTION_CALL store#deferred() @L24 -> store#onUpdated() diff --git a/graph/test/typescript/expected/80-generic-return-receiver.envelope b/graph/test/typescript/expected/80-generic-return-receiver.envelope index aee022b92..9a7c461a1 100644 --- a/graph/test/typescript/expected/80-generic-return-receiver.envelope +++ b/graph/test/typescript/expected/80-generic-return-receiver.envelope @@ -1,6 +1,6 @@ nominal use#Shape.area -> use#Circ.area nominal use#Shape.area -> use#Sq.area nominal use#Warrior.fight -> use#Ninja.fight -value_call use#recordArea -> use#@38 -value_call use#totalArea -> use#@30 -value_call use#totalArea -> use#@31 +value use#@29:33 -> use#@30 +value use#@29:33 -> use#@31 +value use#@38:30 -> use#@38 diff --git a/graph/test/typescript/expected/80-generic-return-receiver.lib.envelope b/graph/test/typescript/expected/80-generic-return-receiver.lib.envelope index aee022b92..9a7c461a1 100644 --- a/graph/test/typescript/expected/80-generic-return-receiver.lib.envelope +++ b/graph/test/typescript/expected/80-generic-return-receiver.lib.envelope @@ -1,6 +1,6 @@ nominal use#Shape.area -> use#Circ.area nominal use#Shape.area -> use#Sq.area nominal use#Warrior.fight -> use#Ninja.fight -value_call use#recordArea -> use#@38 -value_call use#totalArea -> use#@30 -value_call use#totalArea -> use#@31 +value use#@29:33 -> use#@30 +value use#@29:33 -> use#@31 +value use#@38:30 -> use#@38 diff --git a/graph/test/typescript/expected/81-contextual-lambda-param-no-lib.edges b/graph/test/typescript/expected/81-contextual-lambda-param-no-lib.edges index f055468cc..747f9d6f7 100644 --- a/graph/test/typescript/expected/81-contextual-lambda-param-no-lib.edges +++ b/graph/test/typescript/expected/81-contextual-lambda-param-no-lib.edges @@ -14,6 +14,10 @@ ambiguous_unknown METHOD_CALL use#reduceElement(User[]) @L58 -> - ambiguous_unknown METHOD_CALL use#thenBare(Repo) @L61 -> - ambiguous_unknown METHOD_CALL use#thenParam(Promise) @L64 -> - ambiguous_unknown METHOD_CALL use#thenThenMap(Promise) @L82 -> - +callback_handed METHOD_CALL shadow#ctlOwnPromise(Promise) @L29 -> shadow#(?) +callback_handed METHOD_CALL shadow#ctlOwnSet(Set) @L26 -> shadow#(?) +callback_handed METHOD_CALL use#ctlOwnMap(Lazy) @L109 -> use#(?) +callback_handed METHOD_CALL use#ctlOwnThen(Lazy) @L106 -> use#(?) callback_registered METHOD_CALL use#(?) @L78 -> use#(?) callback_registered METHOD_CALL use#(?) @L83 -> use#(?) callback_registered METHOD_CALL use#aliasGeneric(Many) @L73 -> use#(?) diff --git a/graph/test/typescript/expected/82-structural-conformer-across-programs.edges b/graph/test/typescript/expected/82-structural-conformer-across-programs.edges index 5d1aad278..143ff87d0 100644 --- a/graph/test/typescript/expected/82-structural-conformer-across-programs.edges +++ b/graph/test/typescript/expected/82-structural-conformer-across-programs.edges @@ -1,3 +1,4 @@ +callback_handed METHOD_CALL app/pipeline#build(string[]) @L15 -> app/pipeline#(?) known_edge CONSTRUCTOR_CALL Pipeline#map((value: T) =) @L10 -> Pipeline#(T[]) known_edge CONSTRUCTOR_CALL app/pipeline#build(string[]) @L15 -> Pipeline#(T[]) known_edge CONSTRUCTOR_CALL fixture/use#() @L16 -> Bag#() diff --git a/graph/test/typescript/expected/87-handed-parameter-property.edges b/graph/test/typescript/expected/87-handed-parameter-property.edges new file mode 100644 index 000000000..66c55fca3 --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.edges @@ -0,0 +1,12 @@ +ambiguous_unknown FUNCTION_CALL Ticker#start() @L20 -> - +ambiguous_unknown FUNCTION_CALL Ticker#start() @L21 -> - +callback_handed CONSTRUCTOR_CALL app#start() @L10 -> app#countTick() +callback_handed CONSTRUCTOR_CALL app#start() @L9 -> app#reportTimeout() +known_edge CONSTRUCTOR_CALL app#start() @L10 -> Ticker#(() =,number) +known_edge CONSTRUCTOR_CALL app#start() @L12 -> Silent#(() =) +known_edge CONSTRUCTOR_CALL app#start() @L13 -> Ignores#(() =) +known_edge CONSTRUCTOR_CALL app#start() @L9 -> Watchdog#(() =,string) +known_edge METHOD_CALL Watchdog#expire() @L8 -> Watchdog#() +known_edge METHOD_CALL app#start() @L11 -> Ticker#start() +known_edge METHOD_CALL app#start() @L14 -> Silent#name() +known_edge METHOD_CALL app#start() @L14 -> Watchdog#expire() diff --git a/graph/test/typescript/expected/87-handed-parameter-property.entries b/graph/test/typescript/expected/87-handed-parameter-property.entries new file mode 100644 index 000000000..a8437099d --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.entries @@ -0,0 +1,3 @@ +── entry_point (2) ── + exported_from_entry_module app#start app.ts:8 + unimported_module app# app.ts:1 diff --git a/graph/test/typescript/expected/87-handed-parameter-property.envelope b/graph/test/typescript/expected/87-handed-parameter-property.envelope new file mode 100644 index 000000000..4a7e97865 --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.envelope @@ -0,0 +1,4 @@ +value timers#@17:40 -> app#countTick +value timers#@27:40 -> app#finishQuietly +value timers#@36:24 -> app#finishIgnored +value timers#@5:43 -> app#reportTimeout diff --git a/graph/test/typescript/expected/87-handed-parameter-property.fields b/graph/test/typescript/expected/87-handed-parameter-property.fields new file mode 100644 index 000000000..40fc20fd6 --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.fields @@ -0,0 +1,5 @@ +known_edge read Ticker#start() -> Ticker#handle +known_edge read Ticker#start() -> Ticker#ms +known_edge read Ticker#start() -> Ticker#onTick +known_edge read Watchdog#expire() -> Watchdog#label +known_edge write Ticker#start() -> Ticker#handle diff --git a/graph/test/typescript/expected/87-handed-parameter-property.fields-oracle b/graph/test/typescript/expected/87-handed-parameter-property.fields-oracle new file mode 100644 index 000000000..65b55d096 --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.fields-oracle @@ -0,0 +1,8 @@ +87-handed-parameter-property [fields] + precision 1.0000 (5 correct, 0 wrong) + recall 0.8333 (5 of 6 the compiler resolved) + sites 5 resolved 5 (100.0%) + tiers known_edge=5 + access read=4 write=1 + not scored: 0 rows whose target is not a client declaration + MISSING Watchdog#expire() READ Watchdog#onTimeout diff --git a/graph/test/typescript/expected/87-handed-parameter-property.oracle b/graph/test/typescript/expected/87-handed-parameter-property.oracle new file mode 100644 index 000000000..00f772edc --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.oracle @@ -0,0 +1 @@ +oracle=8 engine=8 agree=8 missing=0 (known 0, NEW 0) extra=0 diff --git a/graph/test/typescript/expected/87-handed-parameter-property.type-use b/graph/test/typescript/expected/87-handed-parameter-property.type-use new file mode 100644 index 000000000..18394f40c --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.type-use @@ -0,0 +1,5 @@ +ambiguous_unknown TYPE_ELEMENT 1 Ticker [FIELD] -> - +known_edge OBJECT_CREATION_TYPE 0 app [EXPRESSION] -> Ignores +known_edge OBJECT_CREATION_TYPE 0 app [EXPRESSION] -> Silent +known_edge OBJECT_CREATION_TYPE 0 app [EXPRESSION] -> Ticker +known_edge OBJECT_CREATION_TYPE 0 app [EXPRESSION] -> Watchdog diff --git a/graph/test/typescript/expected/87-handed-parameter-property.types-oracle b/graph/test/typescript/expected/87-handed-parameter-property.types-oracle new file mode 100644 index 000000000..2c69d5dd1 --- /dev/null +++ b/graph/test/typescript/expected/87-handed-parameter-property.types-oracle @@ -0,0 +1,7 @@ +87-handed-parameter-property [types] + precision 1.0000 (4 correct, 0 wrong) + recall 1.0000 (4 of 4 the compiler resolved) + sites 5 resolved 4 (80.0%) + tiers ambiguous_unknown=1 known_edge=4 + contexts OBJECT_CREATION_TYPE=4 TYPE_ELEMENT=1 + not scored: 1 rows whose target is not a client declaration diff --git a/graph/test/typescript/hono/.gitignore b/graph/test/typescript/hono/.gitignore new file mode 100644 index 000000000..67cdb2e91 --- /dev/null +++ b/graph/test/typescript/hono/.gitignore @@ -0,0 +1,8 @@ +.work/ +*.draft +.oracle-all.log +.tip-ts.log +.tip-js.log +.tip-*.log +.rescore.log +.redraft.log diff --git a/graph/test/typescript/hono/cases/chains/ctx-partial-route/src/app.ts b/graph/test/typescript/hono/cases/chains/ctx-partial-route/src/app.ts new file mode 100644 index 000000000..20436a109 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-partial-route/src/app.ts @@ -0,0 +1,42 @@ +import { Hono } from 'hono' +import { Db, UserRepo, UserService } from './users' + +declare const process: { env: Record } + +type Env = { Variables: { services: { users: UserService } } } + +// a feature sub-app with its own Env and its own provider middleware +const users = new Hono() +users.use('*', async (c, next) => { + c.set('services', { users: new UserService(new UserRepo(new Db())) }) + await next() +}) +users.get('/:id', (c) => { + const { users } = c.get('services') + return c.json(users.find(c.req.param('id'))) +}) +users.delete('/:id', async (c) => { + const svc = c.var.services + return c.json({ ok: svc.users.remove(c.req.param('id')) }) +}) + +// the served root lives in a server holder that a run-time prefix rebases (the corpus's server-class shape) +class Server { + app = new Hono() + private prefix?: string + constructor(prefix?: string) { + this.prefix = prefix + } + build() { + this.app = new Hono() + if (this.prefix) { + this.app = this.app.basePath(this.prefix) + } + return this + } +} + +const server = new Server(process.env.API_BASE).build() +server.app.route('/users', users) + +export default server.app diff --git a/graph/test/typescript/hono/cases/chains/ctx-partial-route/src/users.ts b/graph/test/typescript/hono/cases/chains/ctx-partial-route/src/users.ts new file mode 100644 index 000000000..6835ba7f1 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-partial-route/src/users.ts @@ -0,0 +1,39 @@ +// census: ctx_di on a rebased root (SPEC R18 on a PARTIAL route: http_route_partial, dynamic_mount_prefix) +// The served app takes its base path from the environment, so every route under it is partial (its full path is +// not decidable). What R18 asks does not depend on the path: the handler still reads the service out of the +// context, typed by the sub-app's Env, and its calls must still resolve. At run time the variable is unset, so the +// chains are requested at the un-rebased path. +export class Db { + get(key: string): string[] { + return [key] + } + del(key: string): boolean { + return key.length > 0 + } +} + +export class UserRepo { + private db: Db + constructor(db: Db) { + this.db = db + } + byId(id: string) { + return this.db.get(`user:${id}`) + } + drop(id: string) { + return this.db.del(`user:${id}`) + } +} + +export class UserService { + private repo: UserRepo + constructor(repo: UserRepo) { + this.repo = repo + } + find(id: string) { + return this.repo.byId(id) + } + remove(id: string) { + return this.repo.drop(id) + } +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-partial-untyped/src/app.ts b/graph/test/typescript/hono/cases/chains/ctx-partial-untyped/src/app.ts new file mode 100644 index 000000000..52176c566 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-partial-untyped/src/app.ts @@ -0,0 +1,28 @@ +import { Hono } from 'hono' +import { OrderRepo, OrderService } from './orders' + +declare const process: { env: Record } + +// the feature sub-app: no Env, its own provider middleware +const orders = new Hono() +orders.use('*', async (c: any, next) => { + c.set('orders', new OrderService(new OrderRepo())) + await next() +}) +orders.get('/list', (c: any) => { + const svc = c.get('orders') + return c.json({ rows: svc.list(), tenant: String(c.get('tenant') ?? '') }) +}) +orders.get('/total', (c: any) => c.json({ total: c.var.orders.total() })) + +// the served root mounts the feature at a prefix read from the environment (the default is only what an unset +// variable gives at run time); a scoped middleware on the root MAY apply, depending on that prefix +const app = new Hono() +app.use('/api/*', async (c: any, next) => { + c.set('tenant', 't1') + await next() +}) +const prefix = process.env.ORDERS_PREFIX || '/api/orders' +app.route(prefix, orders) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/ctx-partial-untyped/src/orders.ts b/graph/test/typescript/hono/cases/chains/ctx-partial-untyped/src/orders.ts new file mode 100644 index 000000000..dbe30d540 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-partial-untyped/src/orders.ts @@ -0,0 +1,32 @@ +// census: ctx_di on a rebased root, untyped (SPEC R23 with R18's setter-type form, on PARTIAL routes) +// No Env type: the only thing that says what `c.get('orders')` holds is the sub-app middleware's +// `c.set('orders', new OrderService(..))`. That middleware is in the partial routes' DECIDED chain (mwp), so the +// key flows to the handlers exactly as on an exact route (R23) and the calls on the value resolve to OrderService. +// The root's scoped `use('/api/*', ..)` only MAY apply under the unknown mount prefix: its `c.set('tenant', ..)` gives no +// flow row, and the reader of 'tenant' is no_setter_on_chain. The compiler types the reads as any; the run-time +// trace observes the calls. +export class OrderRepo { + rows: string[] + constructor() { + this.rows = [] + } + all() { + return this.rows + } + count() { + return this.rows.length + } +} + +export class OrderService { + repo: OrderRepo + constructor(repo: OrderRepo) { + this.repo = repo + } + list() { + return this.repo.all() + } + total() { + return this.repo.count() + } +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/app.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/app.ts new file mode 100644 index 000000000..22af181f5 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/app.ts @@ -0,0 +1,33 @@ +import { Hono } from 'hono' +import type { IEnv } from './env' +import type { Env } from './env' +import { provide, auditTrail, factory } from './wire' +import { verifyKey, showUser } from './handlers' +import { Db } from './db' +import { UserRepo } from './repos' +import { UserService } from './services' + +const app = new Hono() +app.use('*', provide) +app.use('/keys/*', auditTrail) +app.get('/keys/:key', verifyKey) + +// inline Env generic, c.get(k).m() on the call result +app.get('/users/:id', (c) => c.json(c.get('services').users.find(c.req.param('id') ?? ''))) + +// a factory app with the same Env: handlers from createHandlers read c.var.services +const fapp = factory.createApp() +fapp.use('*', provide) +fapp.get('/whoami/:id', ...factory.createHandlers((c) => c.json(c.var.services.users.find(c.req.param('id') ?? '')))) +app.route('/f', fapp) + +// an interface Env on a sub-app +const iapp = new Hono() +iapp.use('*', async (c, next) => { + c.set('users', new UserService(new UserRepo(new Db()))) + await next() +}) +iapp.get('/u/:id', showUser) +app.route('/i', iapp) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/db.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/db.ts new file mode 100644 index 000000000..9fe53b751 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/db.ts @@ -0,0 +1,10 @@ +// census: ctx_di (SPEC R18; call-chain break class 1, "a service read out of the framework context") +// A request chain handler -> service -> repository -> db, where the handler reaches the service ONLY through the +// framework context: `c.get(k)`, `c.var.k`, a destructured `c.get(k)`, a `const x = c.var.k`, with the key's type +// declared by each Env form (inline generic, type alias, interface, createFactory, MiddlewareHandler, +// Context parameter). +export class Db { + query(sql: string): string[] { + return [sql] + } +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/env.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/env.ts new file mode 100644 index 000000000..0468b8f9a --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/env.ts @@ -0,0 +1,9 @@ +import type { UserService, KeyService, AuditService } from './services' + +// the Env as a type alias +export type Env = { Variables: { services: { users: UserService; keys: KeyService }; audit: AuditService } } + +// the same shape as an interface +export interface IEnv { + Variables: { users: UserService } +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/handlers.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/handlers.ts new file mode 100644 index 000000000..ee076d25e --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/handlers.ts @@ -0,0 +1,14 @@ +import type { Context } from 'hono' +import type { Env, IEnv } from './env' + +// Context parameter, destructured c.get +export async function verifyKey(c: Context) { + const { keys } = c.get('services') + return c.json({ ok: keys.verify(c.req.param('key') ?? '') }) +} + +// Context (an interface Env), `const x = c.var.k` +export async function showUser(c: Context) { + const users = c.var.users + return c.json(users.find(c.req.param('id') ?? '')) +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/repos.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/repos.ts new file mode 100644 index 000000000..bb0af0c87 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/repos.ts @@ -0,0 +1,21 @@ +import { Db } from './db' + +export class UserRepo { + private db: Db + constructor(db: Db) { + this.db = db + } + byId(id: string) { + return this.db.query(`user ${id}`) + } +} + +export class KeyRepo { + private db: Db + constructor(db: Db) { + this.db = db + } + lookup(key: string) { + return this.db.query(`key ${key}`) + } +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/services.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/services.ts new file mode 100644 index 000000000..1358d3a3e --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/services.ts @@ -0,0 +1,27 @@ +import { UserRepo, KeyRepo } from './repos' + +export class UserService { + private repo: UserRepo + constructor(repo: UserRepo) { + this.repo = repo + } + find(id: string) { + return this.repo.byId(id) + } +} + +export class KeyService { + private repo: KeyRepo + constructor(repo: KeyRepo) { + this.repo = repo + } + verify(key: string) { + return this.repo.lookup(key).length > 0 + } +} + +export class AuditService { + record(what: string) { + return what.length + } +} diff --git a/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/wire.ts b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/wire.ts new file mode 100644 index 000000000..bd7b6ed21 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-services-typed/src/wire.ts @@ -0,0 +1,22 @@ +import { createFactory } from 'hono/factory' +import type { MiddlewareHandler } from 'hono' +import type { Env } from './env' +import { Db } from './db' +import { UserRepo, KeyRepo } from './repos' +import { UserService, KeyService, AuditService } from './services' + +const db = new Db() +export const factory = createFactory() + +// MiddlewareHandler: the middleware that puts the services into the context +export const provide: MiddlewareHandler = async (c, next) => { + c.set('services', { users: new UserService(new UserRepo(db)), keys: new KeyService(new KeyRepo(db)) }) + c.set('audit', new AuditService()) + await next() +} + +// createFactory().createMiddleware: a middleware that reads a service back with c.var +export const auditTrail = factory.createMiddleware(async (c, next) => { + c.var.audit.record(c.req.path) + await next() +}) diff --git a/graph/test/typescript/hono/cases/chains/ctx-set-untyped/src/app.ts b/graph/test/typescript/hono/cases/chains/ctx-set-untyped/src/app.ts new file mode 100644 index 000000000..3a1804bf8 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-set-untyped/src/app.ts @@ -0,0 +1,24 @@ +import { Hono } from 'hono' +import { OrderRepo, OrderService } from './orders' + +// handlers whose context parameter is `any` (the commonest untyped shape) +const app = new Hono() +app.use('/orders/*', async (c: any, next) => { + c.set('orders', new OrderService(new OrderRepo())) + await next() +}) +app.get('/orders/list', (c: any) => { + const orders = c.get('orders') + return c.json(orders.list()) +}) + +// an app whose Env is `any`: c.var.k is any too +const reports = new Hono() +reports.use('*', async (c, next) => { + c.set('orders', new OrderService(new OrderRepo())) + await next() +}) +reports.get('/total', (c) => c.json({ total: c.var.orders.total() })) +app.route('/reports', reports) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/ctx-set-untyped/src/orders.ts b/graph/test/typescript/hono/cases/chains/ctx-set-untyped/src/orders.ts new file mode 100644 index 000000000..e9f1c146f --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/ctx-set-untyped/src/orders.ts @@ -0,0 +1,30 @@ +// census: ctx_di (SPEC R18, the untyped form; call-chain break class 1) +// No Env type anywhere: the app is `new Hono()`. The only thing that says what `c.get('orders')` holds is the +// middleware's `c.set('orders', new OrderService(..))` on the chain that reaches the handler (ctx_key_flow), so +// calls on the value read back resolve to OrderService. The compiler types the read as any; the run-time trace +// observes the calls. +export class OrderRepo { + rows: string[] + constructor() { + this.rows = [] + } + all() { + return this.rows + } + count() { + return this.rows.length + } +} + +export class OrderService { + repo: OrderRepo + constructor(repo: OrderRepo) { + this.repo = repo + } + list() { + return this.repo.all() + } + total() { + return this.repo.count() + } +} diff --git a/graph/test/typescript/hono/cases/chains/function-values/src/app.ts b/graph/test/typescript/hono/cases/chains/function-values/src/app.ts new file mode 100644 index 000000000..7ef58978b --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/function-values/src/app.ts @@ -0,0 +1,28 @@ +import { Hono } from 'hono' +import { handlers, withRetry, tryit, run, readInput, pipeline, Mailer, purge } from './ops' + +const app = new Hono() +const ACTION = 'restore' + +// a callback passed to a project higher-order function +app.get('/retry/:id', (c) => c.text(withRetry(2, () => handlers.archive(c.req.param('id'))))) +// a handler table read with a literal bracket key and with a const key +app.get('/table/:id', (c) => c.text(handlers['archive'](c.req.param('id')) + handlers[ACTION](c.req.param('id')))) +// a returned function, then called +app.get('/tryit/:id', (c) => c.text(tryit(purge)(c.req.param('id')))) +// a function stored in an options object +app.get('/options', (c) => c.text(run({ getInput: readInput }))) +// an array element +app.get('/pipeline/:id', (c) => c.text(pipeline[1](c.req.param('id')))) +// a bound method +app.get('/mail/:to', (c) => { + const send = new Mailer('ops').send.bind(new Mailer('noreply')) + return c.text(send(c.req.param('to'))) +}) +// a key the program does not decide: a declared unknown +app.get('/act/:op/:id', (c) => { + const op = c.req.param('op') as keyof typeof handlers + return c.text(handlers[op](c.req.param('id'))) +}) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/function-values/src/ops.ts b/graph/test/typescript/hono/cases/chains/function-values/src/ops.ts new file mode 100644 index 000000000..1a150d374 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/function-values/src/ops.ts @@ -0,0 +1,46 @@ +// census: fn_value (SPEC R21; call-chain break class 2, "callback / higher-order: function values") +// A function value passed, stored or returned reaches its target when the value is decidable: a callback +// parameter, a handler table read with a literal key (dot, bracket, and a const key), an options-object function, +// an array element, a returned function, and a bound function. A table read with a key the program does not decide +// is a declared unknown, never silently dropped. +export function archive(id: string) { + return `archived ${id}` +} +export function restore(id: string) { + return `restored ${id}` +} +export function purge(id: string) { + return `purged ${id}` +} + +export const handlers = { archive, restore, purge } + +export function withRetry(times: number, fn: () => T): T { + let last: T = fn() + for (let i = 1; i < times; i++) last = fn() + return last +} + +export function tryit(fn: (...a: A) => R) { + return (...a: A) => fn(...a) +} + +export function run(opts: { getInput: () => string }) { + return opts.getInput() +} + +export function readInput() { + return 'input' +} + +export const pipeline = [archive, restore] + +export class Mailer { + from: string + constructor(from: string) { + this.from = from + } + send(to: string) { + return `${this.from} -> ${to}` + } +} diff --git a/graph/test/typescript/hono/cases/chains/library-generic-params/src/app.ts b/graph/test/typescript/hono/cases/chains/library-generic-params/src/app.ts new file mode 100644 index 000000000..6b4981278 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/library-generic-params/src/app.ts @@ -0,0 +1,25 @@ +import { Hono } from 'hono' +import { validator } from 'hono/validator' +import { Ledger, Role } from './model' +import { describeRoles, topRank, latestName, staticProviders, byName, makePairs, makeIndex } from './report' + +const app = new Hono() +const ledger = new Ledger() + +app.get('/roles', (c) => c.json(describeRoles(ledger))) +app.get('/rank', (c) => c.json({ top: topRank(ledger) })) +app.get('/latest', async (c) => c.json(await latestName(ledger))) +app.get('/providers', (c) => c.json(staticProviders(makePairs()))) +app.get('/names', (c) => c.json(byName(makeIndex()))) + +// a validator hook: the value is typed by the library's generic +app.post( + '/roles', + validator('json', (value) => new Role(String(value))), + (c) => { + const role = c.req.valid('json') + return c.json(role.toJSON()) + }, +) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/library-generic-params/src/model.ts b/graph/test/typescript/hono/cases/chains/library-generic-params/src/model.ts new file mode 100644 index 000000000..c5f38fd48 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/library-generic-params/src/model.ts @@ -0,0 +1,39 @@ +// census: callback_generic (SPEC R19; call-chain break class 3, "type through a library generic") +// A callback parameter or a destructured element whose type comes ONLY through a library or builtin generic: +// Array.map / forEach / filter / reduce callbacks, Promise.then, Map.forEach, a tuple taken from Array.shift() +// and Object.entries, and a Hono validator hook. Calls on them resolve to the project methods. +export class Role { + name: string + constructor(name: string) { + this.name = name + } + toJSON() { + return { role: this.name } + } + rank() { + return this.name.length + } +} + +export class Wrapper { + label: string + constructor(label: string) { + this.label = label + } + isStatic() { + return this.label.startsWith('static') + } +} + +export class Ledger { + entries: Role[] + constructor() { + this.entries = [new Role('admin'), new Role('viewer')] + } + roles() { + return this.entries + } + async latest(): Promise { + return this.entries[0] + } +} diff --git a/graph/test/typescript/hono/cases/chains/library-generic-params/src/report.ts b/graph/test/typescript/hono/cases/chains/library-generic-params/src/report.ts new file mode 100644 index 000000000..953060335 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/library-generic-params/src/report.ts @@ -0,0 +1,36 @@ +import { Role, Wrapper, Ledger } from './model' + +export function describeRoles(ledger: Ledger) { + return ledger.roles().map((r) => r.toJSON()) +} + +export function topRank(ledger: Ledger) { + return ledger.roles().reduce((acc, r) => Math.max(acc, r.rank()), 0) +} + +export async function latestName(ledger: Ledger) { + return ledger.latest().then((role) => role.toJSON()) +} + +export function staticProviders(pairs: Array<[string, Wrapper]>) { + const [, first] = pairs.shift()! + const out = [first.isStatic()] + for (const [, w] of Object.entries(Object.fromEntries(pairs))) out.push(w.isStatic()) + return out +} + +export function byName(index: Map) { + const names: number[] = [] + index.forEach((role) => { + names.push(role.rank()) + }) + return names +} + +export function makePairs(): Array<[string, Wrapper]> { + return [['a', new Wrapper('static-a')], ['b', new Wrapper('dyn-b')]] +} + +export function makeIndex() { + return new Map([['admin', new Role('admin')]]) +} diff --git a/graph/test/typescript/hono/cases/chains/post-validator-chain/src/app.ts b/graph/test/typescript/hono/cases/chains/post-validator-chain/src/app.ts new file mode 100644 index 000000000..fd87e0885 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/post-validator-chain/src/app.ts @@ -0,0 +1,40 @@ +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' +import { validator } from 'hono/validator' +import { zValidator } from '@hono/zod-validator' +import { z } from 'zod' +import { Db, OrderRepo, OrderService } from './orders' + +type Env = { Variables: { services: { orders: OrderService } } } + +const createOrder = z.object({ sku: z.string(), qty: z.number() }) + +const provide: MiddlewareHandler = async (c, next) => { + c.set('services', { orders: new OrderService(new OrderRepo(new Db())) }) + await next() +} + +const app = new Hono() +app.use('/orders/*', provide) + +// zValidator('json', schema) before the handler; destructured c.get('services') +app.post('/orders', zValidator('json', createOrder), async (c) => { + const input = c.req.valid('json') + const { orders } = c.get('services') + return c.json({ id: orders.create(input) }, 201) +}) + +// the built-in validator('json', fn) with a hand-written check; c.var.services read inline +app.post( + '/orders/:id/items', + validator('json', (value, c) => { + if (typeof value?.sku !== 'string') return c.text('sku required', 400) + return { sku: value.sku as string } + }), + (c) => { + const { sku } = c.req.valid('json') + return c.json({ n: c.var.services.orders.addItem(c.req.param('id'), sku) }) + } +) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/post-validator-chain/src/orders.ts b/graph/test/typescript/hono/cases/chains/post-validator-chain/src/orders.ts new file mode 100644 index 000000000..621a64d6c --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/post-validator-chain/src/orders.ts @@ -0,0 +1,36 @@ +// census: ctx_di + zvalidator + req_valid (SPEC R18 with SPEC 3.9; call-chain break class 1 on a POST route) +// The commonest write route in the corpus: a json validator runs before the handler, the handler reads the +// validated body with c.req.valid('json') and hands it to a service it reads out of the context. The chain is +// provider middleware -> (library validator) -> handler -> service -> repository -> db. At run time the handler +// is only entered when the request carries a JSON body the schema accepts (the golden's `body` rows). +export class Db { + insert(table: string, row: object): number { + return Object.keys(row).length + table.length + } +} + +export class OrderRepo { + private db: Db + constructor(db: Db) { + this.db = db + } + save(sku: string, qty: number) { + return this.db.insert('orders', { sku, qty }) + } + saveItem(orderId: string, sku: string) { + return this.db.insert('order_items', { orderId, sku }) + } +} + +export class OrderService { + private repo: OrderRepo + constructor(repo: OrderRepo) { + this.repo = repo + } + create(input: { sku: string; qty: number }) { + return this.repo.save(input.sku, input.qty) + } + addItem(orderId: string, sku: string) { + return this.repo.saveItem(orderId, sku) + } +} diff --git a/graph/test/typescript/hono/cases/chains/same-name-unrelated/src/app.ts b/graph/test/typescript/hono/cases/chains/same-name-unrelated/src/app.ts new file mode 100644 index 000000000..2fbf1b4c9 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/same-name-unrelated/src/app.ts @@ -0,0 +1,32 @@ +import { Hono } from 'hono' +import { UserStore, AuditLog, saveAll } from './stores' + +type Env = { Variables: { users: UserStore } } + +const users = new UserStore() +const audit = new AuditLog() + +const app = new Hono() +app.use('/typed/*', async (c, next) => { + c.set('users', users) + await next() +}) +// a typed receiver: only UserStore.save +app.post('/typed/save', (c) => c.text(users.save('x'))) +// through the typed context: only UserStore.save +app.post('/typed/ctx', (c) => c.text(c.var.users.save('x'))) + +// untyped: the c.set value decides (UserStore under 'store'; the AuditLog under another key is not it) +const loose = new Hono() +loose.use('*', async (c: any, next) => { + c.set('store', new UserStore()) + c.set('log', new AuditLog()) + await next() +}) +loose.post('/save', (c: any) => c.text(c.get('store').save('y'))) +app.route('/loose', loose) + +// the positive control: an interface call reaches both implementations +app.post('/all', (c) => c.json(saveAll([users, audit], 'z'))) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/same-name-unrelated/src/stores.ts b/graph/test/typescript/hono/cases/chains/same-name-unrelated/src/stores.ts new file mode 100644 index 000000000..b3a883fb5 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/same-name-unrelated/src/stores.ts @@ -0,0 +1,23 @@ +// census: ctx_di, negative (SPEC R18-R21 negative controls) +// Two unrelated classes each declare `save()`. A call on a receiver whose type (or, untyped, whose c.set value) is +// one of them reaches ONLY that class's method: an edge to the other same-named method is a false edge. The +// positive control: a call through an interface both implement reaches both. +export interface Saver { + save(v: string): string +} + +export class UserStore implements Saver { + save(v: string) { + return `user ${v}` + } +} + +export class AuditLog implements Saver { + save(v: string) { + return `audit ${v}` + } +} + +export function saveAll(savers: Saver[], v: string) { + return savers.map((s) => s.save(v)) +} diff --git a/graph/test/typescript/hono/cases/chains/this-in-nested-arrows/src/app.ts b/graph/test/typescript/hono/cases/chains/this-in-nested-arrows/src/app.ts new file mode 100644 index 000000000..117084280 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/this-in-nested-arrows/src/app.ts @@ -0,0 +1,12 @@ +import { Hono } from 'hono' +import { Catalog, Resp } from './resp' + +const app = new Hono() +const catalog = new Catalog() +app.get('/prices', (c) => c.json(catalog.prices())) +app.get('/taxes', (c) => c.json(catalog.taxes())) +app.get('/rounded', (c) => c.json(catalog.rounded())) +app.get('/later', async (c) => c.json(await catalog.later())) +app.get('/fail', (c) => c.json(Resp.fail([{ path: ['a', 'b'] }]))) + +export default app diff --git a/graph/test/typescript/hono/cases/chains/this-in-nested-arrows/src/resp.ts b/graph/test/typescript/hono/cases/chains/this-in-nested-arrows/src/resp.ts new file mode 100644 index 000000000..e0b8e5838 --- /dev/null +++ b/graph/test/typescript/hono/cases/chains/this-in-nested-arrows/src/resp.ts @@ -0,0 +1,47 @@ +// census: this_arrow (SPEC R20; call-chain break class 4, "this inside a nested arrow") +// `this` inside an arrow function nested in a method, at depth 1, 2 and 3, and in an arrow inside a STATIC method +// (where `this` is the class), is the method's `this`: the calls reach the class's own members. +export class Resp { + private static norm(p: string[]) { + return p.join('.') + } + static fail(issues: Array<{ path: string[] }>) { + return issues.map((i) => ({ path: this.norm(i.path) })) + } +} + +export class Catalog { + items: string[] + constructor() { + this.items = ['a', 'b'] + } + price(item: string) { + return item.length + } + tax(n: number) { + return n / 10 + } + round(n: number) { + return Math.round(n) + } + // depth 1 + prices() { + return this.items.map((i) => this.price(i)) + } + // depth 2 + taxes() { + return this.items.map((i) => [i].map((j) => this.tax(this.price(j)))) + } + // depth 3 + rounded() { + return this.items.map((i) => [i].map((j) => [j].map((k) => this.round(this.tax(this.price(k)))))) + } + // an arrow stored in a local, then called + async later() { + const run = async () => { + const inner = () => this.price('late') + return inner() + } + return run() + } +} diff --git a/graph/test/typescript/hono/cases/compose/abstract-strategy-mount/src/index.ts b/graph/test/typescript/hono/cases/compose/abstract-strategy-mount/src/index.ts new file mode 100644 index 000000000..fd3b6d158 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/abstract-strategy-mount/src/index.ts @@ -0,0 +1,31 @@ +// census: route_mount_nonliteral (violation hono-2-01) +// Sub-apps returned by subclass overrides of an abstract method, mounted in a loop over a const map under a prefix +// made from the loop key: each is a mount argument (never a root). The map's entries are known, so each instance's +// own override runs under its own key (/oauth/callback, /password/login; the runtime half agrees). +import { Hono } from 'hono' + +abstract class Strategy { + abstract controller(): Hono +} +class OAuth extends Strategy { + controller(): Hono { + const h = new Hono() + h.get('/callback', (c) => c.text('cb')) + return h + } +} +class Password extends Strategy { + controller(): Hono { + const h = new Hono() + h.post('/login', (c) => c.text('in')) + return h + } +} + +const strategies: Record = { oauth: new OAuth(), password: new Password() } +const app = new Hono() +for (const [name, s] of Object.entries(strategies)) { + app.route(`/${name}`, s.controller()) +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/index.ts b/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/index.ts new file mode 100644 index 000000000..b821fe365 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/index.ts @@ -0,0 +1,10 @@ +// census: route_mount_literal (stress-4 mutation m30 shape; violation hono-4-06) +// The mounted app is an imported default re-exported under another name (`export { local as alias }`): it is the +// same app, mounted exactly at /api/search. +import { Hono } from 'hono' +import { searchApiRoutes } from './search' + +const app = new Hono() +app.route('/api/search', searchApiRoutes) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/search/index.ts b/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/search/index.ts new file mode 100644 index 000000000..626ef3134 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/search/index.ts @@ -0,0 +1,5 @@ +import searchApi from './routes/api' + +export const searchModule = { id: 'search', title: 'Search' } + +export { searchApi as searchApiRoutes } diff --git a/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/search/routes/api.ts b/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/search/routes/api.ts new file mode 100644 index 000000000..def4feab6 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/aliased-reexport-mount/src/search/routes/api.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const searchApi = new Hono() +searchApi.post('/', (c) => c.json({ hits: [] })) +searchApi.get('/suggest', (c) => c.json({ terms: [] })) + +export default searchApi diff --git a/graph/test/typescript/hono/cases/compose/async-wrapper-mount/src/main.ts b/graph/test/typescript/hono/cases/compose/async-wrapper-mount/src/main.ts new file mode 100644 index 000000000..73eedd238 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/async-wrapper-mount/src/main.ts @@ -0,0 +1,13 @@ +// census: bun_serve (stress-5 mutation m38 shape; violation hono-5-06) +// A sub-app passed to an async wrapper that mounts it under its own use('*') and returns the wrapper, which is +// served: the inner route is served by the wrapper, behind the wrapper's middleware. +import { Hono } from 'hono' +import { wrapApp } from './wrap' + +declare const Bun: { serve(o: { fetch: (r: Request) => Response | Promise; port: number }): void } + +const inner = new Hono() +inner.get('/hello', (c) => c.text('hi')) + +const app = await wrapApp(inner) +Bun.serve({ fetch: app.fetch, port: 3000 }) diff --git a/graph/test/typescript/hono/cases/compose/async-wrapper-mount/src/wrap.ts b/graph/test/typescript/hono/cases/compose/async-wrapper-mount/src/wrap.ts new file mode 100644 index 000000000..fdddbe825 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/async-wrapper-mount/src/wrap.ts @@ -0,0 +1,11 @@ +import { Hono } from 'hono' + +export async function wrapApp(inner: Hono): Promise { + const wrapper = new Hono() + wrapper.use('*', async (c, next) => { + c.header('x-wrapped', 'async') + await next() + }) + wrapper.route('/', inner) + return wrapper +} diff --git a/graph/test/typescript/hono/cases/compose/basepath-group/src/index.ts b/graph/test/typescript/hono/cases/compose/basepath-group/src/index.ts new file mode 100644 index 000000000..3b648a045 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/basepath-group/src/index.ts @@ -0,0 +1,13 @@ +// census: basepath +// basePath returns a NEW app sharing the route list: its routes get the prefix, the original app's do not. +import { Hono } from 'hono' + +const app = new Hono() +const api = app.basePath('/api') +const v2 = api.basePath('/v2') + +app.get('/', (c) => c.text('root has no prefix')) +api.get('/status', (c) => c.text('under /api')) +v2.get('/status', (c) => c.text('under /api/v2')) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/basepath-sub-mounted/src/index.ts b/graph/test/typescript/hono/cases/compose/basepath-sub-mounted/src/index.ts new file mode 100644 index 000000000..73eb597a5 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/basepath-sub-mounted/src/index.ts @@ -0,0 +1,11 @@ +// census: basepath, route_mount_literal +// A sub-app built with basePath, then mounted: prefix + basePath + local path. +import { Hono } from 'hono' + +const v1 = new Hono().basePath('/v1') +v1.get('/ping', (c) => c.text('pong')) + +const app = new Hono() +app.route('/svc', v1) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/builder-called-twice/src/main.ts b/graph/test/typescript/hono/cases/compose/builder-called-twice/src/main.ts new file mode 100644 index 000000000..50910e12a --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/builder-called-twice/src/main.ts @@ -0,0 +1,15 @@ +// census: app_factory_fn (violation hono-2-02, SPEC R6; oracle gap O9) +// One helper creates the root AND the sub-app: two apps, two route lists. The sub-app's route is mounted +// under a prefix known only at run time, so it is partial, never a root route. +import { makeApp } from './routes' +import { UserRoutes } from './users' + +declare const process: { env: Record } + +const app = makeApp() +app.get('/logo.png', (c) => c.text('png')) +for (const group of [new UserRoutes()]) { + app.route(group.prefix(process.env.API_VERSION ?? 'v1'), group.build()) +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/builder-called-twice/src/routes.ts b/graph/test/typescript/hono/cases/compose/builder-called-twice/src/routes.ts new file mode 100644 index 000000000..3ad1649df --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/builder-called-twice/src/routes.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +export function makeApp(opts?: { base?: string }) { + const r = new Hono() + if (opts?.base) { + r.basePath(opts.base) + } + return r +} diff --git a/graph/test/typescript/hono/cases/compose/builder-called-twice/src/users.ts b/graph/test/typescript/hono/cases/compose/builder-called-twice/src/users.ts new file mode 100644 index 000000000..5116c2ac5 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/builder-called-twice/src/users.ts @@ -0,0 +1,12 @@ +import { makeApp } from './routes' + +export class UserRoutes { + private routes = makeApp({ base: '/users' }) + prefix(version: string) { + return `/${version}/users` + } + build() { + this.routes.post('/import', (c) => c.text('ok')) + return this.routes + } +} diff --git a/graph/test/typescript/hono/cases/compose/declarative-routes-const/src/index.ts b/graph/test/typescript/hono/cases/compose/declarative-routes-const/src/index.ts new file mode 100644 index 000000000..0b67e1cc8 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/declarative-routes-const/src/index.ts @@ -0,0 +1,24 @@ +// census: route_mount_literal (SPEC R13: a const array of { path, handler } mounted in a loop) +// Declarative routes in a const array literal, mounted by `app.route(r.path, r.handler)` over that array: exact +// routes at the listed paths. A menu list of { path, label } that nothing mounts gives nothing. +import { Hono } from 'hono' + +const tickets = new Hono().get('/', (c) => c.json([])) +const tags = new Hono().get('/:tag', (c) => c.text(c.req.param('tag'))) + +const routes = [ + { path: '/tickets', handler: tickets }, + { path: '/tags', handler: tags }, +] + +export const menu = [ + { path: '/admin/tickets', label: 'Tickets' }, + { path: '/admin/tags', label: 'Tags' }, +] + +const app = new Hono() +for (const r of routes) { + app.route(r.path, r.handler) +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/app.ts b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/app.ts new file mode 100644 index 000000000..0c617e00f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/app.ts @@ -0,0 +1,13 @@ +import { Hono } from 'hono' +import { mountPlugin } from './mount' +import { inboxPlugin } from './plugins/inbox' + +declare const settings: { disabled: Set } + +const app = new Hono() +app.get('/', (c) => c.text('home')) +for (const p of [inboxPlugin].filter((x) => !settings.disabled.has(x.name))) { + mountPlugin(app, p) +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/mount.test.ts b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/mount.test.ts new file mode 100644 index 000000000..f18c4236e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/mount.test.ts @@ -0,0 +1,29 @@ +// census: app_request_test (SPEC R13 / R13b; violation hono-4-09 and its silent menu-list control) +// Declarative `{ path, handler }` routes whose list is reordered or filtered at run time (a priority sort, a settings +// filter): the handler apps are mounted at their element path, EXACT (R13b; conditional_registration where the list +// is filtered), never roots at `/`. The `{ path, label }` menu entries are mounted by nothing and produce nothing. +import { Hono } from 'hono' +import { mountPlugin, type MountablePlugin } from './mount' + +declare function it(name: string, fn: () => unknown): void + +function makeRoute(label: string): Hono { + const r = new Hono() + r.get('/', (c) => c.text(label)) + return r +} + +it('mounts one declarative route', async () => { + const app = new Hono() + const plugin: MountablePlugin = { + name: 'solo', + routes: [{ path: '/solo', handler: makeRoute('solo-ok') }], + menu: [{ path: '/admin/solo', label: 'Solo' }], + } + mountPlugin(app, plugin) +}) + +it('mounts an inline sub-app', async () => { + const app = new Hono() + mountPlugin(app, { name: 'inline', routes: [{ path: '/inline', handler: new Hono().get('/', (c) => c.text('in')) }] }) +}) diff --git a/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/mount.ts b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/mount.ts new file mode 100644 index 000000000..d596826fa --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/mount.ts @@ -0,0 +1,27 @@ +import type { Hono } from 'hono' + +export interface MountableRoute { + path: string + handler: Hono + priority?: number +} +export interface MountablePlugin { + name: string + routes?: MountableRoute[] + menu?: { path: string; label: string }[] +} + +function byPriority(routes: MountableRoute[]): MountableRoute[] { + return routes + .map((route, index) => ({ route, index })) + .sort((a, b) => (b.route.priority ?? 0) - (a.route.priority ?? 0) || a.index - b.index) + .map((entry) => entry.route) +} + +// mounts a plugin's declarative routes in priority order (decided at run time) +export function mountPlugin(app: Hono, plugin: MountablePlugin) { + for (const route of byPriority(plugin.routes ?? [])) { + if (!route.path || !route.handler) continue + app.route(route.path, route.handler) + } +} diff --git a/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/plugins/inbox.ts b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/plugins/inbox.ts new file mode 100644 index 000000000..27113adae --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/declarative-routes-derived/src/plugins/inbox.ts @@ -0,0 +1,10 @@ +import { Hono } from 'hono' +import type { MountablePlugin } from '../mount' + +const inboxApi = new Hono().get('/', (c) => c.json([])) + +export const inboxPlugin: MountablePlugin = { + name: 'inbox', + routes: [{ path: '/api/inbox', handler: inboxApi }], + menu: [{ path: '/admin/inbox', label: 'Inbox' }], +} diff --git a/graph/test/typescript/hono/cases/compose/discarded-basepath/src/index.ts b/graph/test/typescript/hono/cases/compose/discarded-basepath/src/index.ts new file mode 100644 index 000000000..08a03f31a --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/discarded-basepath/src/index.ts @@ -0,0 +1,13 @@ +// census: basepath (SPEC 2 [iter2]: a helper that discards basePath()'s result) +// basePath returns a NEW app; calling it as a statement changes nothing for later routes. +import { Hono } from 'hono' + +function withVersion(app: Hono, version: string) { + app.basePath(`/${version}`) + return app +} + +const app = withVersion(new Hono(), 'v2') +app.get('/items', (c) => c.json([])) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/dynamic-prefix/src/index.ts b/graph/test/typescript/hono/cases/compose/dynamic-prefix/src/index.ts new file mode 100644 index 000000000..954c98d72 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/dynamic-prefix/src/index.ts @@ -0,0 +1,13 @@ +// census: route_mount_nonliteral +// A mount prefix known only at run time is declared undetermined, never guessed. +import { Hono } from 'hono' + +const tenants = new Hono() +tenants.get('/dashboard', (c) => c.text('dash')) + +const prefix = ['/t', String(Date.now() % 3)].join('') +const app = new Hono() +app.route(prefix, tenants) +app.get('/static', (c) => c.text('static')) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/factory-basepath/src/index.ts b/graph/test/typescript/hono/cases/compose/factory-basepath/src/index.ts new file mode 100644 index 000000000..5eac3e6ad --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/factory-basepath/src/index.ts @@ -0,0 +1,12 @@ +// census: app_factory_fn, basepath (violation hono-1-02) +// An app returned from a function through basePath keeps its base: GET /v1/ping, and no base-less twin. +import { Hono } from 'hono' + +function makeServer() { + return new Hono().basePath('/v1') +} + +const srv = makeServer() +srv.get('/ping', (c) => c.text('pong')) + +export default srv diff --git a/graph/test/typescript/hono/cases/compose/factory-fn/src/app.ts b/graph/test/typescript/hono/cases/compose/factory-fn/src/app.ts new file mode 100644 index 000000000..42e0a469a --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/factory-fn/src/app.ts @@ -0,0 +1,11 @@ +import { Hono } from 'hono' + +export function createRouter() { + return new Hono() +} + +export function createApp() { + const app = createRouter() + app.get('/ready', (c) => c.text('ready')) + return app +} diff --git a/graph/test/typescript/hono/cases/compose/factory-fn/src/index.ts b/graph/test/typescript/hono/cases/compose/factory-fn/src/index.ts new file mode 100644 index 000000000..d143ad522 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/factory-fn/src/index.ts @@ -0,0 +1,10 @@ +// census: app_factory_fn +// Apps produced by project factory functions (a factory calling a factory) are app values. +import { createApp, createRouter } from './app' + +const app = createApp() +const items = createRouter() +items.get('/', (c) => c.json([])) +app.route('/items', items) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/field-app-class/src/routes/health.ts b/graph/test/typescript/hono/cases/compose/field-app-class/src/routes/health.ts new file mode 100644 index 000000000..4a77d84e8 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/field-app-class/src/routes/health.ts @@ -0,0 +1,3 @@ +import { Hono } from 'hono' + +export const health = new Hono().get('/', (c) => c.text('ok')) diff --git a/graph/test/typescript/hono/cases/compose/field-app-class/src/routes/users.ts b/graph/test/typescript/hono/cases/compose/field-app-class/src/routes/users.ts new file mode 100644 index 000000000..f7d8678ec --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/field-app-class/src/routes/users.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +export class UsersRoute { + getRoutes() { + const r = new Hono() + r.get('/:id', (c) => c.json({ id: c.req.param('id') })) + return r + } +} diff --git a/graph/test/typescript/hono/cases/compose/field-app-class/src/server.ts b/graph/test/typescript/hono/cases/compose/field-app-class/src/server.ts new file mode 100644 index 000000000..6baaec09f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/field-app-class/src/server.ts @@ -0,0 +1,31 @@ +// census: route_mount_literal, app_factory_fn (SPEC 2 [iter2] flow through fields; a class whose +// app lives in a field, registrations in setupRoutes() called from the constructor, a mount argument built by a method) +import { Hono } from 'hono' +import { health } from './routes/health' +import { UsersRoute } from './routes/users' + +function createApp() { + return new Hono().basePath('/v1') +} + +export class Server { + private app: ReturnType + private extra: Hono = new Hono() + + constructor() { + this.app = createApp() + this.setupRoutes() + } + + private setupRoutes() { + this.app.route('/health', health) + this.app.route('/users', new UsersRoute().getRoutes()) + this.extra.get('/extra', (c) => c.text('extra')) + } + + get fetch() { + return this.app.fetch + } +} + +export const server = new Server() diff --git a/graph/test/typescript/hono/cases/compose/filtered-instance-loop/src/index.ts b/graph/test/typescript/hono/cases/compose/filtered-instance-loop/src/index.ts new file mode 100644 index 000000000..3876435a1 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/filtered-instance-loop/src/index.ts @@ -0,0 +1,31 @@ +// census: route_mount_root (stress-5 mutation m36 shape; violation hono-5-01, SPEC R13b) +// A loop over a FILTERED list of known class instances mounts each one's `routes()` at a literal prefix: exact +// routes (the path is right whenever the module is enabled), each with conditional_registration. +import { Hono } from 'hono' + +declare const process: { env: Record } + +class Accounts { + routes(): Hono { + const h = new Hono() + h.get('/accounts', (c) => c.text('accounts')) + return h + } +} +class Invoices { + routes(): Hono { + const h = new Hono() + h.get('/invoices', (c) => c.text('invoices')) + return h + } +} + +const enabled = (process.env.MODULES ?? '').split(',') +const modules = [new Accounts(), new Invoices()].filter((m) => enabled.includes(m.constructor.name)) + +const app = new Hono() +app.get('/', (c) => c.text('home')) +for (const m of modules) { + app.route('/', m.routes()) +} +export default app diff --git a/graph/test/typescript/hono/cases/compose/foreign-mount/src/index.ts b/graph/test/typescript/hono/cases/compose/foreign-mount/src/index.ts new file mode 100644 index 000000000..d327a0710 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/foreign-mount/src/index.ts @@ -0,0 +1,13 @@ +// census: mount_foreign +// mount() hands a prefix to a foreign fetch handler: verb ANY, path prefix/*, handler the function. +import { Hono } from 'hono' + +function legacyFetch(req: Request): Response { + return new Response('legacy ' + req.url) +} + +const app = new Hono() +app.mount('/legacy', legacyFetch) +app.get('/new', (c) => c.text('new')) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/getter-prefix-typed-holder/src/index.ts b/graph/test/typescript/hono/cases/compose/getter-prefix-typed-holder/src/index.ts new file mode 100644 index 000000000..d27ff3685 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/getter-prefix-typed-holder/src/index.ts @@ -0,0 +1,48 @@ +// census: prop_receiver_route (stress-4 mutation m25 shape; SPEC R2, hono-2-04 residue) +// A controller app mounted on a typed context holder at a prefix read through a getter of run-time config: +// ONE partial per route, never an exact row, never one row per hole depth. +import { Hono } from 'hono' + +class BaseController { + protected create(): Hono { + return BaseController.createServer() + } + static createServer(): Hono { + return new Hono() + } + getController(): Hono { + return this.create() + } +} + +class AssetsController extends BaseController { + override getController() { + const hono = this.create() + hono.delete('/asset/:name', (c) => c.body(null, 204)) + hono.get('/asset/:name', (c) => c.text(c.req.param('name'))) + return hono + } +} + +interface ServerCtx { + server: Hono +} + +class AssetsModule { + private ctx: ServerCtx + private config: { mountAt: string } + constructor(ctx: ServerCtx, config: { mountAt: string }) { + this.ctx = ctx + this.config = config + } + get mountAt() { + return this.config.mountAt + } + build() { + this.ctx.server.route(this.mountAt, new AssetsController().getController()) + } +} + +export function boot(ctx: ServerCtx, cfg: { mountAt: string }) { + new AssetsModule(ctx, cfg).build() +} diff --git a/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/env.ts b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/env.ts new file mode 100644 index 000000000..c42a6ab20 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/env.ts @@ -0,0 +1,7 @@ +// the bundler's typing of import.meta.glob (a project declaration, as a vite-env file would add it) +declare global { + interface ImportMeta { + glob>(pattern: string | string[], options?: { eager?: boolean }): Record + } +} +export {} diff --git a/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/index.ts b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/index.ts new file mode 100644 index 000000000..52132f2a0 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/index.ts @@ -0,0 +1,13 @@ +// census: route_mount_root (SPEC R12.1; oracle note O28: a brace alternative holding a `*` crashed the oracle) +// The glob's brace alternatives are globs themselves: `memory` literally, `*-store` by wildcard. Control: the +// legacy store matches neither alternative: it stays its own exported app (GET /legacy), never under /stores. +import { Hono } from 'hono' + +const stores = import.meta.glob<{ default: Hono }>('./stores/{memory,*-store}/routes.ts', { eager: true }) + +const app = new Hono() +for (const mod of Object.values(stores)) { + app.route('/stores', mod.default) +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/disk-store/routes.ts b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/disk-store/routes.ts new file mode 100644 index 000000000..b680d8313 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/disk-store/routes.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const store = new Hono() +store.get('/disk', (c) => c.text('disk-store')) + +export default store diff --git a/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/legacy/routes.ts b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/legacy/routes.ts new file mode 100644 index 000000000..a105ff83e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/legacy/routes.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const store = new Hono() +store.get('/legacy', (c) => c.text('legacy')) + +export default store diff --git a/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/memory/routes.ts b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/memory/routes.ts new file mode 100644 index 000000000..199f1cb23 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/memory/routes.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const store = new Hono() +store.get('/memory', (c) => c.text('memory')) + +export default store diff --git a/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/remote-store/routes.ts b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/remote-store/routes.ts new file mode 100644 index 000000000..578327247 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-brace-alternatives/src/stores/remote-store/routes.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const store = new Hono() +store.get('/remote', (c) => c.text('remote-store')) + +export default store diff --git a/graph/test/typescript/hono/cases/compose/glob-module-list/src/env.ts b/graph/test/typescript/hono/cases/compose/glob-module-list/src/env.ts new file mode 100644 index 000000000..c42a6ab20 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-module-list/src/env.ts @@ -0,0 +1,7 @@ +// the bundler's typing of import.meta.glob (a project declaration, as a vite-env file would add it) +declare global { + interface ImportMeta { + glob>(pattern: string | string[], options?: { eager?: boolean }): Record + } +} +export {} diff --git a/graph/test/typescript/hono/cases/compose/glob-module-list/src/index.ts b/graph/test/typescript/hono/cases/compose/glob-module-list/src/index.ts new file mode 100644 index 000000000..1e68c5278 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-module-list/src/index.ts @@ -0,0 +1,25 @@ +// census: route_mount_root (SPEC R12.1; QD16 shape: a tier app mounting `mod.default` over a literal glob) +// import.meta.glob with a literal pattern is resolved against the files: every matched module's default-exported +// app is mounted by the loop's route() (eager by for..of over Object.values, lazy by awaiting each loader). +import { Hono } from 'hono' + +const eagerRoutes = import.meta.glob<{ default: Hono }>('./routes/**/*.index.ts', { eager: true }) +const lazyPages = import.meta.glob<() => Promise<{ default: Hono }>>('./lazy/*.page.ts') + +const api = new Hono() +for (const mod of Object.values(eagerRoutes)) { + api.route('/', mod.default) +} + +export async function mountPages(app: Hono) { + for (const key in lazyPages) { + const mod = await lazyPages[key]() + app.route('/pages', mod.default) + } +} + +const app = new Hono() +app.route('/api', api) +await mountPages(app) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/glob-module-list/src/lazy/reports.page.ts b/graph/test/typescript/hono/cases/compose/glob-module-list/src/lazy/reports.page.ts new file mode 100644 index 000000000..48a58236a --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-module-list/src/lazy/reports.page.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const reports = new Hono() +reports.get('/daily', (c) => c.json([])) + +export default reports diff --git a/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/orders/helpers.ts b/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/orders/helpers.ts new file mode 100644 index 000000000..792c67475 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/orders/helpers.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +// not matched by the glob (*.index.ts): an app nothing mounts stays what it is (a root) +const scratch = new Hono() +scratch.get('/scratch', (c) => c.text('scratch')) + +export default scratch diff --git a/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/orders/orders.index.ts b/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/orders/orders.index.ts new file mode 100644 index 000000000..0060860ca --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/orders/orders.index.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const orders = new Hono() +orders.post('/orders', (c) => c.json({ ok: true }, 201)) + +export default orders diff --git a/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/users/users.index.ts b/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/users/users.index.ts new file mode 100644 index 000000000..fa3fb0223 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/glob-module-list/src/routes/users/users.index.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const users = new Hono() +users.get('/users', (c) => c.json([])) +users.get('/users/:id', (c) => c.json({ id: c.req.param('id') })) + +export default users diff --git a/graph/test/typescript/hono/cases/compose/late-sub-registration/src/index.ts b/graph/test/typescript/hono/cases/compose/late-sub-registration/src/index.ts new file mode 100644 index 000000000..c80d1186c --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/late-sub-registration/src/index.ts @@ -0,0 +1,14 @@ +// census: route_mount_literal +// route() copies the sub-app's routes AT THE CALL: a registration on the sub-app after the mount +// is not served under the prefix. +import { Hono } from 'hono' + +const sub = new Hono() +sub.get('/early', (c) => c.text('mounted')) + +const app = new Hono() +app.route('/sub', sub) + +sub.get('/late', (c) => c.text('registered after the mount: not under /sub')) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/let-rebase-conditional/src/index.ts b/graph/test/typescript/hono/cases/compose/let-rebase-conditional/src/index.ts new file mode 100644 index 000000000..ec61f8e7d --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/let-rebase-conditional/src/index.ts @@ -0,0 +1,29 @@ +// census: basepath (SPEC R8a/R8b, oracle note O27: a module-level app variable rebased under a condition) +// `let app = new Hono(); if (base) app = app.basePath(base)`: the routes registered through `app` afterwards are +// served at `/...` when the variable is set and at `/...` when it is not, so neither exact path is known: +// every route on it is partial (dynamic_mount_prefix), never exact. The same holds for a LITERAL base behind a +// condition (`legacy`). A route registered BEFORE the rebase is on the un-rebased app and stays exact. +import { Hono } from 'hono' + +declare const process: { env: Record } + +const users = new Hono() +users.get('/:id', (c) => c.text(c.req.param('id'))) + +let app = new Hono() +app.get('/health', (c) => c.text('ok')) +const base = process.env.API_BASE +if (base) { + app = app.basePath(base) +} +app.get('/version', (c) => c.text('1')) +app.route('/users', users) + +let legacy = new Hono() +if (process.env.LEGACY_PREFIX === 'on') { + legacy = legacy.basePath('/v1') +} +legacy.get('/ping', (c) => c.text('pong')) + +export { legacy } +export default app diff --git a/graph/test/typescript/hono/cases/compose/let-rebase-literal/src/index.ts b/graph/test/typescript/hono/cases/compose/let-rebase-literal/src/index.ts new file mode 100644 index 000000000..a1fa34e69 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/let-rebase-literal/src/index.ts @@ -0,0 +1,15 @@ +// census: basepath (SPEC R8a/R8b control: an app variable re-pointed at a LITERAL basePath with no condition) +// `let app = new Hono(); app = app.basePath('/api')` always runs, so the base is known: every route registered through +// `app` afterwards is exact under /api; the one registered before the reassignment stays at its own path. +import { Hono } from 'hono' + +const users = new Hono() +users.get('/:id', (c) => c.text(c.req.param('id'))) + +let app = new Hono() +app.get('/health', (c) => c.text('ok')) +app = app.basePath('/api') +app.get('/version', (c) => c.text('1')) +app.route('/users', users) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/lib-dirs/src/index.ts b/graph/test/typescript/hono/cases/compose/lib-dirs/src/index.ts new file mode 100644 index 000000000..a2bf7d373 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/lib-dirs/src/index.ts @@ -0,0 +1,8 @@ +// census: route_mount_literal (project sources under lib/ and libs/, a common monorepo layout) +// A project path that starts with lib/ or libs/ is project code, not a library key. +import { app } from './lib/app' +import { users } from './libs/users/routes' + +app.route('/users', users) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/lib-dirs/src/lib/app.ts b/graph/test/typescript/hono/cases/compose/lib-dirs/src/lib/app.ts new file mode 100644 index 000000000..564eeb5f4 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/lib-dirs/src/lib/app.ts @@ -0,0 +1,4 @@ +import { Hono } from 'hono' + +export const app = new Hono() +app.get('/from-lib', (c) => c.text('declared under lib/')) diff --git a/graph/test/typescript/hono/cases/compose/lib-dirs/src/libs/users/routes.ts b/graph/test/typescript/hono/cases/compose/lib-dirs/src/libs/users/routes.ts new file mode 100644 index 000000000..f7216bf3b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/lib-dirs/src/libs/users/routes.ts @@ -0,0 +1,4 @@ +import { Hono } from 'hono' + +export const users = new Hono() +users.get('/:id', (c) => c.json({ id: c.req.param('id') })) diff --git a/graph/test/typescript/hono/cases/compose/literal-prefix-method/src/index.ts b/graph/test/typescript/hono/cases/compose/literal-prefix-method/src/index.ts new file mode 100644 index 000000000..7761ef5b4 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/literal-prefix-method/src/index.ts @@ -0,0 +1,41 @@ +// census: mount_dynamic_prefix_call (violation hono-3-05, SPEC 3.2 G8) +// The mount prefix comes from a zero-argument method that returns a literal: it is that constant, so the routes +// are exact under /console. A method that builds its prefix from a field stays dynamic. +import { Hono } from 'hono' + +class ConsoleRoutes { + private hono = new Hono() + constructor() { + this.hono.get('/login', (c) => c.text('login')) + this.hono.get('/home', (c) => c.text('home')) + } + getBasePath(): string { + return '/console' + } + getRoutes() { + return this.hono + } +} + +class VersionedRoutes { + private hono = new Hono() + private version: string + constructor(version: string) { + this.version = version + this.hono.get('/items', (c) => c.json([])) + } + getBasePath(): string { + return `/${this.version}` + } + getRoutes() { + return this.hono + } +} + +const app = new Hono() +const ui = new ConsoleRoutes() +app.route(ui.getBasePath(), ui.getRoutes()) +const v = new VersionedRoutes(String(Date.now())) +app.route(v.getBasePath(), v.getRoutes()) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/loop-mount-method-fallback/src/index.ts b/graph/test/typescript/hono/cases/compose/loop-mount-method-fallback/src/index.ts new file mode 100644 index 000000000..6c3e98104 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/loop-mount-method-fallback/src/index.ts @@ -0,0 +1,43 @@ +// census: mount_dynamic_prefix_call (stress-4 mutation m29 shape; violation hono-4-05) +// A loop mounts the elements of a const list by method calls whose prefix depends on a run-time version; another +// class with methods of the same names is mounted exactly elsewhere. Only the loop's element class is partial. +import { Hono } from 'hono' + +declare const process: { env: Record } + +class HealthRoutes { + private hono = new Hono() + constructor() { + this.hono.get('/health', (c) => c.text('ok')) + } + getBasePath(version: string) { + return `/${version}/ops` + } + getRoutes() { + return this.hono + } +} + +class AdminRoutes { + private hono = new Hono() + constructor() { + this.hono.get('/signin', (c) => c.text('signin')) + } + getBasePath() { + return '/admin' + } + getRoutes() { + return this.hono + } +} + +const VERSION = process.env.API_VERSION ?? 'v1' +const app = new Hono() +const versioned = [new HealthRoutes()] +for (const r of versioned) { + app.route(r.getBasePath(VERSION), r.getRoutes()) +} +const admin = new AdminRoutes() +app.route(admin.getBasePath(), admin.getRoutes()) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/index.ts b/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/index.ts new file mode 100644 index 000000000..04668caed --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/index.ts @@ -0,0 +1,17 @@ +// census: mount_dynamic_prefix_call (violation hono-5-03) +// A loop over a const list of route groups mounts `g.build()` at `g.prefix(V)`, a method whose template only uses +// its argument, called with a const: the prefix is /v2/members, and the routes are exact (a discarded basePath in +// the factory changes nothing). +import { makeApp } from './routes' +import { MemberRoutes } from './members' + +declare const Deno: { serve(o: { port: number }, h: (r: Request) => Response | Promise): void } + +const V = 'v2' +const app = makeApp() +const groups = [new MemberRoutes()] +for (const g of groups) { + app.route(g.prefix(V), g.build()) +} +app.get('/logo.png', (c) => c.text('img')) +Deno.serve({ port: 3000 }, app.fetch) diff --git a/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/members.ts b/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/members.ts new file mode 100644 index 000000000..a5a33bd3c --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/members.ts @@ -0,0 +1,13 @@ +import { makeApp } from './routes' + +export class MemberRoutes { + private routes = makeApp({ base: '/members' }) + prefix(v: string) { + return `/${v}/members` + } + build() { + this.routes.post('/import', (c) => c.text('ok')) + this.routes.get('/:id', (c) => c.text(c.req.param('id'))) + return this.routes + } +} diff --git a/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/routes.ts b/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/routes.ts new file mode 100644 index 000000000..3ad1649df --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/method-prefix-const-list/src/routes.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +export function makeApp(opts?: { base?: string }) { + const r = new Hono() + if (opts?.base) { + r.basePath(opts.base) + } + return r +} diff --git a/graph/test/typescript/hono/cases/compose/mount-arg-never-root/src/index.ts b/graph/test/typescript/hono/cases/compose/mount-arg-never-root/src/index.ts new file mode 100644 index 000000000..aeca873e0 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/mount-arg-never-root/src/index.ts @@ -0,0 +1,13 @@ +// census: neg_route_on_nonhono, route_mount_literal (SPEC 2 [iter2]: a mount argument is never a root) +// `.route(p, B)` on a receiver that is not recognised as an app: B (a real Hono app) is not served bare; its +// route is partial with unresolved_mount. A `.route()` whose argument is not an app produces nothing. +import { Hono } from 'hono' + +const reports = new Hono() +reports.get('/daily', (c) => c.text('daily')) + +declare const registry: { route(prefix: string, app: unknown): void } +registry.route('/reports', reports) + +const workflow = { route(name: string, step: () => void) { step() } } +workflow.route('/not-an-app', () => {}) diff --git a/graph/test/typescript/hono/cases/compose/mount-chain/src/index.ts b/graph/test/typescript/hono/cases/compose/mount-chain/src/index.ts new file mode 100644 index 000000000..2b10210c1 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/mount-chain/src/index.ts @@ -0,0 +1,17 @@ +// census: mount_foreign, use_scoped (oracle gap O8) +// A mount() handler is a route (ANY prefix/*) with a middleware chain like any other route. +import { Hono } from 'hono' +import { cors } from 'hono/cors' +import type { MiddlewareHandler } from 'hono' + +const legacyAuth: MiddlewareHandler = async (c, next) => { await next() } +function legacyFetch(req: Request): Response { + return new Response('legacy ' + req.url) +} + +const app = new Hono() +app.use(cors()) +app.use('/legacy/*', legacyAuth) +app.mount('/legacy', legacyFetch) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/nested-three-deep/src/api.ts b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/api.ts new file mode 100644 index 000000000..70781f44e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/api.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' +import { posts } from './posts' + +export const api = new Hono().basePath('/api') + +api.route('/posts', posts) diff --git a/graph/test/typescript/hono/cases/compose/nested-three-deep/src/comments.ts b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/comments.ts new file mode 100644 index 000000000..ad7968f09 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/comments.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +export const comments = new Hono() + +comments.get('/', (c) => c.json([])) +comments.delete('/:commentId', (c) => c.body(null, 204)) diff --git a/graph/test/typescript/hono/cases/compose/nested-three-deep/src/index.ts b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/index.ts new file mode 100644 index 000000000..ff6b94fa3 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/index.ts @@ -0,0 +1,10 @@ +// census: route_mount_literal, basepath +// Three levels of route() across modules, named exports, a basePath at the middle level, mounted at /. +import { Hono } from 'hono' +import { api } from './api' + +const app = new Hono() + +app.route('/', api) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/nested-three-deep/src/posts.ts b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/posts.ts new file mode 100644 index 000000000..0807e2898 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/nested-three-deep/src/posts.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' +import { comments } from './comments' + +export const posts = new Hono() + +posts.get('/:postId', (c) => c.json({})) +posts.route('/:postId/comments', comments) diff --git a/graph/test/typescript/hono/cases/compose/opaque-module-list/src/routes/billing.ts b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/routes/billing.ts new file mode 100644 index 000000000..07da1c383 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/routes/billing.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const billing = new Hono() +billing.get('/invoices', (c) => c.json([])) + +export default billing diff --git a/graph/test/typescript/hono/cases/compose/opaque-module-list/src/routes/status.ts b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/routes/status.ts new file mode 100644 index 000000000..e16c7c4c6 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/routes/status.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const status = new Hono() +status.get('/status', (c) => c.text('up')) + +export default status diff --git a/graph/test/typescript/hono/cases/compose/opaque-module-list/src/server.ts b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/server.ts new file mode 100644 index 000000000..a57fcf609 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/server.ts @@ -0,0 +1,20 @@ +// census: route_mount_root (SPEC R12.2: an opaque run-time module list) +// The server mounts `mod.default` for every file a directory listing finds at run time. A default-exported app that +// nothing imports, mounts or serves may be one of them: partial (unresolved_mount), never an exact root. The server's +// own app, an imported app and a separately served worker are unaffected. +import { Hono } from 'hono' +import shared from './shared' + +declare function listRouteFiles(dir: string): Promise + +const app = new Hono() +app.route('/', shared) + +export async function loadRoutes(dir: string) { + for (const file of await listRouteFiles(dir)) { + const mod = await import(file) + app.route('/', mod.default) + } +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/opaque-module-list/src/shared.ts b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/shared.ts new file mode 100644 index 000000000..cd5fc3867 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/shared.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +// imported by the server: not a module-list candidate, mounted exactly +const shared = new Hono() +shared.get('/version', (c) => c.text('1')) + +export default shared diff --git a/graph/test/typescript/hono/cases/compose/opaque-module-list/src/worker.ts b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/worker.ts new file mode 100644 index 000000000..21a0b0f2b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/opaque-module-list/src/worker.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +// a separate worker served on its own (its fetch is read): a served root, never a candidate +const worker = new Hono() +worker.get('/tick', (c) => c.text('tick')) + +export default { fetch: worker.fetch } diff --git a/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/cli.ts b/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/cli.ts new file mode 100644 index 000000000..c7b281a6e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/cli.ts @@ -0,0 +1,39 @@ +// a command-line builder chained two dozen times at module level: linear work, not one evaluation per path +export class Command { + private flags: string[] = [] + command(name: string): Command { + this.flags.push(name) + return this + } + option(flag: string, help: string): Command { + this.flags.push(flag + ' ' + help) + return this + } +} + +export const deploy = new Command() + .command('deploy') + .option('--flag-0', 'flag 0') + .option('--flag-1', 'flag 1') + .option('--flag-2', 'flag 2') + .option('--flag-3', 'flag 3') + .option('--flag-4', 'flag 4') + .option('--flag-5', 'flag 5') + .option('--flag-6', 'flag 6') + .option('--flag-7', 'flag 7') + .option('--flag-8', 'flag 8') + .option('--flag-9', 'flag 9') + .option('--flag-10', 'flag 10') + .option('--flag-11', 'flag 11') + .option('--flag-12', 'flag 12') + .option('--flag-13', 'flag 13') + .option('--flag-14', 'flag 14') + .option('--flag-15', 'flag 15') + .option('--flag-16', 'flag 16') + .option('--flag-17', 'flag 17') + .option('--flag-18', 'flag 18') + .option('--flag-19', 'flag 19') + .option('--flag-20', 'flag 20') + .option('--flag-21', 'flag 21') + .option('--flag-22', 'flag 22') + .option('--flag-23', 'flag 23') diff --git a/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/index.ts b/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/index.ts new file mode 100644 index 000000000..65c4b0628 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/index.ts @@ -0,0 +1,21 @@ +// census: new_hono_inside_function (oracle gap O15) +// A large project's oracle run overflowed the stack on a destructure-and-rebuild cycle (saver.ts), and did not finish +// in 45 minutes on a long builder chain (cli.ts). The oracle must terminate, declare the value unknown, and still give +// the routes and middleware of the app around it. +import { Hono } from 'hono' +import { Saver, resume } from './saver' +import './cli' + +const saver = new Saver() + +const app = new Hono<{ Variables: { saver: Saver } }>() +app.use('/threads/*', async (c, next) => { + c.set('saver', saver) + await next() +}) +app.post('/threads/:id/resume', async (c) => { + const cfg = await resume(c.get('saver'), { configurable: { thread: c.req.param('id'), ns: '' } }) + return c.json(cfg) +}) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/saver.ts b/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/saver.ts new file mode 100644 index 000000000..724e86ac2 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/oracle-eval-cycle/src/saver.ts @@ -0,0 +1,24 @@ +export interface Configurable { + thread: string + ns: string + id?: string +} +export interface Cfg { + configurable: Configurable +} + +// destructures its argument and hands back an object built from those names: called on its own result, every +// read of `thread` goes through the previous call's object (an evaluation cycle for a naive evaluator) +export class Saver { + async put(config: Cfg, id: string): Promise { + const { thread, ns } = config.configurable + const next: Cfg = { configurable: { thread, ns, id } as Configurable } + return next + } +} + +export async function resume(saver: Saver, config: Cfg) { + const first = await saver.put(config, 'a') + const second = await saver.put(first, 'b') + return saver.put(second, 'c') +} diff --git a/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/partial-paths b/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/partial-paths new file mode 100644 index 000000000..a2ca2b11d --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/partial-paths @@ -0,0 +1 @@ +opt-in: compare the known path of every partial route (ppath rows; oracle --partial-paths) diff --git a/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/src/main.ts b/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/src/main.ts new file mode 100644 index 000000000..19a634857 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/src/main.ts @@ -0,0 +1,25 @@ +// census: route_mount_nonliteral, use_scoped, use_global (violation hono-7-05: a partial route whose unknown piece +// is in the MIDDLE of the path) +// The mount prefix is a template: the version is a const, the group name is a run-time value. Every route of the +// sub-app is partial with the known path /v1/{}/; the global use runs on it, the /v1/* scoped use is a +// declared unknown (SPEC 3.3), and no exact /v1/... route is guessed. +import { Hono } from 'hono' +import { system } from './system' + +const VERSION = 'v1' + +declare const process: { env: Record } + +const app = new Hono() +app.use('*', async (c, next) => { + await next() +}) +app.use(`/${VERSION}/*`, async (c, next) => { + if (!c.req.header('authorization')) return c.text('no', 401) + await next() +}) +const group = process.env.GROUP ?? 'system' +app.route(`/${VERSION}/${group}`, system) +app.get('/health', (c) => c.text('ok')) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/src/system.ts b/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/src/system.ts new file mode 100644 index 000000000..82f2cce16 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/partial-path-mid-hole/src/system.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +export const system = new Hono() +system.use('*', async (c, next) => { + c.header('x-system', '1') + await next() +}) +system.get('/ping', (c) => c.text('pong')) +system.get('/status/:part', (c) => c.json({ part: c.req.param('part') })) diff --git a/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/app.test.ts b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/app.test.ts new file mode 100644 index 000000000..7a20e7dfe --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/app.test.ts @@ -0,0 +1,20 @@ +// census: app_request_test (oracle gap O20; SPEC R13 / R13b) +// Plugin apps reach a mount only through a helper over a filtered, dependency-sorted list (a ternary of two +// filtered lists, a push-built result): each is mounted at its element's path, exact plus conditional, never a +// root at its own local paths. +import { Hono } from 'hono' +import { createApp } from './app' +import type { Plugin } from './mount' + +declare function it(name: string, fn: () => unknown): void + +function makeCustomPlugin(): Plugin { + const routes = new Hono() + routes.get('/', (c) => c.json({ custom: true })) + return { id: 'custom', routes: [{ path: '/api/custom-test', handler: routes }] } +} + +it('mounts a custom plugin', async () => { + const app = createApp({ plugins: { register: [makeCustomPlugin()] } }) + await app.request('/api/custom-test') +}) diff --git a/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/app.ts b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/app.ts new file mode 100644 index 000000000..68d963f1e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/app.ts @@ -0,0 +1,15 @@ +import { Hono } from 'hono' +import { registerPluginRoutes, type Plugin } from './mount' +import { magicLinkPlugin } from './plugins/magic-link' + +const coreAfterCatchAll: Plugin[] = [magicLinkPlugin] + +export function createApp(config: { plugins?: { register?: Plugin[] } } = {}) { + const app = new Hono() + app.get('/', (c) => c.text('home')) + if (config.plugins?.register) { + registerPluginRoutes(app, config.plugins.register) + } + registerPluginRoutes(app, coreAfterCatchAll) + return app +} diff --git a/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/mount.ts b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/mount.ts new file mode 100644 index 000000000..8a50f60a0 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/mount.ts @@ -0,0 +1,22 @@ +import type { Hono } from 'hono' +import { topoSort } from './sort' + +export interface Plugin { + id: string + dependencies?: string[] + routes?: { path: string; handler: Hono }[] +} + +export function mountPlugin(app: Hono, plugin: Plugin) { + for (const route of plugin.routes ?? []) { + if (!route.path || !route.handler) continue + app.route(route.path, route.handler) + } +} + +export function registerPluginRoutes(app: Hono, plugins: Array, opts: { sort?: boolean } = {}) { + const sorted = (opts.sort ?? true) + ? topoSort(plugins.filter((p): p is Plugin => !!p)) + : plugins.filter((p): p is Plugin => !!p) + for (const plugin of sorted) mountPlugin(app, plugin) +} diff --git a/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/plugins/magic-link.ts b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/plugins/magic-link.ts new file mode 100644 index 000000000..33d518c70 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/plugins/magic-link.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' +import type { Plugin } from '../mount' + +const magic = new Hono() +magic.post('/request', (c) => c.json({ sent: true })) +magic.get('/verify', (c) => c.text('ok')) + +export const magicLinkPlugin: Plugin = { id: 'magic-link', routes: [{ path: '/auth/magic-link', handler: magic }] } diff --git a/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/sort.ts b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/sort.ts new file mode 100644 index 000000000..ce5a7d056 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-helper-list/src/sort.ts @@ -0,0 +1,17 @@ +export interface Sortable { + id: string + dependencies?: string[] +} + +// dependency order (dependencies elided here): rebuilt into a new array at run time from the elements it is given +export function topoSort(plugins: ReadonlyArray): T[] { + const result: T[] = [] + const seen = new Set() + function visit(p: T): void { + if (seen.has(p.id)) return + seen.add(p.id) + result.push(p) + } + for (const p of plugins) visit(p) + return result +} diff --git a/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/app.ts b/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/app.ts new file mode 100644 index 000000000..4b8a859de --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/app.ts @@ -0,0 +1,18 @@ +import { Hono } from 'hono' +import { createMagicLinkPlugin, type Plugin } from './plugins/magic-link' + +function mountAll(app: Hono, plugins: Plugin[]) { + for (const p of plugins.filter((x) => !!x.name)) { + for (const r of p.routes ?? []) app.route(r.path, r.handler) + } +} + +export function createApp() { + const app = new Hono() + app.get('/', (c) => c.text('home')) + const magicLink = createMagicLinkPlugin() + mountAll(app, [magicLink]) + return app +} + +export default createApp() diff --git a/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/plugins/legacy-export.ts b/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/plugins/legacy-export.ts new file mode 100644 index 000000000..da4be31a3 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/plugins/legacy-export.ts @@ -0,0 +1,12 @@ +// A plugin module nothing imports: a loader the program does not show may mount its entry, at a prefix the program +// does not spell. Its handlers are routed nowhere else, so they are partial (unresolved_mount), never roots. +import { Hono } from 'hono' +import type { Plugin } from './magic-link' + +function createLegacyExportPlugin(): Plugin { + const legacy = new Hono() + legacy.get('/csv', (c) => c.text('a,b')) + return { name: 'legacy-export', routes: [{ path: '/legacy/export', handler: legacy }] } +} + +export default createLegacyExportPlugin() diff --git a/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/plugins/magic-link.ts b/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/plugins/magic-link.ts new file mode 100644 index 000000000..1cc3ec043 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-instance-never-mounted/src/plugins/magic-link.ts @@ -0,0 +1,21 @@ +// census: plugin_list_mount (oracle gap O24; SPEC R13 / R13b) +// A plugin factory builds its own app and writes it into a declarative route-list entry. The host calls the factory +// and mounts that instance under the entry's path. The module ALSO default-exports a second instance that nothing +// imports, mounts or serves: its app is never served at any path, so it gives no exact route (not a root at +// /request, /verify). The handlers are still served through the mounted instance. +import { Hono } from 'hono' + +export interface Plugin { name: string; dependencies?: string[]; routes?: { path: string; handler: Hono }[] } + +export function createMagicLinkPlugin(): Plugin { + const routes = new Hono() + routes.post('/request', (c) => c.json({ sent: true })) + routes.get('/verify', (c) => c.text('verified')) + return { + name: 'magic-link', + dependencies: ['email'], + routes: [{ path: '/auth/magic-link', handler: routes }], + } +} + +export default createMagicLinkPlugin() diff --git a/graph/test/typescript/hono/cases/compose/plugin-register-method/src/index.ts b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/index.ts new file mode 100644 index 000000000..46c2f3585 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/index.ts @@ -0,0 +1,22 @@ +// census: route_mount_literal (oracle gap O11 residual; SPEC 2 a mount argument is never a root) +// Plugins mount their apps in a `register(app)` method of the object they hand to definePlugin; the host calls +// it over a FILTERED list of known plugins. R13b: each plugin app is mounted exactly at its literal prefix with +// conditional_registration, never a root. +import { Hono } from 'hono' +import type { PluginInput } from './sdk' +import { mediaPlugin } from './plugins/media' +import { variablesPlugin } from './plugins/variables' + +declare const settings: { enabled: Set } + +export function mountPlugins(app: Hono, plugins: PluginInput[]) { + for (const p of plugins) { + p.register?.(app) + } +} + +const app = new Hono() +app.get('/', (c) => c.text('home')) +mountPlugins(app, [mediaPlugin, variablesPlugin].filter((p) => settings.enabled.has(p.id))) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/plugin-register-method/src/plugins/media.ts b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/plugins/media.ts new file mode 100644 index 000000000..6691ccf1f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/plugins/media.ts @@ -0,0 +1,17 @@ +import { Hono } from 'hono' +import { definePlugin } from '../sdk' + +function buildMediaApi() { + const api = new Hono() + api.get('/', (c) => c.json([])) + api.delete('/:id', (c) => c.body(null, 204)) + return api +} + +export const mediaPlugin = definePlugin({ + id: 'media', + register(app) { + app.route('/api/media', buildMediaApi()) + }, + menu: [{ label: 'Media', path: '/admin/media' }], +}) diff --git a/graph/test/typescript/hono/cases/compose/plugin-register-method/src/plugins/variables.ts b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/plugins/variables.ts new file mode 100644 index 000000000..646b14c2a --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/plugins/variables.ts @@ -0,0 +1,18 @@ +import { Hono } from 'hono' +import { definePlugin } from '../sdk' + +const apiRoutes = new Hono() +apiRoutes.get('/:key', (c) => c.json({ key: c.req.param('key') })) + +const adminRoutes = new Hono() +adminRoutes.post('/', (c) => c.text('saved', 201)) + +export const variablesPlugin = definePlugin({ + id: 'variables', + register: (app) => { + app.route('/api/variables', apiRoutes) + app.route('/admin/variables', adminRoutes) + }, +}) + +export { apiRoutes as variablesApiRoutes } diff --git a/graph/test/typescript/hono/cases/compose/plugin-register-method/src/sdk.ts b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/sdk.ts new file mode 100644 index 000000000..a4914f8ba --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-register-method/src/sdk.ts @@ -0,0 +1,12 @@ +import type { Hono } from 'hono' + +export interface PluginInput { + id: string + register?(app: Hono): void + menu?: { label: string; path: string }[] +} + +export function definePlugin(input: PluginInput) { + if (!input.id) throw new Error('definePlugin: id is required') + return { ...input, defined: true } +} diff --git a/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins.ts b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins.ts new file mode 100644 index 000000000..60d6fe4cb --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins.ts @@ -0,0 +1,15 @@ +// census: app_request_test, plugin_list_mount (SPEC R16 control; R6, R13b) +// The control for R16: ONE plugin module is mounted by the production app AND by a test's own app. Both apps +// really serve its routes, so its routes are rows on BOTH apps. A plugin only the test mounts stays on the test app; +// a plugin only production mounts stays on the production app. +import type { Hono } from 'hono' + +export interface Plugin { name: string; routes?: { path: string; handler: Hono }[] } + +export function mountPlugin(app: Hono, plugin: Plugin) { + for (const route of plugin.routes ?? []) app.route(route.path, route.handler) +} + +export function registerPlugins(app: Hono, plugins: Plugin[]) { + for (const p of plugins.filter((x) => !!x.name)) mountPlugin(app, p) +} diff --git a/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins/billing.ts b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins/billing.ts new file mode 100644 index 000000000..36a89bda2 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins/billing.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' +import type { Plugin } from '../plugins' + +const billing = new Hono() +billing.get('/invoices', (c) => c.json([])) + +export const billingPlugin: Plugin = { name: 'billing', routes: [{ path: '/api/billing', handler: billing }] } diff --git a/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins/search.ts b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins/search.ts new file mode 100644 index 000000000..f01c3e776 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/plugins/search.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' +import type { Plugin } from '../plugins' + +const search = new Hono() +search.get('/', (c) => c.json({ hits: [] })) +search.post('/reindex', (c) => c.text('queued', 202)) + +export const searchPlugin: Plugin = { name: 'search', routes: [{ path: '/api/search', handler: search }] } diff --git a/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/server.ts b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/server.ts new file mode 100644 index 000000000..0a1c1ac7e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/server.ts @@ -0,0 +1,10 @@ +import { Hono } from 'hono' +import { registerPlugins } from './plugins' +import { searchPlugin } from './plugins/search' +import { billingPlugin } from './plugins/billing' + +const app = new Hono() +app.get('/', (c) => c.text('home')) +registerPlugins(app, [searchPlugin, billingPlugin]) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/test/search.test.ts b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/test/search.test.ts new file mode 100644 index 000000000..f0cee673b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/plugin-shared-test-and-prod/src/test/search.test.ts @@ -0,0 +1,22 @@ +import { Hono } from 'hono' +import { mountPlugin, type Plugin } from '../plugins' +import { searchPlugin } from '../plugins/search' + +declare function it(name: string, fn: () => unknown): void + +it('serves the search plugin on a bare app', async () => { + const app = new Hono() + mountPlugin(app, searchPlugin) + await app.request('/api/search') + await app.request('/api/search/reindex', { method: 'POST' }) +}) + +it('serves a test-only plugin beside it', async () => { + const probe = new Hono().get('/', (c) => c.text('probe')) + const testOnly: Plugin = { name: 'probe', routes: [{ path: '/__probe', handler: probe }] } + const app = new Hono() + mountPlugin(app, searchPlugin) + mountPlugin(app, testOnly) + await app.request('/__probe') + await app.request('/api/billing/invoices') +}) diff --git a/graph/test/typescript/hono/cases/compose/rebased-holder-getter/src/index.ts b/graph/test/typescript/hono/cases/compose/rebased-holder-getter/src/index.ts new file mode 100644 index 000000000..4ff5a187b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/rebased-holder-getter/src/index.ts @@ -0,0 +1,42 @@ +// census: basepath (violation hono-3-01, SPEC R8a; holder read through a getter) +// The rebased holder is reached through a getter of another class, and the mounted app comes from a controller +// method: still ONE partial (dynamic_mount_prefix) per route, no exact row. +import { Hono } from 'hono' + +declare const process: { env: Record } + +class Modules { + server = new Hono() + constructor(private settings?: { prefix?: string }) {} + reset() { + this.server = new Hono() + if (this.settings?.prefix) { + this.server = this.server.basePath(this.settings.prefix) + } + } +} + +class Kernel { + modules = new Modules({ prefix: process.env.PREFIX }) + get server() { + return this.modules.server + } +} + +class HealthController { + getController() { + const h = new Hono() + h.get('/live', (c) => c.text('live')) + h.post('/drain', (c) => c.text('drained')) + return h + } + register(kernel: Kernel) { + kernel.server.route('/internal/health', this.getController()) + } +} + +const kernel = new Kernel() +kernel.modules.reset() +new HealthController().register(kernel) + +export default { fetch: kernel.server.fetch } diff --git a/graph/test/typescript/hono/cases/compose/rebased-holder-mount/src/index.ts b/graph/test/typescript/hono/cases/compose/rebased-holder-mount/src/index.ts new file mode 100644 index 000000000..15dd6656d --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/rebased-holder-mount/src/index.ts @@ -0,0 +1,26 @@ +// census: basepath (violation hono-3-01, SPEC R8a) +// A sub-app mounted with route() into an app holder that a run-time basePath can rebase: its route is ONE partial +// (dynamic_mount_prefix) and never an exact row, exactly as a route registered on the holder directly. +import { Hono } from 'hono' + +declare const process: { env: Record } + +const status = new Hono() +status.get('/ping', (c) => c.text('pong')) + +class Runtime { + server = new Hono() + constructor(private settings?: { prefix?: string }) {} + reset() { + this.server = new Hono() + if (this.settings?.prefix) { + this.server = this.server.basePath(this.settings.prefix) + } + } +} + +const rt = new Runtime({ prefix: process.env.PREFIX }) +rt.reset() +rt.server.route('/internal/status', status) + +export default rt.server diff --git a/graph/test/typescript/hono/cases/compose/rebased-holder-one-partial/src/index.ts b/graph/test/typescript/hono/cases/compose/rebased-holder-one-partial/src/index.ts new file mode 100644 index 000000000..1d1e937b8 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/rebased-holder-one-partial/src/index.ts @@ -0,0 +1,46 @@ +// census: prop_receiver_route (violation hono-2-04 residue, SPEC R8 / R8a) +// A holder rebuilt by a method that several call sites run (each rebuild may rebase it with a run-time prefix), +// with controllers mounted into it through a build context object. Each route is ONE partial with ONE reason +// (dynamic_mount_prefix), not one row per hole depth and not a second reason per route. +import { Hono } from 'hono' + +declare const process: { env: Record } + +interface BuildContext { + server: Hono +} + +class UsersController { + getController() { + const h = new Hono() + h.get('/', (c) => c.json([])) + h.get('/:id', (c) => c.json({ id: c.req.param('id') })) + return h + } +} + +class Modules { + server = new Hono() + constructor(private options?: { basePath?: string }) {} + private rebuildServer() { + this.server = new Hono() + if (this.options?.basePath) { + this.server = this.server.basePath(this.options.basePath) + } + } + ctx(rebuild?: boolean): BuildContext { + if (rebuild) this.rebuildServer() + return { server: this.server } + } + build() { + this.rebuildServer() + const ctx = this.ctx() + ctx.server.route('/api/users', new UsersController().getController()) + } +} + +const modules = new Modules({ basePath: process.env.BASE_PATH }) +modules.ctx(true) +modules.build() + +export default modules.server diff --git a/graph/test/typescript/hono/cases/compose/rebased-two-mounts/src/index.ts b/graph/test/typescript/hono/cases/compose/rebased-two-mounts/src/index.ts new file mode 100644 index 000000000..faae2199b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/rebased-two-mounts/src/index.ts @@ -0,0 +1,32 @@ +// census: basepath (stress-4 mutation m33 shape; violations hono-3-01, hono-4-04) +// Two sub-apps mounted into a holder a run-time basePath can rebase, one at a literal prefix and one at a run-time +// prefix: every route is ONE partial (dynamic_mount_prefix), no exact rows. +import { Hono } from 'hono' + +declare const process: { env: Record } + +const settings = new Hono() +settings.get('/config/raw', (c) => c.text('raw')) +const callbacks = new Hono() +callbacks.post('/:provider', (c) => c.text(c.req.param('provider'))) + +class Server { + app = new Hono() + private opts?: { prefix?: string } + constructor(opts?: { prefix?: string }) { + this.opts = opts + } + reset() { + this.app = new Hono() + if (this.opts?.prefix) { + this.app = this.app.basePath(this.opts.prefix) + } + } +} + +const srv = new Server({ prefix: process.env.PREFIX }) +srv.reset() +srv.app.route('/api/settings', settings) +srv.app.route(process.env.CALLBACK_PREFIX ?? '/callbacks', callbacks) + +export default srv.app diff --git a/graph/test/typescript/hono/cases/compose/reexport-barrel/src/index.ts b/graph/test/typescript/hono/cases/compose/reexport-barrel/src/index.ts new file mode 100644 index 000000000..83badd3b6 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/reexport-barrel/src/index.ts @@ -0,0 +1,9 @@ +// census: reexport_default_as, route_mount_literal +// A sub-app reached through a barrel re-export (`export { default as x } from`). +import { Hono } from 'hono' +import { books } from './routes' + +const app = new Hono() +app.route('/books', books) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/reexport-barrel/src/routes/books.ts b/graph/test/typescript/hono/cases/compose/reexport-barrel/src/routes/books.ts new file mode 100644 index 000000000..fb4fc1581 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/reexport-barrel/src/routes/books.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +const books = new Hono() +books.get('/', (c) => c.json([])) + +export default books diff --git a/graph/test/typescript/hono/cases/compose/reexport-barrel/src/routes/index.ts b/graph/test/typescript/hono/cases/compose/reexport-barrel/src/routes/index.ts new file mode 100644 index 000000000..e30ba09e4 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/reexport-barrel/src/routes/index.ts @@ -0,0 +1 @@ +export { default as books } from './books' diff --git a/graph/test/typescript/hono/cases/compose/register-fn/src/index.ts b/graph/test/typescript/hono/cases/compose/register-fn/src/index.ts new file mode 100644 index 000000000..037a7aea7 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/register-fn/src/index.ts @@ -0,0 +1,15 @@ +// census: app_factory_fn +// The app reaches its routes through registration functions: a parameter typed `Hono`, and one typed +// `typeof `; the callee's registrations are spliced in at the call. +import { Hono } from 'hono' +import { registerUsers } from './users' +import { monitorsApi, registerMonitorRoutes } from './monitors' + +const app = new Hono() +app.get('/', (c) => c.text('first')) +registerUsers(app) +registerMonitorRoutes(monitorsApi) +app.route('/v1', monitorsApi) +app.get('/last', (c) => c.text('last')) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/register-fn/src/monitors.ts b/graph/test/typescript/hono/cases/compose/register-fn/src/monitors.ts new file mode 100644 index 000000000..20a03da91 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/register-fn/src/monitors.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +export const monitorsApi = new Hono() + +export function registerMonitorRoutes(api: typeof monitorsApi) { + api.get('/monitors', (c) => c.json([])) +} diff --git a/graph/test/typescript/hono/cases/compose/register-fn/src/users.ts b/graph/test/typescript/hono/cases/compose/register-fn/src/users.ts new file mode 100644 index 000000000..653205dac --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/register-fn/src/users.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +export function registerUsers(app: Hono) { + app.get('/users', (c) => c.json([])) + app.post('/users', (c) => c.json({}, 201)) +} diff --git a/graph/test/typescript/hono/cases/compose/register-loop-plugins/src/plugins.ts b/graph/test/typescript/hono/cases/compose/register-loop-plugins/src/plugins.ts new file mode 100644 index 000000000..ae21bfb8b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/register-loop-plugins/src/plugins.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +const billing = new Hono().get('/invoices', (c) => c.json([])) +const search = new Hono().get('/query', (c) => c.json([])) + +export const plugins = [ + { prefix: '/billing', app: billing }, + { prefix: '/search', app: search }, +] diff --git a/graph/test/typescript/hono/cases/compose/register-loop-plugins/src/register.ts b/graph/test/typescript/hono/cases/compose/register-loop-plugins/src/register.ts new file mode 100644 index 000000000..5962cdd6b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/register-loop-plugins/src/register.ts @@ -0,0 +1,11 @@ +// census: route_mount_literal (oracle gap O11; SPEC 2 a mount argument is never a root) +// Plugins mounted in a loop inside a register(app) that nothing in the program calls: the plugin apps are +// mount arguments, so they are not roots; the receiver is a parameter typed Hono (prefix unknown). +import type { Hono } from 'hono' +import { plugins } from './plugins' + +export function register(app: Hono) { + for (const p of plugins) { + app.route(p.prefix, p.app) + } +} diff --git a/graph/test/typescript/hono/cases/compose/registered-by/src/index.ts b/graph/test/typescript/hono/cases/compose/registered-by/src/index.ts new file mode 100644 index 000000000..3e9b376e4 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/registered-by/src/index.ts @@ -0,0 +1,14 @@ +// census: app_factory_fn (SPEC 4 [iter2] route_registered_by: the method enclosing each registering call) +// Routes registered by two registration functions, through a mount, and at module level. +import { Hono } from 'hono' +import { registerGetMonitor, registerListMonitors } from './monitors' + +const api = new Hono() +registerGetMonitor(api) +registerListMonitors(api) + +const app = new Hono() +app.get('/', (c) => c.text('module level')) +app.route('/v1', api) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/registered-by/src/monitors.ts b/graph/test/typescript/hono/cases/compose/registered-by/src/monitors.ts new file mode 100644 index 000000000..094351adb --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/registered-by/src/monitors.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +export function registerGetMonitor(api: Hono) { + api.get('/monitors/:id', (c) => c.json({ id: c.req.param('id') })) +} +export function registerListMonitors(api: Hono) { + api.get('/monitors', (c) => c.json([])) + api.post('/monitors', (c) => c.json({}, 201)) +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/index.ts b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/index.ts new file mode 100644 index 000000000..ed660901b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/index.ts @@ -0,0 +1,17 @@ +// census: route_mount_literal, app_factory_fn (violation hono-7-01, P1 false_route: sub-apps read out of an +// object a function returns) +// Destructured reads, one of them renamed. Control: the three sub-apps have distinct paths and handlers, so a +// name that took another property's value would show a route at the wrong prefix (e.g. DELETE /v1/orders/:sku). +import { Hono } from 'hono' +import { createRuntime } from './runtime' + +const { stockRoutes, orderRoutes, auditRoutes: audit } = createRuntime('eu') + +const app = new Hono() +const v1 = new Hono() +v1.route('/stock', stockRoutes) +v1.route('/orders', orderRoutes) +v1.route('/audit', audit) +app.route('/v1', v1) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/audit.ts b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/audit.ts new file mode 100644 index 000000000..eb0660691 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/audit.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +export function buildAuditRoutes(): Hono { + const audit = new Hono() + audit.post('/flush', (c) => c.text('flushed')) + return audit +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/orders.ts b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/orders.ts new file mode 100644 index 000000000..e36d8b474 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/orders.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function buildOrderRoutes(label: () => string): Hono { + const orders = new Hono() + orders.get('/recent', (c) => c.text(label())) + orders.put('/:orderId', (c) => c.text('saved')) + return orders +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/stock.ts b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/stock.ts new file mode 100644 index 000000000..5ad98860b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/routes/stock.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function buildStockRoutes(label: () => string): Hono { + const stock = new Hono() + stock.get('/', (c) => c.text(label())) + stock.delete('/:sku', (c) => c.text('removed')) + return stock +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/runtime.ts b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/runtime.ts new file mode 100644 index 000000000..2a897328f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-destructure/src/runtime.ts @@ -0,0 +1,11 @@ +import { buildStockRoutes } from './routes/stock' +import { buildOrderRoutes } from './routes/orders' +import { buildAuditRoutes } from './routes/audit' + +// The factory hands back several sub-apps in one object literal: shorthand properties, one written-out +// property, and a non-app property. Each read below must take only its own property's value. +export function createRuntime(region: string) { + const stockRoutes = buildStockRoutes(() => region) + const orderRoutes = buildOrderRoutes(() => region) + return { region, stockRoutes, orderRoutes, auditRoutes: buildAuditRoutes() } +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-member/src/index.ts b/graph/test/typescript/hono/cases/compose/returned-object-member/src/index.ts new file mode 100644 index 000000000..c193af77e --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-member/src/index.ts @@ -0,0 +1,17 @@ +// census: route_mount_literal, prop_receiver_route, app_factory_fn (violation hono-7-01, P1 false_route: sub-apps +// read out of an object a function returns) +// Member reads `rt.p` of the returned object. Control: the three sub-apps have distinct paths and handlers, so a +// read that took another property's value would show a route at the wrong prefix (e.g. GET /v1/stock/recent). +import { Hono } from 'hono' +import { createRuntime } from './runtime' + +const rt = createRuntime('eu') + +const app = new Hono() +const v1 = new Hono() +v1.route('/stock', rt.stockRoutes) +v1.route('/orders', rt.orderRoutes) +v1.route('/audit', rt.auditRoutes) +app.route('/v1', v1) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/audit.ts b/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/audit.ts new file mode 100644 index 000000000..eb0660691 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/audit.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +export function buildAuditRoutes(): Hono { + const audit = new Hono() + audit.post('/flush', (c) => c.text('flushed')) + return audit +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/orders.ts b/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/orders.ts new file mode 100644 index 000000000..e36d8b474 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/orders.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function buildOrderRoutes(label: () => string): Hono { + const orders = new Hono() + orders.get('/recent', (c) => c.text(label())) + orders.put('/:orderId', (c) => c.text('saved')) + return orders +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/stock.ts b/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/stock.ts new file mode 100644 index 000000000..5ad98860b --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-member/src/routes/stock.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function buildStockRoutes(label: () => string): Hono { + const stock = new Hono() + stock.get('/', (c) => c.text(label())) + stock.delete('/:sku', (c) => c.text('removed')) + return stock +} diff --git a/graph/test/typescript/hono/cases/compose/returned-object-member/src/runtime.ts b/graph/test/typescript/hono/cases/compose/returned-object-member/src/runtime.ts new file mode 100644 index 000000000..2a897328f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/returned-object-member/src/runtime.ts @@ -0,0 +1,11 @@ +import { buildStockRoutes } from './routes/stock' +import { buildOrderRoutes } from './routes/orders' +import { buildAuditRoutes } from './routes/audit' + +// The factory hands back several sub-apps in one object literal: shorthand properties, one written-out +// property, and a non-app property. Each read below must take only its own property's value. +export function createRuntime(region: string) { + const stockRoutes = buildStockRoutes(() => region) + const orderRoutes = buildOrderRoutes(() => region) + return { region, stockRoutes, orderRoutes, auditRoutes: buildAuditRoutes() } +} diff --git a/graph/test/typescript/hono/cases/compose/route-and-partial/src/index.ts b/graph/test/typescript/hono/cases/compose/route-and-partial/src/index.ts new file mode 100644 index 000000000..046a49284 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/route-and-partial/src/index.ts @@ -0,0 +1,19 @@ +// census: app_factory_fn (oracle gap O12) +// One registration function called with a known app and with an app of unknown prefix: the handler has its +// route, and is not also reported partial. +import { Hono } from 'hono' + +interface Ctx { server: Hono } + +export function registerMemory(api: Hono) { + api.get('/memory', (c) => c.json({ used: 0 })) +} + +const app = new Hono() +registerMemory(app) + +export function wire(ctx: Ctx) { + registerMemory(ctx.server) +} + +export default app diff --git a/graph/test/typescript/hono/cases/compose/route-cross-module/src/index.ts b/graph/test/typescript/hono/cases/compose/route-cross-module/src/index.ts new file mode 100644 index 000000000..99e9af792 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/route-cross-module/src/index.ts @@ -0,0 +1,11 @@ +// census: route_mount_literal, export_default_app +// A sub-app defined and default-exported in another module, mounted under a prefix. +import { Hono } from 'hono' +import users from './users' + +const app = new Hono() + +app.get('/', (c) => c.text('home')) +app.route('/users', users) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/route-cross-module/src/users.ts b/graph/test/typescript/hono/cases/compose/route-cross-module/src/users.ts new file mode 100644 index 000000000..78063a585 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/route-cross-module/src/users.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +const users = new Hono() + +users.get('/', (c) => c.json([])) +users.get('/:id', (c) => c.json({ id: c.req.param('id') })) +users.post('/', (c) => c.json({}, 201)) + +export default users diff --git a/graph/test/typescript/hono/cases/compose/route-root/src/index.ts b/graph/test/typescript/hono/cases/compose/route-root/src/index.ts new file mode 100644 index 000000000..5946b2dd6 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/route-root/src/index.ts @@ -0,0 +1,16 @@ +// census: route_mount_root +// route('/', other) merges the other app's routes unprefixed; chained route() calls. +import { Hono } from 'hono' + +const auth = new Hono() +auth.post('/login', (c) => c.text('in')) +auth.post('/logout', (c) => c.text('out')) + +const misc = new Hono() +misc.get('/about', (c) => c.text('about')) + +const app = new Hono() +const routes = app.route('/', auth).route('/', misc) + +export type AppType = typeof routes +export default app diff --git a/graph/test/typescript/hono/cases/compose/same-sub-twice/src/index.ts b/graph/test/typescript/hono/cases/compose/same-sub-twice/src/index.ts new file mode 100644 index 000000000..5bcc957c9 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/same-sub-twice/src/index.ts @@ -0,0 +1,12 @@ +// census: route_mount_literal +// One sub-app mounted under two prefixes serves its routes under both. +import { Hono } from 'hono' + +const health = new Hono() +health.get('/health', (c) => c.text('ok')) + +const app = new Hono() +app.route('/a', health) +app.route('/b', health) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/self-basepath-field/src/index.ts b/graph/test/typescript/hono/cases/compose/self-basepath-field/src/index.ts new file mode 100644 index 000000000..d9923d63f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/self-basepath-field/src/index.ts @@ -0,0 +1,22 @@ +// census: basepath (violation hono-2-04, SPEC R8) +// A self-referential update of an app field, behind a condition with a run-time base: evaluated once per +// textual assignment; the route is declared ONCE (partial, dynamic_mount_prefix), never exploded. +import { Hono } from 'hono' + +declare const process: { env: Record } + +class Manager { + server = new Hono() + rebuild(base?: string) { + this.server = new Hono() + if (base) { + this.server = this.server.basePath(base) + } + } +} + +const m = new Manager() +m.rebuild(process.env.BASE) +m.server.get('/x', (c) => c.text('x')) + +export default m.server diff --git a/graph/test/typescript/hono/cases/compose/shared-factory-filtered-loop/src/index.ts b/graph/test/typescript/hono/cases/compose/shared-factory-filtered-loop/src/index.ts new file mode 100644 index 000000000..e6c6d013f --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/shared-factory-filtered-loop/src/index.ts @@ -0,0 +1,47 @@ +// census: route_mount_root (stress-5 mutation m35b shape; violation hono-5-02, SPEC R6 and R13b) +// Controllers built through one static factory, each adding its own use() calls, mounted at '/' over a filtered +// list. Each call of the factory is its own app (R6): /reports gets only its own guard; /exports gets the reports +// guard first (mounted at '/', its `*` scope reaches later routes) and its own two, and since that first guard +// belongs to another, filtered element, the chain is declared dynamic. Routes are exact plus conditional. +import { Hono } from 'hono' +import type { Context, Next } from 'hono' + +const guard = () => async (_c: Context, next: Next) => { + await next() +} +const quota = () => async (_c: Context, next: Next) => { + await next() +} + +class Controller { + protected create(): Hono { + return Controller.createServer() + } + static createServer(): Hono { + return new Hono() + } + getController(): Hono { + return this.create() + } +} +class Reports extends Controller { + override getController() { + const h = this.create().use(guard()) + h.get('/reports', (c) => c.text('reports')) + return h + } +} +class Exports extends Controller { + override getController() { + const h = this.create().use(guard()).use(quota()) + h.get('/exports', (c) => c.text('exports')) + return h + } +} + +declare const flags: { has(name: string): boolean } + +const app = new Hono() +const list: Controller[] = [new Reports(), new Exports()].filter((c) => flags.has(c.constructor.name)) +for (const c of list) app.route('/', c.getController()) +export default app diff --git a/graph/test/typescript/hono/cases/compose/sync-wrapper-mount/src/main.ts b/graph/test/typescript/hono/cases/compose/sync-wrapper-mount/src/main.ts new file mode 100644 index 000000000..659664027 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/sync-wrapper-mount/src/main.ts @@ -0,0 +1,13 @@ +// census: bun_serve (stress-5 mutation m38b shape; violation hono-5-06) +// The same wrapper, synchronous: the served wrapper serves the inner route behind its use('*'). +import { Hono } from 'hono' +import { wrapApp } from './wrap' + +declare const Bun: { serve(o: { fetch: (r: Request) => Response | Promise; port: number }): void } + +const inner = new Hono() +inner.get('/hello', (c) => c.text('hi')) +inner.post('/echo', async (c) => c.json(await c.req.json())) + +const app = wrapApp(inner) +Bun.serve({ fetch: app.fetch, port: 3000 }) diff --git a/graph/test/typescript/hono/cases/compose/sync-wrapper-mount/src/wrap.ts b/graph/test/typescript/hono/cases/compose/sync-wrapper-mount/src/wrap.ts new file mode 100644 index 000000000..ae7f8e3ba --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/sync-wrapper-mount/src/wrap.ts @@ -0,0 +1,11 @@ +import { Hono } from 'hono' + +export function wrapApp(inner: Hono): Hono { + const wrapper = new Hono() + wrapper.use('*', async (c, next) => { + c.header('x-wrapped', '1') + await next() + }) + wrapper.route('/', inner) + return wrapper +} diff --git a/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/__tests__/define-plugin.test.ts b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/__tests__/define-plugin.test.ts new file mode 100644 index 000000000..961c485d2 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/__tests__/define-plugin.test.ts @@ -0,0 +1,29 @@ +import { Hono } from 'hono' +import { definePlugin, registerPluginRoutes } from '../sdk' + +declare function it(name: string, fn: () => unknown): void +declare function describe(name: string, fn: () => unknown): void +declare function expect(v: unknown): { toBe(x: unknown): void } + +describe('definePlugin mounts like any plugin', () => { + it('declarative routes mount through registerPluginRoutes', async () => { + const sub = new Hono().get('/', (c) => c.text('defined')) + const p = definePlugin({ id: 'routed', routes: [{ path: '/api/defined', handler: sub }] }) + const app = new Hono() + registerPluginRoutes(app, [p]) + // oracle gap O26: a request inside an assertion's argument is still a request to THIS app + expect(await (await app.request('/api/defined')).text()).toBe('defined') + }) + + it('register(app) runs at mount', async () => { + const p = definePlugin({ + id: 'imperative', + register(app) { + app.route('/imp', new Hono().get('/', (c) => c.text('imp'))) + }, + }) + const app = new Hono() + registerPluginRoutes(app, [p]) + expect((await app.request('/imp')).status).toBe(200) + }) +}) diff --git a/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/__tests__/mount.test.ts b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/__tests__/mount.test.ts new file mode 100644 index 000000000..0dddc5532 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/__tests__/mount.test.ts @@ -0,0 +1,33 @@ +import { Hono } from 'hono' +import { mountPlugin, registerPluginRoutes, type MountLog, type Plugin } from '../sdk' + +declare function it(name: string, fn: () => unknown): void + +function routesFor(label: string) { + const r = new Hono() + r.get('/', (c) => c.text(label)) + return r +} + +it('mounts one plugin', async () => { + const app = new Hono() + const plugin: Plugin = { name: 'alpha', routes: [{ path: '/alpha', handler: routesFor('alpha') }] } + mountPlugin(app, plugin) + await app.request('/alpha') +}) + +it('records what it mounted', async () => { + const app = new Hono() + const log: MountLog = { mounted: [], skipped: [] } + mountPlugin(app, { name: 'beta', routes: [{ path: '/beta', handler: routesFor('beta'), priority: 5 }] }, log) + await app.request('/beta') +}) + +it('mounts a list in order', async () => { + const app = new Hono() + registerPluginRoutes(app, [ + { name: 'gamma', routes: [{ path: '/gamma', handler: routesFor('gamma') }] }, + null, + ]) + await app.request('/gamma') +}) diff --git a/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/app.ts b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/app.ts new file mode 100644 index 000000000..6982d6f85 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/app.ts @@ -0,0 +1,15 @@ +import { Hono } from 'hono' +import { registerPluginRoutes } from './sdk' +import { auditPlugin } from './plugins/audit' +import { tenantsPlugin } from './plugins/tenants' + +const corePlugins = [auditPlugin, tenantsPlugin] + +export function createApp() { + const app = new Hono() + app.get('/health', (c) => c.text('ok')) + registerPluginRoutes(app, corePlugins) + return app +} + +export default createApp() diff --git a/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/plugins/audit.ts b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/plugins/audit.ts new file mode 100644 index 000000000..949432128 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/plugins/audit.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' +import { definePlugin } from '../sdk' + +const audit = new Hono() +audit.get('/', (c) => c.json([])) +audit.get('/:id', (c) => c.json({ id: c.req.param('id') })) + +export const auditPlugin = definePlugin({ id: 'audit', routes: [{ path: '/admin/audit', handler: audit }] }) diff --git a/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/plugins/tenants.ts b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/plugins/tenants.ts new file mode 100644 index 000000000..a96bb1acf --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/plugins/tenants.ts @@ -0,0 +1,15 @@ +import { Hono } from 'hono' +import { definePlugin } from '../sdk' + +function tenantRoutes() { + const r = new Hono() + r.get('/', (c) => c.text('tenants')) + return r +} + +export const tenantsPlugin = definePlugin({ + id: 'tenants', + register(app) { + app.route('/admin/tenants', tenantRoutes()) + }, +}) diff --git a/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/sdk.ts b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/sdk.ts new file mode 100644 index 000000000..6e9ed04ab --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/test-plugin-own-app/src/sdk.ts @@ -0,0 +1,70 @@ +// census: app_request_test, plugin_list_mount (SPEC R16; R6, R13b; violation hono-6-02) +// A plugin SDK: definePlugin copies `routes` and `register` from its input; mountPlugin mounts one plugin's +// priority-sorted routes and calls its register(app); registerPluginRoutes mounts a filtered, dependency-sorted list. +// Production and several tests each call these helpers on their OWN app. A route belongs only to the app that the +// call which brought its plugin was given: test plugins never reach the production app or another test's app. +import type { Hono } from 'hono' + +export interface PluginRoute { path: string; handler: Hono; priority?: number } +export interface Plugin { + name: string + dependencies?: string[] + routes?: PluginRoute[] + register?: (app: Hono) => void +} +export interface MountLog { mounted: string[]; skipped: string[] } + +export function definePlugin(input: { id: string; routes?: PluginRoute[]; register?: (app: Hono) => void }): Plugin { + if (!input.id) throw new Error('id is required') + return { name: input.id, routes: input.routes, register: input.register } +} + +function byPriority(routes: PluginRoute[]): PluginRoute[] { + return routes + .map((route, index) => ({ route, index })) + .sort((a, b) => (b.route.priority ?? 0) - (a.route.priority ?? 0) || a.index - b.index) + .map((e) => e.route) +} + +export function mountPlugin(app: Hono, plugin: Plugin, log?: MountLog): void { + if (!plugin || !plugin.name) return + if (Array.isArray(plugin.routes) && plugin.routes.length > 0) { + for (const route of byPriority(plugin.routes)) { + if (!route.path || !route.handler) continue + app.route(route.path, route.handler) + log?.mounted.push(route.path) + } + } + if (typeof plugin.register === 'function') plugin.register(app) +} + +function dependencyOrder(plugins: ReadonlyArray): T[] { + const byName = new Map() + for (const p of plugins) byName.set(p.name, p) + const out: T[] = [] + const done = new Set() + function visit(p: T): void { + if (done.has(p.name)) return + done.add(p.name) + for (const d of p.dependencies ?? []) { + const dep = byName.get(d) + if (dep) visit(dep) + } + out.push(p) + } + for (const p of plugins) visit(p) + return out +} + +export function registerPluginRoutes(app: Hono, plugins: Array, opts: { sort?: boolean } = {}): MountLog { + const log: MountLog = { mounted: [], skipped: [] } + const kept = (opts.sort ?? true) + ? dependencyOrder(plugins.filter((p): p is Plugin => !!p)) + : plugins.filter((p): p is Plugin => !!p) + for (const plugin of kept) { + const before = log.mounted.length + mountPlugin(app, plugin, log) + if (log.mounted.length === before) log.skipped.push(plugin.name) + } + return log +} diff --git a/graph/test/typescript/hono/cases/compose/typed-property-receiver/src/index.ts b/graph/test/typescript/hono/cases/compose/typed-property-receiver/src/index.ts new file mode 100644 index 000000000..763e8ead5 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/typed-property-receiver/src/index.ts @@ -0,0 +1,20 @@ +// census: route_mount_literal (violation hono-1-01; SPEC R2) +// route() on a receiver DECLARED as Hono (an interface property) whose value the program never shows: a mount +// on an app of unknown prefix. The child's route is partial (unresolved_app_value), never a root route at /raw. +import { Hono } from 'hono' + +interface ServerCtx { + server: Hono +} + +class StatusController { + getController() { + const h = new Hono() + h.get('/raw', (c) => c.text('raw')) + return h + } +} + +export function register(ctx: ServerCtx) { + ctx.server.route('/api/status', new StatusController().getController()) +} diff --git a/graph/test/typescript/hono/cases/compose/uncalled-start-server/src/api.ts b/graph/test/typescript/hono/cases/compose/uncalled-start-server/src/api.ts new file mode 100644 index 000000000..2674e18c7 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/uncalled-start-server/src/api.ts @@ -0,0 +1,4 @@ +import { Hono } from 'hono' + +export const api = new Hono() +api.get('/status', (c) => c.text('up')) diff --git a/graph/test/typescript/hono/cases/compose/uncalled-start-server/src/server.ts b/graph/test/typescript/hono/cases/compose/uncalled-start-server/src/server.ts new file mode 100644 index 000000000..cf2a2c182 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/uncalled-start-server/src/server.ts @@ -0,0 +1,11 @@ +// census: app_factory_fn (oracle gap O2) +// The server is assembled inside a function no module in the program calls (its caller is a CLI outside it): +// the sub-app is mounted under /api, not served bare. +import { Hono } from 'hono' +import { api } from './api' + +export function startServer(port: number) { + const app = new Hono() + app.route('/api', api) + return { app, port } +} diff --git a/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/apps/api/src/index.ts b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/apps/api/src/index.ts new file mode 100644 index 000000000..b48b17f21 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/apps/api/src/index.ts @@ -0,0 +1,14 @@ +// census: workspace_subpath (SPEC R22a; violation hono-5-06's shape) +// The app imports `@acme/core/adapters`, a subpath the workspace package's `exports` does not list, under +// moduleResolution bundler. The TypeScript compiler enforces `exports` in this mode and refuses the import, so the +// binding is unknown: the mount is unresolved and nothing is served under /adapters. (The adapters module's own app, +// which nothing mounts, keeps the root row every never-mounted exported app gets; that is not R22a's to change.) +import { Hono } from 'hono' +// @ts-expect-error -- not exported by @acme/core under moduleResolution bundler (the compiler refuses it) +import { adapters } from '@acme/core/adapters' + +const app = new Hono() +app.get('/health', (c) => c.text('ok')) +app.route('/adapters', adapters) + +export default app diff --git a/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/apps/api/tsconfig.json b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/apps/api/tsconfig.json new file mode 100644 index 000000000..b34b8ae7c --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/apps/api/tsconfig.json @@ -0,0 +1 @@ +{ "compilerOptions": { "target": "es2022", "module": "esnext", "moduleResolution": "bundler", "strict": true }, "include": ["src"] } diff --git a/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/adapters/index.ts b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/adapters/index.ts new file mode 100644 index 000000000..9532fe3cd --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/adapters/index.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +// a sub-app in a subpath the package's `exports` does not list +export const adapters = new Hono() +adapters.get('/list', (c) => c.json([])) diff --git a/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/index.ts b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/index.ts new file mode 100644 index 000000000..168f0cfa2 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/index.ts @@ -0,0 +1 @@ +export const coreVersion = '1' diff --git a/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/package.json b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/package.json new file mode 100644 index 000000000..cf76582b8 --- /dev/null +++ b/graph/test/typescript/hono/cases/compose/workspace-unlisted-subpath-bundler/src/packages/core/package.json @@ -0,0 +1 @@ +{ "name": "@acme/core", "version": "1.0.0", "exports": { ".": "./index.ts" } } diff --git a/graph/test/typescript/hono/cases/context/chain-of-setters/src/index.ts b/graph/test/typescript/hono/cases/context/chain-of-setters/src/index.ts new file mode 100644 index 000000000..008f2d9cd --- /dev/null +++ b/graph/test/typescript/hono/cases/context/chain-of-setters/src/index.ts @@ -0,0 +1,20 @@ +// census: ctx_set, ctx_get, verb_multi_handler +// Per-route middleware sets a key a later per-route middleware and the handler read. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +type Env = { Variables: { lang: string; greeting: string } } + +const detectLang: MiddlewareHandler = async (c, next) => { + c.set('lang', 'en') + await next() +} +const greet: MiddlewareHandler = async (c, next) => { + c.set('greeting', c.get('lang') === 'en' ? 'hello' : 'hallo') + await next() +} + +const app = new Hono() +app.get('/hello', detectLang, greet, (c) => c.text(`${c.var.greeting} (${c.get('lang')})`)) + +export default app diff --git a/graph/test/typescript/hono/cases/context/closure-access/src/index.ts b/graph/test/typescript/hono/cases/context/closure-access/src/index.ts new file mode 100644 index 000000000..c23adc7e2 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/closure-access/src/index.ts @@ -0,0 +1,20 @@ +// census: ctx_set_in_callback, ctx_get_in_callback +// A middleware writes a key, and a handler reads one, inside callbacks nested in them: the callbacks +// run during the request with the outer function's context, so the key still flows. +import { Hono } from 'hono' + +type Env = { Variables: { user: string; role: string } } +const app = new Hono() + +app.use(async (c, next) => { + await Promise.all([1].map(async () => c.set('user', 'u1'))) + c.set('role', 'admin') + await next() +}) +app.get('/', async (c) => { + const user = await Promise.resolve().then(() => c.get('user')) + const role = [0].map(() => c.var.role)[0] + return c.json({ user, role }) +}) + +export default app diff --git a/graph/test/typescript/hono/cases/context/cross-module/src/auth.ts b/graph/test/typescript/hono/cases/context/cross-module/src/auth.ts new file mode 100644 index 000000000..908c82472 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/cross-module/src/auth.ts @@ -0,0 +1,8 @@ +import { createMiddleware } from 'hono/factory' + +export type AuthEnv = { Variables: { session: { id: string } } } + +export const session = createMiddleware(async (c, next) => { + c.set('session', { id: 's1' }) + await next() +}) diff --git a/graph/test/typescript/hono/cases/context/cross-module/src/index.ts b/graph/test/typescript/hono/cases/context/cross-module/src/index.ts new file mode 100644 index 000000000..5321950b0 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/cross-module/src/index.ts @@ -0,0 +1,12 @@ +// census: ctx_set, ctx_get, route_mount_literal +// The setter is in one module, the readers in a sub-app in another; the flow follows the mounted chain. +// A function that sets then reads the same key flows to itself (SPEC 3.4, j == i only when it reads after). +import { Hono } from 'hono' +import { session, type AuthEnv } from './auth' +import { account } from './routes' + +const app = new Hono() +app.use('/account/*', session) +app.route('/account', account) + +export default app diff --git a/graph/test/typescript/hono/cases/context/cross-module/src/routes.ts b/graph/test/typescript/hono/cases/context/cross-module/src/routes.ts new file mode 100644 index 000000000..265223b2d --- /dev/null +++ b/graph/test/typescript/hono/cases/context/cross-module/src/routes.ts @@ -0,0 +1,11 @@ +import { Hono } from 'hono' +import type { AuthEnv } from './auth' + +export const account = new Hono() + +account.get('/', (c) => c.json(c.get('session'))) +account.delete('/', async (c, next) => { + const s = c.var.session + c.set('session', { id: '' }) + return c.json(s) +}) diff --git a/graph/test/typescript/hono/cases/context/destructured-var/src/index.ts b/graph/test/typescript/hono/cases/context/destructured-var/src/index.ts new file mode 100644 index 000000000..bd978fcd4 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/destructured-var/src/index.ts @@ -0,0 +1,25 @@ +// census: ctx_set, ctx_get_destructured, factory_init_app +// A middleware installed by the factory sets two keys; one handler reads them by destructuring +// the context's variables, another by name. +import { createFactory } from 'hono/factory' + +type Env = { Variables: { db: { url: string }; origin: string } } + +const factory = createFactory({ + initApp: (app) => { + app.use(async (c, next) => { + c.set('db', { url: 'pg://local' }) + c.set('origin', 'https://example.test') + await next() + }) + }, +}) + +const app = factory.createApp() +app.get('/both', (c) => { + const { db, origin: from } = c.var + return c.json({ url: db.url, from }) +}) +app.get('/one', (c) => c.text(c.var.origin)) + +export default app diff --git a/graph/test/typescript/hono/cases/context/early-return-next/src/index.ts b/graph/test/typescript/hono/cases/context/early-return-next/src/index.ts new file mode 100644 index 000000000..6484b04c8 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/early-return-next/src/index.ts @@ -0,0 +1,24 @@ +// census: ctx_set, ctx_get, ctx_next_in_branch +// A middleware that hands on early for some requests (`if (..) return next()`) and sets a key +// on the others: the set is before the `next()` that runs on its path, so the handler reads it. +import { Hono } from 'hono' + +type Env = { Variables: { user: string; role: string } } +const app = new Hono() + +app.use(async (c, next) => { + if (c.req.path === '/health') return next() + c.set('user', 'u1') + await next() +}) +app.use(async (c, next) => { + if (c.req.header('x-skip')) { + await next() + return + } + c.set('role', 'admin') + await next() +}) +app.get('/', (c) => c.json({ user: c.get('user'), role: c.var.role })) + +export default app diff --git a/graph/test/typescript/hono/cases/context/set-after-next/src/index.ts b/graph/test/typescript/hono/cases/context/set-after-next/src/index.ts new file mode 100644 index 000000000..fae73db13 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/set-after-next/src/index.ts @@ -0,0 +1,18 @@ +// census: ctx_set, ctx_get, ctx_set_after_next +// A middleware sets one key before handing on and another after the rest of the chain has +// returned: only the first is there when the handler reads it. The same middleware reads its +// late key back itself. +import { Hono } from 'hono' + +type Env = { Variables: { started: number; finished: number } } +const app = new Hono() + +app.use(async (c, next) => { + c.set('started', Date.now()) + await next() + c.set('finished', Date.now()) + c.header('x-elapsed', String(c.get('finished') - c.get('started'))) +}) +app.get('/', (c) => c.json({ started: c.var.started, finished: c.get('finished') })) + +export default app diff --git a/graph/test/typescript/hono/cases/context/set-get/src/index.ts b/graph/test/typescript/hono/cases/context/set-get/src/index.ts new file mode 100644 index 000000000..c754b46a7 --- /dev/null +++ b/graph/test/typescript/hono/cases/context/set-get/src/index.ts @@ -0,0 +1,22 @@ +// census: ctx_set, ctx_get, ctx_var, variables_type +// A middleware sets keys on the context; handlers read them by c.get and c.var; a reader with no +// setter on its chain is declared, not linked. +import { Hono } from 'hono' +import { createMiddleware } from 'hono/factory' + +type Env = { Variables: { user: string; tenant: string; traceId: string } } + +const loadUser = createMiddleware(async (c, next) => { + c.set('user', 'u1') + c.set('tenant', 't1') + await next() +}) + +const app = new Hono() +app.get('/before', (c) => c.text(c.get('user') ?? 'no setter ran before this route')) +app.use(loadUser) +app.get('/me', (c) => c.text(c.get('user'))) +app.get('/tenant', (c) => c.text(c.var.tenant)) +app.get('/trace', (c) => c.text(c.var.traceId ?? 'never set')) + +export default app diff --git a/graph/test/typescript/hono/cases/deno/denoland-url/src/deno.json b/graph/test/typescript/hono/cases/deno/denoland-url/src/deno.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/denoland-url/src/deno.json @@ -0,0 +1 @@ +{} diff --git a/graph/test/typescript/hono/cases/deno/denoland-url/src/main.ts b/graph/test/typescript/hono/cases/deno/denoland-url/src/main.ts new file mode 100644 index 000000000..10ae9aa9a --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/denoland-url/src/main.ts @@ -0,0 +1,10 @@ +// census: none (corpus gap). https://deno.land/x/hono@v3.x/mod.ts and /middleware.ts: shape from Hono's Deno docs (v3 era), corpus gap. +// Oracle maps mod.ts to the pinned hono and middleware.ts to a re-export of its built-ins. +import { Hono } from 'https://deno.land/x/hono@v3.12.11/mod.ts' +import { etag } from 'https://deno.land/x/hono@v3.12.11/middleware.ts' + +const app = new Hono() +app.use(etag()) +app.get('/url', (c) => c.text('url')) + +export default app diff --git a/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/deno.json b/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/deno.json new file mode 100644 index 000000000..7bf44f9bb --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/deno.json @@ -0,0 +1,7 @@ +{ + "imports": { + "hono": "jsr:@hono/hono@^4", + "hono/": "jsr:@hono/hono@^4/" + }, + "tasks": { "start": "deno serve main.ts" } +} diff --git a/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/main.ts b/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/main.ts new file mode 100644 index 000000000..47d1f82d2 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/main.ts @@ -0,0 +1,12 @@ +// census: route_mount_literal, export_default_app; bare 'hono' mapped by deno.json imports (exact and the +// "hono/" prefix map), .ts-extension relative imports, `export default app` run by `deno serve`. +// The one corpus Deno shape (deno.json import map). Oracle applies the import map. +import { Hono } from 'hono' +import { secureHeaders } from 'hono/secure-headers' +import { users } from './routes/users.ts' + +const app = new Hono() +app.use(secureHeaders()) +app.route('/users', users) + +export default app diff --git a/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/routes/users.ts b/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/routes/users.ts new file mode 100644 index 000000000..f219b0911 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-deno-json/src/routes/users.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +export const users = new Hono() +users.get('/', (c) => c.json([])) +users.get('/:id', (c) => c.json({ id: c.req.param('id') })) diff --git a/graph/test/typescript/hono/cases/deno/import-map-file/src/import_map.json b/graph/test/typescript/hono/cases/deno/import-map-file/src/import_map.json new file mode 100644 index 000000000..19a8b0bc6 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-file/src/import_map.json @@ -0,0 +1,6 @@ +{ + "imports": { + "hono": "npm:hono@4", + "hono/": "npm:hono@4/" + } +} diff --git a/graph/test/typescript/hono/cases/deno/import-map-file/src/main.ts b/graph/test/typescript/hono/cases/deno/import-map-file/src/main.ts new file mode 100644 index 000000000..6d057b43f --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-file/src/main.ts @@ -0,0 +1,13 @@ +// census: none (corpus gap). a standalone import_map.json mapping bare hono to npm:hono@4 (prefix map for hono/*): shape from Hono's +// Deno docs, corpus gap. +import { Hono } from 'hono' +import { createMiddleware } from 'hono/factory' + +const timer = createMiddleware(async (c, next) => { + await next() +}) +const app = new Hono() +app.use(timer) +app.get('/mapped', (c) => c.text('mapped')) + +export default { fetch: app.fetch } diff --git a/graph/test/typescript/hono/cases/deno/import-map-jsonc/src/deno.jsonc b/graph/test/typescript/hono/cases/deno/import-map-jsonc/src/deno.jsonc new file mode 100644 index 000000000..a2f2a65f6 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-jsonc/src/deno.jsonc @@ -0,0 +1,6 @@ +{ + // comments are allowed here + "imports": { + "@hono/hono": "jsr:@hono/hono@^4" /* the bare JSR name */ + } +} diff --git a/graph/test/typescript/hono/cases/deno/import-map-jsonc/src/main.ts b/graph/test/typescript/hono/cases/deno/import-map-jsonc/src/main.ts new file mode 100644 index 000000000..2dfc10c3e --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/import-map-jsonc/src/main.ts @@ -0,0 +1,7 @@ +// census: none (corpus gap). bare JSR name `@hono/hono` mapped by deno.jsonc (comments stripped): shape from Hono's Deno docs, corpus gap. +import { Hono } from '@hono/hono' + +const app = new Hono() +app.get('/jsonc', (c) => c.text('jsonc')) + +Deno.serve(app.fetch) diff --git a/graph/test/typescript/hono/cases/deno/jsr-specifier/src/deno.json b/graph/test/typescript/hono/cases/deno/jsr-specifier/src/deno.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/jsr-specifier/src/deno.json @@ -0,0 +1 @@ +{} diff --git a/graph/test/typescript/hono/cases/deno/jsr-specifier/src/main.ts b/graph/test/typescript/hono/cases/deno/jsr-specifier/src/main.ts new file mode 100644 index 000000000..bc9a7d310 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/jsr-specifier/src/main.ts @@ -0,0 +1,11 @@ +// census: deno_serve. jsr:@hono/hono and jsr:@hono/hono@^4/logger specifiers are a shape from Hono's Deno +// docs, corpus gap. The oracle maps jsr:/npm:/URL hono specifiers to the pinned hono types (oracle-only +// resolution host); the runtime half cannot load them under node and says so. +import { Hono } from 'jsr:@hono/hono' +import { logger } from 'jsr:@hono/hono@^4/logger' + +const app = new Hono() +app.use(logger()) +app.get('/jsr', (c) => c.text('jsr')) + +Deno.serve(app.fetch) diff --git a/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/deno.json b/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/deno.json new file mode 100644 index 000000000..58b00fb7e --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/deno.json @@ -0,0 +1 @@ +{ "imports": { "hono": "jsr:@hono/hono@4.7.10", "hono/": "jsr:@hono/hono@4.7.10/" } } diff --git a/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/main.ts b/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/main.ts new file mode 100644 index 000000000..283d6b4e4 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/main.ts @@ -0,0 +1,8 @@ +// census: deno_serve (shape of a Deno holdout project: a deno.json import map to jsr:, below the repository root, +// and an app created by a static method; served with Deno.serve({ port }, fetch)) +import { Routes } from './routes.ts' + +const hono = Routes.initHono('/static') +hono.get('/logo.jpg', (c) => c.text('jpg')) + +Deno.serve({ port: 8000 }, hono.fetch) diff --git a/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/routes.ts b/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/routes.ts new file mode 100644 index 000000000..9a601f0e6 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/jsr-static-method/src/api/routes.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +export class Routes { + static initHono(base: string) { + return new Hono().basePath(base) + } +} diff --git a/graph/test/typescript/hono/cases/deno/npm-specifier/src/deno.json b/graph/test/typescript/hono/cases/deno/npm-specifier/src/deno.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/npm-specifier/src/deno.json @@ -0,0 +1 @@ +{} diff --git a/graph/test/typescript/hono/cases/deno/npm-specifier/src/main.ts b/graph/test/typescript/hono/cases/deno/npm-specifier/src/main.ts new file mode 100644 index 000000000..6e771f6ab --- /dev/null +++ b/graph/test/typescript/hono/cases/deno/npm-specifier/src/main.ts @@ -0,0 +1,10 @@ +// census: none (corpus gap). npm:hono@4 and npm:hono/cors specifiers: shape from Hono's Deno docs, corpus gap. Oracle maps them to the +// pinned hono types. +import { Hono } from 'npm:hono@4' +import { cors } from 'npm:hono/cors' + +const app = new Hono() +app.use('/api/*', cors()) +app.get('/api/npm', (c) => c.text('npm')) + +Deno.serve({ port: 8000 }, app.fetch) diff --git a/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/index.ts b/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/index.ts new file mode 100644 index 000000000..c63f18a5d --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/index.ts @@ -0,0 +1,13 @@ +// census: app_factory_fn, export_default_fetch_obj (oracle gap O4, SPEC R4) +// The app comes from a tsconfig-path-aliased module, and the default export is a custom object whose fetch +// forwards to the app's fetch: a served shape, and the forwarding call is no request of its own. +import { newApp } from '@/lib/app' + +const app = newApp() +app.get('/aliased', (c) => c.text('aliased')) + +export default { + fetch(req: Request, env: unknown, ctx: any) { + return app.fetch(req, env, ctx) + }, +} diff --git a/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/lib/app.ts b/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/lib/app.ts new file mode 100644 index 000000000..a628cb589 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/lib/app.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +export function newApp() { + return new Hono() +} diff --git a/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/tsconfig.json b/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/tsconfig.json new file mode 100644 index 000000000..711f00614 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/aliased-app-fetch-wrapper/src/tsconfig.json @@ -0,0 +1 @@ +{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./*"] } } } diff --git a/graph/test/typescript/hono/cases/entry/app-request-test/src/app.test.ts b/graph/test/typescript/hono/cases/entry/app-request-test/src/app.test.ts new file mode 100644 index 000000000..55fcdafad --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/app-request-test/src/app.test.ts @@ -0,0 +1,30 @@ +// census: app_request_test, test_client +// Tests that hit routes through app.request and testClient: each test function reaches its route. +import { testClient } from 'hono/testing' +import { app } from './app' + +export async function healthIsOk() { + const res = await app.request('/health') + return res.status === 200 +} + +export async function createsItem() { + const res = await app.request('/items', { method: 'POST', body: '{}' }) + return res.status === 201 +} + +export async function readsOneItem() { + const res = await app.request('/items/42') + return res.status +} + +export async function viaTestClient() { + const client = testClient(app) + const res = await client.health.$get() + return res.status +} + +export async function missesEveryRoute() { + const res = await app.request('/nowhere') + return res.status +} diff --git a/graph/test/typescript/hono/cases/entry/app-request-test/src/app.ts b/graph/test/typescript/hono/cases/entry/app-request-test/src/app.ts new file mode 100644 index 000000000..31939f36b --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/app-request-test/src/app.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +export const app = new Hono() + .get('/health', (c) => c.text('ok')) + .post('/items', (c) => c.json({}, 201)) + .get('/items/:id', (c) => c.json({ id: c.req.param('id') })) diff --git a/graph/test/typescript/hono/cases/entry/deno-bun/src/index.ts b/graph/test/typescript/hono/cases/entry/deno-bun/src/index.ts new file mode 100644 index 000000000..adfd56e43 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/deno-bun/src/index.ts @@ -0,0 +1,14 @@ +// census: deno_serve, bun_serve +// Deno.serve(app.fetch) and Bun.serve({ fetch }) (runtime globals declared locally so the fixture typechecks). +import { Hono } from 'hono' + +declare const Deno: { serve(handler: (req: Request) => Response | Promise): void } +declare const Bun: { serve(opts: { fetch: (req: Request) => Response | Promise }): void } + +export const app = new Hono() +app.get('/deno', (c) => c.text('deno')) + +export function start(kind: 'deno' | 'bun') { + if (kind === 'deno') Deno.serve(app.fetch) + else Bun.serve({ fetch: app.fetch }) +} diff --git a/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/admin.ts b/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/admin.ts new file mode 100644 index 000000000..8891d2f4a --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/admin.ts @@ -0,0 +1,3 @@ +import { Hono } from 'hono' + +export const adminRoutes = new Hono().get('/stats', (c) => c.json({ n: 0 })) diff --git a/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/skills.test.ts b/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/skills.test.ts new file mode 100644 index 000000000..d3623afdf --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/skills.test.ts @@ -0,0 +1,29 @@ +// census: app_request_test (oracle gap O16; SPEC R1) +// Test apps mount sub-apps bound by `const { x } = await import('./m.ts')` (at module level and inside a test): +// the test apps are roots, the requests reach the mounted routes, nothing is unserved. +import { Hono } from 'hono' + +declare function it(name: string, fn: () => unknown): void + +const { skillsRoutes } = await import('./skills.ts') + +const testApp = new Hono() + .use('*', async (c, next) => { + c.header('x-test', '1') + await next() + }) + .route('/', skillsRoutes) + +it('reads a skill', async () => { + await testApp.request('/acme/review') +}) + +it('publishes a skill', async () => { + await testApp.request('/acme/review', { method: 'POST', body: '{}' }) +}) + +it('reads admin stats', async () => { + const { adminRoutes } = await import('./admin.ts') + const app = new Hono().route('/admin', adminRoutes) + await app.request('/admin/stats') +}) diff --git a/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/skills.ts b/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/skills.ts new file mode 100644 index 000000000..39d10bbb8 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/dynamic-import-test-app/src/skills.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +export const skillsRoutes = new Hono() + .get('/:ns/:name', (c) => c.json({ ns: c.req.param('ns'), name: c.req.param('name') })) + .post('/:ns/:name', (c) => c.json({ ok: true }, 201)) diff --git a/graph/test/typescript/hono/cases/entry/fetch-object/src/index.ts b/graph/test/typescript/hono/cases/entry/fetch-object/src/index.ts new file mode 100644 index 000000000..2a3a61e90 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/fetch-object/src/index.ts @@ -0,0 +1,18 @@ +// census: export_default_fetch_obj, app_fetch_ref +// A Workers-style default export: fetch is the app; scheduled and queue are called by the platform. +import { Hono } from 'hono' + +const app = new Hono() +app.get('/', (c) => c.text('worker')) + +async function scheduled(event: unknown) { + return event +} + +export default { + fetch: app.fetch, + scheduled, + async queue(batch: unknown) { + return batch + }, +} diff --git a/graph/test/typescript/hono/cases/entry/fixture-prop-request/src/app.test.ts b/graph/test/typescript/hono/cases/entry/fixture-prop-request/src/app.test.ts new file mode 100644 index 000000000..33ab6d4b6 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/fixture-prop-request/src/app.test.ts @@ -0,0 +1,15 @@ +// census: app_request_test (violation hono-2-06) +// A request on an app held in a property of the object a test helper returns reaches the route. +import { createApp } from './app' + +declare function test(name: string, fn: () => Promise): void + +async function setupFixture() { + const dir = '/tmp/x' + return { dir, app: createApp(dir) } +} + +test('flow', async () => { + const fixture = await setupFixture() + await fixture.app.request('http://localhost/api/flow') +}) diff --git a/graph/test/typescript/hono/cases/entry/fixture-prop-request/src/app.ts b/graph/test/typescript/hono/cases/entry/fixture-prop-request/src/app.ts new file mode 100644 index 000000000..2a050f895 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/fixture-prop-request/src/app.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +export function createApp(dir: string) { + const app = new Hono() + app.get('/api/flow', (c) => c.text(dir)) + return app +} diff --git a/graph/test/typescript/hono/cases/entry/jsx-render/src/components.tsx b/graph/test/typescript/hono/cases/entry/jsx-render/src/components.tsx new file mode 100644 index 000000000..22bbeecdb --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/jsx-render/src/components.tsx @@ -0,0 +1,10 @@ +/** @jsxImportSource hono/jsx */ +import type { FC } from 'hono/jsx' + +export const Layout: FC = (props) => ( + + {props.children} + +) + +export const Greeting: FC<{ name: string }> = ({ name }) =>

Hello {name}

diff --git a/graph/test/typescript/hono/cases/entry/jsx-render/src/index.tsx b/graph/test/typescript/hono/cases/entry/jsx-render/src/index.tsx new file mode 100644 index 000000000..052e9d02a --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/jsx-render/src/index.tsx @@ -0,0 +1,15 @@ +/** @jsxImportSource hono/jsx */ +// census: c_render, jsx_import +// hono/jsx components rendered through c.html, and c.render under jsxRenderer: SPEC 3.8 gives them no Hono +// semantics, so the handlers are routes and entries, jsxRenderer is middleware, and the components are +// neither routes, middleware nor entries. +import { Hono } from 'hono' +import { jsxRenderer } from 'hono/jsx-renderer' +import { Layout, Greeting } from './components' + +const app = new Hono() +app.get('/html', (c) => c.html()) +app.use('/page/*', jsxRenderer(({ children }) => {children})) +app.get('/page/hello', (c) => c.render()) + +export default app diff --git a/graph/test/typescript/hono/cases/entry/node-serve/src/index.ts b/graph/test/typescript/hono/cases/entry/node-serve/src/index.ts new file mode 100644 index 000000000..0903ba2f5 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/node-serve/src/index.ts @@ -0,0 +1,9 @@ +// census: serve_fetch +// Served with serve({ fetch: app.fetch }) from the node adapter; nothing is exported. +import { Hono } from 'hono' +import { serve } from '@hono/node-server' + +const app = new Hono() +app.get('/served', (c) => c.text('served')) + +serve({ fetch: app.fetch, port: 8787 }) diff --git a/graph/test/typescript/hono/cases/entry/notfound-onerror/src/index.ts b/graph/test/typescript/hono/cases/entry/notfound-onerror/src/index.ts new file mode 100644 index 000000000..9c17ba302 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/notfound-onerror/src/index.ts @@ -0,0 +1,12 @@ +// census: not_found, on_error +// notFound and onError handlers are http entry points, not routes. +import { Hono } from 'hono' + +const app = new Hono() +app.get('/boom', () => { + throw new Error('boom') +}) +app.notFound((c) => c.text('custom 404', 404)) +app.onError((err, c) => c.text(`custom 500: ${err.message}`, 500)) + +export default app diff --git a/graph/test/typescript/hono/cases/entry/request-object-and-fetch/src/app.test.ts b/graph/test/typescript/hono/cases/entry/request-object-and-fetch/src/app.test.ts new file mode 100644 index 000000000..01bc6a3ae --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/request-object-and-fetch/src/app.test.ts @@ -0,0 +1,18 @@ +// census: app_request_test, app_fetch_ref +// Tests that build a Request object, through app.request(new Request(...)) and app.fetch(req, env). +import { app } from './app' + +export async function viaRequestObject() { + const res = await app.request(new Request('http://localhost/ping')) + return res.status +} + +export async function viaFetchWithInit() { + const res = await app.fetch(new Request('http://localhost/items/7', { method: 'PUT' }), { DB: 'test' }) + return res.status +} + +export async function viaRequestWithInit() { + const res = await app.request(new Request('http://localhost/items/8', { method: 'PUT' })) + return res.status +} diff --git a/graph/test/typescript/hono/cases/entry/request-object-and-fetch/src/app.ts b/graph/test/typescript/hono/cases/entry/request-object-and-fetch/src/app.ts new file mode 100644 index 000000000..0755de163 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/request-object-and-fetch/src/app.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +export const app = new Hono() +app.get('/ping', (c) => c.text('pong')) +app.put('/items/:id', (c) => c.text('put')) diff --git a/graph/test/typescript/hono/cases/entry/test-built-app/src/app.test.ts b/graph/test/typescript/hono/cases/entry/test-built-app/src/app.test.ts new file mode 100644 index 000000000..f455fc302 --- /dev/null +++ b/graph/test/typescript/hono/cases/entry/test-built-app/src/app.test.ts @@ -0,0 +1,16 @@ +// census: app_request_test (SPEC R1: oracle gap O1/O5) +// An app built INSIDE a test callback and exercised with app.request is a served root: its routes are +// http_route rows and the request reaches them. +import { Hono } from 'hono' + +declare function describe(name: string, fn: () => void): void +declare function it(name: string, fn: () => Promise | void): void + +describe('health', () => { + it('answers', async () => { + const app = new Hono() + app.get('/health', (c) => c.text('ok')) + const res = await app.request('/health') + if (res.status !== 200) throw new Error('down') + }) +}) diff --git a/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/index.ts b/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/index.ts new file mode 100644 index 000000000..61483b7d1 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/index.ts @@ -0,0 +1,14 @@ +// census: use_global (oracle gap O14) +// Library middleware re-exported through a project barrel (`export { cors } from 'hono/cors'`, a renamed export, +// `export *`) is still the library middleware at its registering call, in order, with no dynamic list. +import { Hono } from 'hono' +import { audit, cors, requestLog, secureHeaders } from './middleware' + +const app = new Hono() +app.use('*', requestLog()) +app.use('*', cors({ origin: '*' })) +app.use('/api/*', secureHeaders(), audit) +app.get('/api/me', (c) => c.json({ id: 1 })) +app.get('/health', (c) => c.text('ok')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/middleware/audit.ts b/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/middleware/audit.ts new file mode 100644 index 000000000..94141fe11 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/middleware/audit.ts @@ -0,0 +1,6 @@ +import { createMiddleware } from 'hono/factory' + +export const audit = createMiddleware(async (c, next) => { + await next() + c.header('x-audited', '1') +}) diff --git a/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/middleware/index.ts b/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/middleware/index.ts new file mode 100644 index 000000000..6b1afd792 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/barrel-library-mw/src/middleware/index.ts @@ -0,0 +1,4 @@ +export { cors } from 'hono/cors' +export { logger as requestLog } from 'hono/logger' +export * from 'hono/secure-headers' +export { audit } from './audit' diff --git a/graph/test/typescript/hono/cases/middleware/builtin/src/index.ts b/graph/test/typescript/hono/cases/middleware/builtin/src/index.ts new file mode 100644 index 000000000..83ccf9d92 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/builtin/src/index.ts @@ -0,0 +1,16 @@ +// census: builtin_mw_import +// Built-in middleware are library calls: each is a middleware node at its registering expression. +import { Hono } from 'hono' +import { cors } from 'hono/cors' +import { logger } from 'hono/logger' +import { secureHeaders } from 'hono/secure-headers' +import { etag } from 'hono/etag' + +const app = new Hono() +app.use(logger()) +app.use('/api/*', cors()) +app.use('/api/*', secureHeaders(), etag()) +app.get('/api/data', (c) => c.json({})) +app.get('/', (c) => c.text('home')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/combine/src/index.ts b/graph/test/typescript/hono/cases/middleware/combine/src/index.ts new file mode 100644 index 000000000..8b58cb62b --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/combine/src/index.ts @@ -0,0 +1,19 @@ +// census: combine_every_some_except +// hono/combine: the combinator call is the middleware node at its registering expression. +import { Hono } from 'hono' +import { every, some, except } from 'hono/combine' +import type { MiddlewareHandler } from 'hono' + +const isAdmin: MiddlewareHandler = async (c, next) => { await next() } +const hasToken: MiddlewareHandler = async (c, next) => { await next() } +const isLocal: MiddlewareHandler = async (c, next) => { await next() } + +const app = new Hono() +app.use('/admin/*', every(isAdmin, hasToken)) +app.use('/ops/*', some(isLocal, hasToken)) +app.use('*', except('/health', hasToken)) +app.get('/admin/panel', (c) => c.text('panel')) +app.get('/ops/status', (c) => c.text('status')) +app.get('/health', (c) => c.text('ok')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/conditional-lib-mw/src/index.ts b/graph/test/typescript/hono/cases/middleware/conditional-lib-mw/src/index.ts new file mode 100644 index 000000000..20d8f2822 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/conditional-lib-mw/src/index.ts @@ -0,0 +1,16 @@ +// census: use_conditional_loop (stress-5 mutation m40 shape; violation hono-5-04) +// A library middleware registered in each branch of an if/else: both are on the chain with +// conditional_registration, each keyed at its own call. +import { Hono } from 'hono' +import { logger } from 'hono/logger' + +declare const process: { env: Record } + +const app = new Hono() +if (process.env.NODE_ENV !== 'production') { + app.use('*', logger()) +} else { + app.use('*', logger((m: string) => console.error(m))) +} +app.get('/x', (c) => c.text('x')) +export default app diff --git a/graph/test/typescript/hono/cases/middleware/const-library-mw/src/index.ts b/graph/test/typescript/hono/cases/middleware/const-library-mw/src/index.ts new file mode 100644 index 000000000..c77e4672a --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/const-library-mw/src/index.ts @@ -0,0 +1,35 @@ +// census: use_scoped (stress-4 mutation m31 shapes; violation hono-4-07, SPEC R10/R11) +// A library middleware bound to a const before use(): at module level, inside a builder, and inside a branch of a +// builder. Each is keyed at the jwt(...) call (library_call), never at the identifier. +import { Hono } from 'hono' +import { jwt } from 'hono/jwt' + +declare const process: { env: Record } + +const api = new Hono() +const apiJwt = jwt({ alg: 'HS256', secret: process.env.SECRET ?? 'dev' }) +api.use('/v1/*', apiJwt) +api.get('/v1/me', (c) => c.json({ me: true })) + +export function buildAdmin(secret: string) { + const admin = new Hono() + const adminJwt = jwt({ alg: 'HS256', secret }) + admin.use('/admin/*', adminJwt) + admin.get('/admin/users', (c) => c.json([])) + return admin +} + +export function buildPartner(cfg: { devMode: boolean; secret: string }) { + const partner = new Hono() + if (!cfg.devMode) { + const partnerJwt = jwt({ alg: 'HS256', secret: cfg.secret }) + partner.use('/partner/*', partnerJwt) + } + partner.get('/partner/orders', (c) => c.json([])) + return partner +} + +api.route('/', buildAdmin(process.env.ADMIN_SECRET ?? 'dev')) +api.route('/', buildPartner({ devMode: false, secret: 'p' })) + +export default api diff --git a/graph/test/typescript/hono/cases/middleware/detached-factory-method/src/factory.ts b/graph/test/typescript/hono/cases/middleware/detached-factory-method/src/factory.ts new file mode 100644 index 000000000..e220fdfbb --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/detached-factory-method/src/factory.ts @@ -0,0 +1,11 @@ +import { createFactory } from 'hono/factory' + +type AdminEnv = { Variables: { role: string } } + +export function createTierFactory() { + return createFactory() +} + +const adminFactory = createTierFactory() +export const createAdminMiddleware = adminFactory.createMiddleware +export const createAdminHandlers = adminFactory.createHandlers diff --git a/graph/test/typescript/hono/cases/middleware/detached-factory-method/src/index.ts b/graph/test/typescript/hono/cases/middleware/detached-factory-method/src/index.ts new file mode 100644 index 000000000..fe599d25d --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/detached-factory-method/src/index.ts @@ -0,0 +1,23 @@ +// census: create_middleware (oracle gap O17) +// `createMiddleware` / `createHandlers` read off a factory into consts and called later: the middleware is the +// function passed in, at its chain position; the handlers spread into the route in order. +import { Hono } from 'hono' +import { createAdminHandlers, createAdminMiddleware } from './factory' + +const requireAdmin = createAdminMiddleware(async (c, next) => { + c.set('role', 'admin') + await next() +}) + +const listUsers = createAdminHandlers( + async (_c, next) => { + await next() + }, + (c) => c.json({ role: c.get('role') }), +) + +const app = new Hono<{ Variables: { role: string } }>() +app.use('/admin/*', requireAdmin) +app.get('/admin/users', ...listUsers) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/factory-fn/src/index.ts b/graph/test/typescript/hono/cases/middleware/factory-fn/src/index.ts new file mode 100644 index 000000000..53ba22bc1 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-fn/src/index.ts @@ -0,0 +1,10 @@ +// census: mw_factory_returning_fn, create_middleware +// A project middleware factory: the middleware is the INNER function the factory returns. +import { Hono } from 'hono' +import { rateLimit, requestId } from './mw' + +const app = new Hono() +app.use(requestId('req')) +app.get('/limited', rateLimit({ max: 10 }), (c) => c.text('ok')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/factory-fn/src/mw.ts b/graph/test/typescript/hono/cases/middleware/factory-fn/src/mw.ts new file mode 100644 index 000000000..371397e96 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-fn/src/mw.ts @@ -0,0 +1,13 @@ +import type { MiddlewareHandler } from 'hono' + +export function rateLimit(opts: { max: number }): MiddlewareHandler { + return async (c, next) => { + if (opts.max < 0) return c.text('limited', 429) + await next() + } +} + +export const requestId = (prefix: string): MiddlewareHandler => async (c, next) => { + c.header('x-request-id', prefix) + await next() +} diff --git a/graph/test/typescript/hono/cases/middleware/factory-handlers/src/index.ts b/graph/test/typescript/hono/cases/middleware/factory-handlers/src/index.ts new file mode 100644 index 000000000..3d7a30fee --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-handlers/src/index.ts @@ -0,0 +1,22 @@ +// census: create_factory, factory_create_app, create_middleware +// createFactory: initApp registrations run first on every app createApp makes; createHandlers spreads +// its arguments into the route (middleware then handler); factory.createMiddleware's arg is the middleware. +import { createFactory } from 'hono/factory' + +const factory = createFactory({ + initApp: (app) => { + app.use(async (c, next) => { + await next() + }) + }, +}) + +const check = factory.createMiddleware(async (c, next) => { + await next() +}) +const handlers = factory.createHandlers(check, (c) => c.text('from createHandlers')) + +const app = factory.createApp() +app.get('/factory', ...handlers) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/factory-object-member/src/checks.ts b/graph/test/typescript/hono/cases/middleware/factory-object-member/src/checks.ts new file mode 100644 index 000000000..ff590e876 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-object-member/src/checks.ts @@ -0,0 +1,16 @@ +import type { MiddlewareHandler } from 'hono' + +// Two middleware in one returned object, one written inline: each read must take its own property's function. +export function makeChecks(realm: string) { + const auth: MiddlewareHandler = async (c, next) => { + if (!c.req.header('authorization')) return c.text(realm, 401) + await next() + } + return { + auth, + audit: (async (c, next) => { + await next() + console.log(realm, c.req.path) + }) as MiddlewareHandler, + } +} diff --git a/graph/test/typescript/hono/cases/middleware/factory-object-member/src/index.ts b/graph/test/typescript/hono/cases/middleware/factory-object-member/src/index.ts new file mode 100644 index 000000000..5f214f6d6 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-object-member/src/index.ts @@ -0,0 +1,18 @@ +// census: use_global, use_scoped, mw_factory_returning_fn (violation hono-7-04: middleware read off the object a +// factory returns was keyed as the property-read expression, not as the function) +// limiter.middleware is the arrow in limiter.ts; m.auth and m.audit are the two functions in checks.ts, each on its +// own scope. Control: a cross-assignment would put audit on /admin/* or auth on every route. +import { Hono } from 'hono' +import { limiter } from './limiter' +import { makeChecks } from './checks' + +const m = makeChecks('ops') + +const app = new Hono() +app.use('*', limiter.middleware) +app.use('/admin/*', m.auth) +app.use('*', m.audit) +app.get('/ping', (c) => c.text('pong')) +app.get('/admin/users', (c) => c.json([])) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/factory-object-member/src/limiter.ts b/graph/test/typescript/hono/cases/middleware/factory-object-member/src/limiter.ts new file mode 100644 index 000000000..0089c2cfd --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-object-member/src/limiter.ts @@ -0,0 +1,18 @@ +import type { MiddlewareHandler } from 'hono' + +// The factory returns an object: the middleware is one property, a counter reader the other. +export function createLimiter(opts: { limit: number }) { + let active = 0 + const middleware: MiddlewareHandler = async (c, next) => { + if (active >= opts.limit) return c.text('busy', 503) + active++ + try { + await next() + } finally { + active-- + } + } + return { middleware, active: () => active } +} + +export const limiter = createLimiter({ limit: 10 }) diff --git a/graph/test/typescript/hono/cases/middleware/factory-two-returns/src/index.ts b/graph/test/typescript/hono/cases/middleware/factory-two-returns/src/index.ts new file mode 100644 index 000000000..7865f6fa3 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/factory-two-returns/src/index.ts @@ -0,0 +1,25 @@ +// census: use_scoped (violation hono-3-03, SPEC 3.1 "resolve the return; if several, all", R10) +// A middleware factory returns a pass-through arrow in one branch and a library middleware otherwise: both are +// middleware of the chain at the same position; the library one is keyed at its call, its options callback is no +// middleware. +import { Hono } from 'hono' +import type { Context, Next } from 'hono' +import { basicAuth } from 'hono/basic-auth' + +declare const process: { env: Record } + +export function guard(realm: string) { + if (process.env.NODE_ENV !== 'production') { + return async (_c: Context, next: Next) => { + await next() + } + } + return basicAuth({ realm, verifyUser: (user, pass) => user === 'admin' && pass === realm }) +} + +const app = new Hono() +app.use('/admin/*', guard('ops')) +app.get('/admin/stats', (c) => c.json({ n: 1 })) +app.get('/public', (c) => c.text('hi')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/helper-app-mounted-thrice/src/routes.test.ts b/graph/test/typescript/hono/cases/middleware/helper-app-mounted-thrice/src/routes.test.ts new file mode 100644 index 000000000..8bdcd849d --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/helper-app-mounted-thrice/src/routes.test.ts @@ -0,0 +1,40 @@ +// census: app_request_test (stress-4 mutation m28 shape; violation hono-4-02, SPEC R6) +// A test helper builds a fresh app per call and a second helper mounts the same routes into it; three tests do so. +// Each call is its own app: the chain is [use 0, param validator 1, json validator 2] on every one, never positions +// accumulated across calls. +import { Hono } from 'hono' +import { profileRoutes } from './routes' + +declare function it(name: string, fn: () => unknown): void + +function makeTestApp() { + const app = new Hono<{ Variables: { actor: string } }>() + app.use('*', async (c, next) => { + c.set('actor', 'tester') + await next() + }) + return { app } +} + +function mountRoutes(app: Hono<{ Variables: { actor: string } }>) { + app.route('/', profileRoutes) + return app +} + +it('renames one', async () => { + const { app } = makeTestApp() + mountRoutes(app) + await app.request('/1/rename', { method: 'POST' }) +}) + +it('renames two', async () => { + const { app } = makeTestApp() + mountRoutes(app) + await app.request('/2/rename', { method: 'POST' }) +}) + +it('renames three', async () => { + const { app } = makeTestApp() + mountRoutes(app) + await app.request('/3/rename', { method: 'POST' }) +}) diff --git a/graph/test/typescript/hono/cases/middleware/helper-app-mounted-thrice/src/routes.ts b/graph/test/typescript/hono/cases/middleware/helper-app-mounted-thrice/src/routes.ts new file mode 100644 index 000000000..0628204f8 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/helper-app-mounted-thrice/src/routes.ts @@ -0,0 +1,10 @@ +import { Hono } from 'hono' +import { zValidator } from '@hono/zod-validator' +import { z } from 'zod' + +export const profileRoutes = new Hono().post( + '/:id/rename', + zValidator('param', z.object({ id: z.string() })), + zValidator('json', z.object({ name: z.string() })), + (c) => c.json({ ok: true }), +) diff --git a/graph/test/typescript/hono/cases/middleware/if-else-unequal-mw/src/index.ts b/graph/test/typescript/hono/cases/middleware/if-else-unequal-mw/src/index.ts new file mode 100644 index 000000000..84857971e --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/if-else-unequal-mw/src/index.ts @@ -0,0 +1,32 @@ +// census: use_conditional_loop, use_scoped (SPEC R15 clause 2) +// An if/else whose branches register DIFFERENT numbers of middleware on the same app: the branch middleware start +// at the same position (one of the two runs), each conditional; every LATER position on a chain that holds them is +// decided at run time, so that chain is declared dynamic_middleware_list (positions after the branch continue after +// the LONGER branch). A chain with no middleware after the branch is not dynamic; a chain the branch does not reach +// is untouched. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +declare const process: { env: Record } + +const requestId: MiddlewareHandler = async (c, next) => { c.header('x-request-id', '1'); await next() } +const verifyToken: MiddlewareHandler = async (c, next) => { await next() } +const loadUser: MiddlewareHandler = async (c, next) => { await next() } +const apiKey: MiddlewareHandler = async (c, next) => { await next() } +const audit: MiddlewareHandler = async (c, next) => { await next() } + +const app = new Hono() +app.use('*', requestId) +if (process.env.AUTH_MODE === 'token') { + app.use('/api/*', verifyToken) + app.use('/api/*', loadUser) +} else { + app.use('/api/*', apiKey) +} +app.use('/api/items/*', audit) + +app.get('/health', (c) => c.text('ok')) +app.get('/api/ping', (c) => c.text('pong')) +app.get('/api/items/:id', (c) => c.json({ id: c.req.param('id') })) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/lib-mw-options/src/index.ts b/graph/test/typescript/hono/cases/middleware/lib-mw-options/src/index.ts new file mode 100644 index 000000000..a5fbf4d39 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/lib-mw-options/src/index.ts @@ -0,0 +1,18 @@ +// census: builtin_mw_import, mw_factory_returning_fn (violation hono-2-07, SPEC R10) +// A library middleware built with project callbacks in its options: the middleware is the library call; the +// callbacks are not middleware and have no chain position. +import { Hono } from 'hono' +import { cors } from 'hono/cors' +import { basicAuth } from 'hono/basic-auth' +import type { MiddlewareHandler } from 'hono' + +function guard(realm: string): MiddlewareHandler { + return basicAuth({ realm, verifyUser: (user, pass) => user === 'a' && pass === 'b' }) +} + +const app = new Hono() +app.use('*', cors({ origin: (origin) => (origin.endsWith('.example') ? origin : null) })) +app.use('*', guard('admin')) +app.get('/x', (c) => c.text('x')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/loop-use/src/index.ts b/graph/test/typescript/hono/cases/middleware/loop-use/src/index.ts new file mode 100644 index 000000000..f47c16406 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/loop-use/src/index.ts @@ -0,0 +1,26 @@ +// census: use_global, use_multi (violation hono-1-06, LOOP form; SPEC 3.3 dynamic chains) +// Middleware registered in a loop over a run-time list sits between two known middleware: positions are the +// ordinal among the known ones, and the chain is declared dynamic_middleware_list. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +export function build(config: { before?: MiddlewareHandler[] }) { + const app = new Hono() + app.use('*', async (c, next) => { + await next() + }) + if (config.before) { + for (const m of config.before) { + app.use('*', m) + } + } + app.use('*', async (c, next) => { + c.header('x-done', '1') + await next() + }) + app.get('/x', (c) => c.text('x')) + return app +} + +declare const loadedConfig: { before?: MiddlewareHandler[] } +export default build(loadedConfig) diff --git a/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/index.ts b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/index.ts new file mode 100644 index 000000000..3b2e77ddc --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/index.ts @@ -0,0 +1,2 @@ +export { session } from './session' +export { scope } from './scope' diff --git a/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/scope.ts b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/scope.ts new file mode 100644 index 000000000..4b050e1a2 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/scope.ts @@ -0,0 +1,9 @@ +import type { Context, Next } from 'hono' + +export function scope(name: string) { + const check = async (c: Context, next: Next) => { + if (!c.get('user')) return c.text('denied ' + name, 403) + await next() + } + return Object.assign(check, { scope: name }) +} diff --git a/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/session.ts b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/session.ts new file mode 100644 index 000000000..76ecb34c1 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/guards/session.ts @@ -0,0 +1,7 @@ +import { createMiddleware } from 'hono/factory' + +export const session = (options?: { optional?: boolean }) => + createMiddleware(async (c, next) => { + c.set('user', { id: 'u1', optional: options?.optional ?? false }) + await next() + }) diff --git a/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/index.ts b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/index.ts new file mode 100644 index 000000000..7229ea17f --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/mw-from-namespace-field/src/index.ts @@ -0,0 +1,31 @@ +// census: use_global (stress-4 mutation m32 shapes; violation hono-4-01) +// Project middleware factories reached three ways: destructured from a field holding a namespace import, destructured +// from the namespace at module level, and as namespace members. Each is the inner project function, never a library +// call. +import { Hono } from 'hono' +import * as guards from './guards' + +type Env = { Variables: { user: { id: string; optional: boolean } } } + +class Controller { + protected guards = guards + getController() { + const { session, scope } = this.guards + const hono = new Hono().use(session(), scope('read')) + hono.get('/info', (c) => c.json(c.get('user'))) + return hono + } +} + +const { session, scope } = guards +const reports = new Hono().use(session({ optional: true }), scope('reports')) +reports.get('/daily', (c) => c.json(c.get('user'))) + +const audit = new Hono().use(guards.session(), guards.scope('audit')) +audit.get('/log', (c) => c.json(c.get('user'))) + +const app = new Hono() +app.route('/api/system', new Controller().getController()) +app.route('/api/reports', reports) +app.route('/api/audit', audit) +export default app diff --git a/graph/test/typescript/hono/cases/middleware/partial-sub-app-chain/src/index.ts b/graph/test/typescript/hono/cases/middleware/partial-sub-app-chain/src/index.ts new file mode 100644 index 000000000..2df4520a9 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/partial-sub-app-chain/src/index.ts @@ -0,0 +1,55 @@ +// census: basepath (stress-4 mutation m34 shape; violation hono-4-03, SPEC 3.3 [iter2] partial routes) +// A controller with its own use(guard()) and a per-route middleware, mounted (through a getter) into a holder that a +// run-time basePath can rebase and that has a global use('*') and a scoped use('/api/*'). The route is partial; its +// decidable chain is [holder's use('*'), the controller's own use, the per-route middleware]; the scoped use is +// undecidable (partial_route_scope). +import { Hono } from 'hono' +import type { Context, Next } from 'hono' + +declare const process: { env: Record } + +const guard = () => async (_c: Context, next: Next) => { + await next() +} +const trace = async (_c: Context, next: Next) => { + await next() +} +const audit = async (_c: Context, next: Next) => { + await next() +} + +class Controller { + protected create(): Hono { + return new Hono() + } + getController(): Hono { + const hono = this.create().use(guard()) + hono.get('/config/raw', audit, (c) => c.text('raw')) + return hono + } +} + +class Holder { + server = new Hono() + private opts?: { prefix?: string } + constructor(opts?: { prefix?: string }) { + this.opts = opts + } + rebuild() { + this.server = new Hono() + if (this.opts?.prefix) { + this.server = this.server.basePath(this.opts.prefix) + } + this.server.use('*', trace) + this.server.use('/api/*', guard()) + } + get app() { + return this.server + } +} + +const h = new Holder({ prefix: process.env.PREFIX }) +h.rebuild() +h.app.route('/api/system', new Controller().getController()) + +export default h.server diff --git a/graph/test/typescript/hono/cases/middleware/runtime-list-except-ternary/src/index.ts b/graph/test/typescript/hono/cases/middleware/runtime-list-except-ternary/src/index.ts new file mode 100644 index 000000000..d18ca9036 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/runtime-list-except-ternary/src/index.ts @@ -0,0 +1,42 @@ +// census: use_conditional_loop, combine_except (stress-6 oracle note; SPEC 3.3 dynamic chains, SPEC 3.1 except) +// Middleware come from a list chosen at run time (the tier's own, or one looked up in a registry, or none); each is registered as itself or wrapped in except(..) with a +// run-time exclusion list. Which middleware run, in which order, is decided at run time: every chain on the app is +// declared dynamic_middleware_list. Each tier's base path is a run-time value, so its routes are partial +// (dynamic_mount_prefix) and the dynamic chain is declared on the partial route too (its decidable chain keeps the +// tier's own first middleware). The except(..) call is a library middleware node at its call; its excluded +// paths are not literal, so its scope is also declared (dynamic_except). +import { Hono } from 'hono' +import { except } from 'hono/combine' +import type { MiddlewareHandler, Context } from 'hono' + +type Guarded = { handler: MiddlewareHandler; except: (c: Context) => boolean } +type Entry = MiddlewareHandler | Guarded + +const isGuarded = (m: Entry): m is Guarded => typeof m === 'object' && 'except' in m + +// the tier's own list when it declares one, else one looked up by name in a run-time registry, else none +function tierEntries(tier: { name: string; entries?: Entry[] }, registry: Record): Entry[] { + if (tier.entries) return tier.entries + const key = Object.keys(registry).find((k) => k.includes(`/${tier.name}/`)) + return key ? registry[key].default : [] +} + +type Tier = { name: string; basePath: string; entries?: Entry[] } + +export function buildTier(tier: Tier, registry: Record) { + const app = new Hono().basePath(tier.basePath) + app.use('/*', async (c, next) => { c.header('x-tier', '1'); await next() }) + for (const mw of tierEntries(tier, registry)) { + app.use('/*', isGuarded(mw) ? except(mw.except, mw.handler) : mw) + } + app.get('/status', (c) => c.text('ok')) + return app +} + +declare const registry: Record +declare const tiers: Tier[] + +const root = new Hono() +root.get('/', (c) => c.text('root')) +for (const tier of tiers) root.route('/', buildTier(tier, registry)) +export default root diff --git a/graph/test/typescript/hono/cases/middleware/scoped-use/src/index.ts b/graph/test/typescript/hono/cases/middleware/scoped-use/src/index.ts new file mode 100644 index 000000000..9f1b8686c --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/scoped-use/src/index.ts @@ -0,0 +1,22 @@ +// census: use_scoped, path_wildcard +// Path-scoped middleware applies to the routes its pattern matches; a param segment in the scope matches any segment. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const adminOnly: MiddlewareHandler = async (c, next) => { + await next() +} +const perOrg: MiddlewareHandler = async (c, next) => { + await next() +} + +const app = new Hono() +app.use('/admin/*', adminOnly) +app.use('/orgs/:org/*', perOrg) + +app.get('/admin/users', (c) => c.text('admin')) +app.get('/admin/users/:id', (c) => c.text('admin one')) +app.get('/orgs/:org/billing', (c) => c.text('billing')) +app.get('/public', (c) => c.text('public')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/spread-after-mount/src/index.ts b/graph/test/typescript/hono/cases/middleware/spread-after-mount/src/index.ts new file mode 100644 index 000000000..384c7004f --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/spread-after-mount/src/index.ts @@ -0,0 +1,19 @@ +// census: use_multi, route_mount_literal +// A const middleware array spread into use(); a use() AFTER mounting a sub-app does not reach the +// sub-app's routes, which were copied before it. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const a: MiddlewareHandler = async (c, next) => { await next() } +const b: MiddlewareHandler = async (c, next) => { await next() } +const protectedMiddleware = [a, b] + +const sub = new Hono() +sub.get('/inside', (c) => c.text('mounted before the use')) + +const routers = new Hono() +routers.route('/sub', sub) +routers.use(...protectedMiddleware) +routers.get('/after', (c) => c.text('gets a then b')) + +export default routers diff --git a/graph/test/typescript/hono/cases/middleware/spread-call-result/src/index.ts b/graph/test/typescript/hono/cases/middleware/spread-call-result/src/index.ts new file mode 100644 index 000000000..b2acc6776 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/spread-call-result/src/index.ts @@ -0,0 +1,29 @@ +// census: use_multi, mw_factory_returning_fn (violation hono-1-06) +// A spread of a project function's returned array literal is seen through: the chain is +// [limiter's inner fn (1), limiter's inner fn (2), after] before the handler, positions exact. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +function limiter(n: number): MiddlewareHandler { + return async (c, next) => { + if (n < 0) return c.text('limited', 429) + await next() + } +} +function createLimits() { + const a = limiter(1) + const b = limiter(2) + return [a, b] +} + +const limits = createLimits() +const after: MiddlewareHandler = async (c, next) => { + await next() +} + +const app = new Hono() +app.use('*', ...limits) +app.use('*', after) +app.get('/x', (c) => c.text('x')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/sub-app-middleware/src/index.ts b/graph/test/typescript/hono/cases/middleware/sub-app-middleware/src/index.ts new file mode 100644 index 000000000..d817dd76f --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/sub-app-middleware/src/index.ts @@ -0,0 +1,18 @@ +// census: use_global, route_mount_literal +// Middleware registered on a sub-app is mounted with it: scoped to the prefix, in its relative order. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const outer: MiddlewareHandler = async (c, next) => { await next() } +const inner: MiddlewareHandler = async (c, next) => { await next() } + +const users = new Hono() +users.use(inner) +users.get('/', (c) => c.text('users')) + +const app = new Hono() +app.use(outer) +app.route('/users', users) +app.get('/other', (c) => c.text('outer only')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/use-order/src/index.ts b/graph/test/typescript/hono/cases/middleware/use-order/src/index.ts new file mode 100644 index 000000000..acdee94b4 --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/use-order/src/index.ts @@ -0,0 +1,20 @@ +// census: use_global, use_scoped, await_next +// Registration ORDER decides: routes registered before a later use('/*', auth) do NOT get auth. +import { Hono } from 'hono' +import { createMiddleware } from 'hono/factory' + +const timing = createMiddleware(async (c, next) => { + await next() +}) +const auth = createMiddleware(async (c, next) => { + await next() +}) + +const app = new Hono() +app.use(timing) +app.get('/public', (c) => c.text('timing only')) +app.use('/*', auth) +app.get('/private', (c) => c.text('timing then auth')) +app.post('/private', (c) => c.text('timing then auth too')) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/validator/src/index.ts b/graph/test/typescript/hono/cases/middleware/validator/src/index.ts new file mode 100644 index 000000000..2dde9f1ad --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/validator/src/index.ts @@ -0,0 +1,18 @@ +// census: zvalidator, validator_builtin, req_valid +// A validator argument is per-route middleware for that route. +import { Hono } from 'hono' +import { validator } from 'hono/validator' +import { zValidator } from '@hono/zod-validator' +import { z } from 'zod' + +const NewPost = z.object({ title: z.string() }) + +const app = new Hono() +app.post('/posts', zValidator('json', NewPost), (c) => c.json(c.req.valid('json'), 201)) +app.get( + '/search', + validator('query', (value) => value), + (c) => c.text('search') +) + +export default app diff --git a/graph/test/typescript/hono/cases/middleware/verb-next/src/index.ts b/graph/test/typescript/hono/cases/middleware/verb-next/src/index.ts new file mode 100644 index 000000000..f5398f1bc --- /dev/null +++ b/graph/test/typescript/hono/cases/middleware/verb-next/src/index.ts @@ -0,0 +1,11 @@ +// census: await_next, verb_literal_path +// A verb registration whose function takes next and calls it is middleware for later matching routes. +import { Hono } from 'hono' + +const app = new Hono() +app.all('*', async (c, next) => { + await next() +}) +app.get('/x', (c) => c.text('x')) + +export default app diff --git a/graph/test/typescript/hono/cases/negative/context-lookalike/src/index.ts b/graph/test/typescript/hono/cases/negative/context-lookalike/src/index.ts new file mode 100644 index 000000000..d100a50e8 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/context-lookalike/src/index.ts @@ -0,0 +1,18 @@ +// census: ctx_get (partition outside Hono contexts) (SPEC N5) +// set/get on a Map called `c` is not a context key flow, even inside a file with a real app. +import { Hono } from 'hono' + +function remember(c: Map) { + c.set('user', 'u1') +} +function recall(c: Map) { + return c.get('user') +} +const store = new Map() +remember(store) +recall(store) + +const app = new Hono() +app.get('/me', (c) => c.text('me')) + +export default app diff --git a/graph/test/typescript/hono/cases/negative/foreign-fetch/src/index.ts b/graph/test/typescript/hono/cases/negative/foreign-fetch/src/index.ts new file mode 100644 index 000000000..42b2a56c3 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/foreign-fetch/src/index.ts @@ -0,0 +1,16 @@ +// census: neg_verb_literal_nonhono (violation hono-2-12) +// fetch to another host's /health is not a request to this app's GET /health. +import { Hono } from 'hono' + +class ExternalApi { + #baseUrl = 'https://api.example.com' + async ping() { + return fetch(`${this.#baseUrl}/health`) + } +} +export const external = new ExternalApi() + +const app = new Hono() +app.get('/health', (c) => c.text('ok')) + +export default app diff --git a/graph/test/typescript/hono/cases/negative/http-client/src/client.ts b/graph/test/typescript/hono/cases/negative/http-client/src/client.ts new file mode 100644 index 000000000..a081eeff5 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/http-client/src/client.ts @@ -0,0 +1,13 @@ +// census: neg_verb_literal_nonhono (SPEC N2) +// An HTTP client spelled like a router: verbs with literal paths and callbacks. Not a Hono app. +type Cb = (body: unknown) => void + +export const api = { + get(url: string, cb?: Cb) { cb?.(url) }, + post(url: string, body: unknown, cb?: Cb) { cb?.(body) }, +} + +export function loadUsers() { + api.get('/users', (body) => { console.log(body) }) + api.post('/users', { name: 'x' }, (res) => { console.log(res) }) +} diff --git a/graph/test/typescript/hono/cases/negative/http-client/src/index.ts b/graph/test/typescript/hono/cases/negative/http-client/src/index.ts new file mode 100644 index 000000000..084ce3b07 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/http-client/src/index.ts @@ -0,0 +1,7 @@ +// census: neg_verb_literal_nonhono (SPEC N2): the one real app beside it +import { Hono } from 'hono' + +const app = new Hono() +app.get('/only', (c) => c.text('the only route')) + +export default app diff --git a/graph/test/typescript/hono/cases/negative/local-hono-class/src/index.ts b/graph/test/typescript/hono/cases/negative/local-hono-class/src/index.ts new file mode 100644 index 000000000..39a6b5bc1 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/local-hono-class/src/index.ts @@ -0,0 +1,19 @@ +// census: neg_route_on_nonhono (SPEC N4) +// A project class that happens to be called Hono, and .route() on a workflow builder: neither is an app. +class Hono { + get(path: string, h: () => string) { return this } + use(h: () => void) { return this } + route(path: string, other: Hono) { return this } +} + +const fake = new Hono() +fake.use(() => {}) +fake.get('/fake', () => 'not a route') +fake.route('/nested', new Hono()) + +const workflow = { + route(name: string, step: () => void) { step(); return this }, +} +workflow.route('/step-one', () => {}) + +export default fake diff --git a/graph/test/typescript/hono/cases/negative/map-get/src/index.ts b/graph/test/typescript/hono/cases/negative/map-get/src/index.ts new file mode 100644 index 000000000..9c13cc759 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/map-get/src/index.ts @@ -0,0 +1,22 @@ +// census: neg_map_get_in_hono_file (SPEC N1) +// get/set/use on Maps, a KV-like object and Headers, in the same file as a real app: only the app routes. +import { Hono } from 'hono' + +const cache = new Map() +cache.set('/users', 'cached') +cache.get('/users') + +const kv = { + get(key: string, onMiss: () => string) { return onMiss() }, + use(fn: () => void) { fn() }, +} +kv.get('/kv/key', () => 'computed on miss') +kv.use(() => {}) + +const headers = new Headers() +headers.get('accept') + +const app = new Hono() +app.get('/real', (c) => c.text(cache.get('/users') ?? '')) + +export default app diff --git a/graph/test/typescript/hono/cases/negative/other-router/src/index.ts b/graph/test/typescript/hono/cases/negative/other-router/src/index.ts new file mode 100644 index 000000000..e2ade76e7 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/other-router/src/index.ts @@ -0,0 +1,16 @@ +// census: neg_other_router_import (SPEC N3) +// Another router in the same project: none of its registrations is a Hono route or middleware. +import { Hono } from 'hono' +import { Router } from './minirouter' + +const legacy = new Router() +legacy.use((req, res) => {}) +legacy.get('/legacy/users', (req, res) => {}) +legacy.post('/legacy/users', (req, res) => {}) +const outer = new Router() +outer.route('/v0', legacy) + +const app = new Hono() +app.get('/hono', (c) => c.text('hono')) + +export default app diff --git a/graph/test/typescript/hono/cases/negative/other-router/src/minirouter.ts b/graph/test/typescript/hono/cases/negative/other-router/src/minirouter.ts new file mode 100644 index 000000000..10ad2ff15 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/other-router/src/minirouter.ts @@ -0,0 +1,8 @@ +// A router that is not Hono: same method names, same call shapes. +type H = (req: unknown, res: unknown) => void +export class Router { + get(path: string, h: H) { return this } + post(path: string, h: H) { return this } + use(pathOrH: string | H, h?: H) { return this } + route(path: string, r: Router) { return this } +} diff --git a/graph/test/typescript/hono/cases/negative/request-lookalike/src/index.ts b/graph/test/typescript/hono/cases/negative/request-lookalike/src/index.ts new file mode 100644 index 000000000..dd1bd478c --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/request-lookalike/src/index.ts @@ -0,0 +1,18 @@ +// census: app_request_test (partition where the receiver is not an app) (SPEC N7, N8) +// `.request()` on a test agent and a project function named hc: no remote edge to the route. +import { Hono } from 'hono' + +const app = new Hono() +app.get('/real', (c) => c.text('real')) + +const agent = { request(path: string) { return path } } +export function hitsWithAgent() { + return agent.request('/real') +} + +function hc(base: string): any { return {} } +export function callsLocalHc() { + return hc('/').real.$get() +} + +export default app diff --git a/graph/test/typescript/hono/cases/negative/zod-openapi-meta/src/index.ts b/graph/test/typescript/hono/cases/negative/zod-openapi-meta/src/index.ts new file mode 100644 index 000000000..20d16a882 --- /dev/null +++ b/graph/test/typescript/hono/cases/negative/zod-openapi-meta/src/index.ts @@ -0,0 +1,20 @@ +// census: openapi_register, apptype_typeof (SPEC N6, N9) +// zod .openapi('Name') / .openapi({...}) metadata calls are not registrations, and a type alias of a +// createRoute value is not an RPC root. The one real registration is app.openapi. +import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi' + +const User = z.object({ id: z.string().openapi({ example: '1' }) }).openapi('User') +const Params = z.object({ id: z.string() }).openapi('Params') + +const getUser = createRoute({ + method: 'get', + path: '/users/{id}', + request: { params: Params }, + responses: { 200: { description: 'a user', content: { 'application/json': { schema: User } } } }, +}) +export type GetUserRoute = typeof getUser + +const app = new OpenAPIHono() +app.openapi(getUser, (c) => c.json({ id: c.req.valid('param').id }, 200)) + +export default app diff --git a/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/index.ts b/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/index.ts new file mode 100644 index 000000000..df0e5dac7 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/index.ts @@ -0,0 +1,11 @@ +// census: create_route, openapi_register, new_openapihono (violation hono-7-03: routes built through a project +// wrapper around createRoute were dropped with no partial and no unknown; SPEC 3.2 "never dropped") +// Control: listRoute comes from createRoute directly. The wrapped DELETE and PATCH routes must be routes, each with +// its own scope check as route middleware at position 0, or partial/unknown with a reason; never absent. +import { OpenAPIHono } from '@hono/zod-openapi' +import items from './items' + +const app = new OpenAPIHono() +app.route('/api/items', items) + +export default app diff --git a/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/items.ts b/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/items.ts new file mode 100644 index 000000000..97947685a --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/items.ts @@ -0,0 +1,21 @@ +import { OpenAPIHono, createRoute } from '@hono/zod-openapi' +import { scopedRoute } from './openapi' + +const listRoute = createRoute({ method: 'get', path: '/', responses: { 200: { description: 'ok' } } }) +const removeRoute = scopedRoute('items:delete', { + method: 'delete', + path: '/{id}', + responses: { 204: { description: 'gone' } }, +}) +const renameRoute = scopedRoute('items:write', { + method: 'patch', + path: '/{id}/name', + responses: { 200: { description: 'renamed' } }, +}) + +const items = new OpenAPIHono() + .openapi(listRoute, (c) => c.json([], 200)) + .openapi(removeRoute, (c) => c.body(null, 204)) + .openapi(renameRoute, (c) => c.json({ ok: true }, 200)) + +export default items diff --git a/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/openapi.ts b/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/openapi.ts new file mode 100644 index 000000000..5b81bcec5 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/create-route-wrapper/src/openapi.ts @@ -0,0 +1,16 @@ +import { createRoute, type RouteConfig } from '@hono/zod-openapi' +import type { MiddlewareHandler } from 'hono' + +export function authorize(scope: string): MiddlewareHandler { + return async (c, next) => { + if (!scope) return c.text('no', 403) + await next() + } +} + +// A project wrapper around createRoute: it adds a scope check to the route's own middleware and returns +// createRoute's result. A route built through it is a route like any other. +export function scopedRoute

& { path: P }>(scope: string, config: T): T { + const middleware = [authorize(scope), ...((config.middleware ?? []) as [])] + return createRoute({ ...config, middleware } as T) as T +} diff --git a/graph/test/typescript/hono/cases/openapi/create-route/src/index.ts b/graph/test/typescript/hono/cases/openapi/create-route/src/index.ts new file mode 100644 index 000000000..cf5d4abf1 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/create-route/src/index.ts @@ -0,0 +1,20 @@ +// census: create_route, openapi_register, new_openapihono +// Route objects declared in another module; {id} registers as :id; the THIRD argument is a validation +// hook, not the handler. +import { OpenAPIHono } from '@hono/zod-openapi' +import { listTasks, getTask } from './routes' + +const app = new OpenAPIHono() + +app.openapi(listTasks, (c) => c.json([], 200)) +app.openapi( + getTask, + (c) => c.json({ id: c.req.valid('param').id, done: false }, 200), + (result, c) => { + if (!result.success) console.log('rejected', c.req.path) + return undefined + } +) +app.doc('/doc', { openapi: '3.0.0', info: { title: 'tasks', version: '1' } }) + +export default app diff --git a/graph/test/typescript/hono/cases/openapi/create-route/src/routes.ts b/graph/test/typescript/hono/cases/openapi/create-route/src/routes.ts new file mode 100644 index 000000000..3016c4b72 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/create-route/src/routes.ts @@ -0,0 +1,16 @@ +import { createRoute, z } from '@hono/zod-openapi' + +export const Task = z.object({ id: z.string(), done: z.boolean() }).openapi('Task') + +export const listTasks = createRoute({ + method: 'get', + path: '/tasks', + responses: { 200: { description: 'tasks', content: { 'application/json': { schema: z.array(Task) } } } }, +}) + +export const getTask = createRoute({ + method: 'get', + path: '/tasks/{id}', + request: { params: z.object({ id: z.string() }) }, + responses: { 200: { description: 'task', content: { 'application/json': { schema: Task } } } }, +}) diff --git a/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/auth.handlers.ts b/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/auth.handlers.ts new file mode 100644 index 000000000..4fff532a5 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/auth.handlers.ts @@ -0,0 +1,3 @@ +import type { Context } from 'hono' + +export const login = async (c: Context) => c.json({ ok: true }, 200) diff --git a/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/auth.routes.ts b/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/auth.routes.ts new file mode 100644 index 000000000..43e05c0c0 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/auth.routes.ts @@ -0,0 +1,3 @@ +import { createRoute } from '@hono/zod-openapi' + +export const login = createRoute({ path: `${'/auth'}/login`, method: 'post', responses: { 200: { description: 'ok' } } }) diff --git a/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/index.ts b/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/index.ts new file mode 100644 index 000000000..b50d5fcb5 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/namespace-handlers/src/index.ts @@ -0,0 +1,11 @@ +// census: openapi_register, create_route (violation hono-1-04) +// The handler is a member of a namespace import (`handlers.login`), the route object a named import whose +// path is a template over a literal. +import { OpenAPIHono } from '@hono/zod-openapi' +import * as handlers from './auth.handlers' +import { login } from './auth.routes' + +const auth = new OpenAPIHono() +auth.openapi(login, handlers.login) + +export default auth diff --git a/graph/test/typescript/hono/cases/openapi/response-helper/src/index.ts b/graph/test/typescript/hono/cases/openapi/response-helper/src/index.ts new file mode 100644 index 000000000..a7e40a117 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/response-helper/src/index.ts @@ -0,0 +1,42 @@ +// census: create_route (violation hono-3-04, SPEC 3.9) +// createRoute responses written through a project helper that wraps the schema ({ content: { json: { schema } } }): +// the response schema of each route is the helper's ARGUMENT, as for an inline response. +import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi' + +const jsonBody = (schema: T, description: string) => ({ + content: { 'application/json': { schema } }, + description, +}) +const jsonBodyRequired = (schema: T, description: string) => ({ + ...jsonBody(schema, description), + required: true, +}) + +const Account = z.object({ id: z.string(), email: z.string() }) +const ErrorBody = z.object({ message: z.string() }) +const AccountList = z.array(Account) + +const getAccount = createRoute({ + method: 'get', + path: '/accounts/{id}', + request: { params: z.object({ id: z.string() }) }, + responses: { 200: jsonBody(Account, 'the account'), 404: jsonBody(ErrorBody, 'not found') }, +}) +const listAccounts = createRoute({ + method: 'get', + path: '/accounts', + responses: { 200: { content: { 'application/json': { schema: AccountList } }, description: 'all' } }, +}) +const createAccount = createRoute({ + method: 'post', + path: '/accounts', + request: { body: jsonBodyRequired(Account, 'the new account') }, + responses: { 201: jsonBody(Account, 'created') }, +}) + +const app = new OpenAPIHono() +app.openapi(getAccount, (c) => c.json({ id: c.req.valid('param').id, email: 'a@b' }, 200)) +app.openapi(listAccounts, (c) => c.json([], 200)) +app.openapi(createAccount, (c) => c.json(c.req.valid('json'), 201)) + +export default app diff --git a/graph/test/typescript/hono/cases/openapi/route-middleware/src/index.ts b/graph/test/typescript/hono/cases/openapi/route-middleware/src/index.ts new file mode 100644 index 000000000..582ef78d6 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/route-middleware/src/index.ts @@ -0,0 +1,21 @@ +// census: create_route, openapi_register, use_global +// routeDef.middleware runs before the validators and the handler; app-level use before that. +import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi' +import type { MiddlewareHandler } from 'hono' + +const audit: MiddlewareHandler = async (c, next) => { await next() } +const guard: MiddlewareHandler = async (c, next) => { await next() } + +const create = createRoute({ + method: 'post', + path: '/notes', + middleware: [guard] as const, + request: { body: { content: { 'application/json': { schema: z.object({ text: z.string() }) } } } }, + responses: { 201: { description: 'created' } }, +}) + +const app = new OpenAPIHono() +app.use(audit) +app.openapi(create, (c) => c.body(null, 201)) + +export default app diff --git a/graph/test/typescript/hono/cases/openapi/spread-error-responses/src/errors.ts b/graph/test/typescript/hono/cases/openapi/spread-error-responses/src/errors.ts new file mode 100644 index 000000000..8d5d7d4ef --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/spread-error-responses/src/errors.ts @@ -0,0 +1,14 @@ +import { z } from 'zod' + +const errorBody = (code: string) => z.object({ code: z.literal(code), message: z.string() }) + +export const errorResponses = { + 400: { + description: 'bad request', + content: { 'application/json': { schema: errorBody('BAD_REQUEST') } }, + }, + 403: { + description: 'forbidden', + content: { 'application/json': { schema: errorBody('FORBIDDEN') } }, + }, +} diff --git a/graph/test/typescript/hono/cases/openapi/spread-error-responses/src/index.ts b/graph/test/typescript/hono/cases/openapi/spread-error-responses/src/index.ts new file mode 100644 index 000000000..4ded04ef3 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/spread-error-responses/src/index.ts @@ -0,0 +1,21 @@ +// census: create_route (stress-4 mutation m27 shape; violation hono-4-08, oracle gap O19) +// Error responses spread from a module-level object: each slot is the call `errorBody('...')` (named once, at the +// call), never the helper declaration as well. +import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi' +import { errorResponses } from './errors' + +const Secret = z.object({ id: z.string() }) + +const getSecret = createRoute({ + method: 'get', + path: '/secrets/{id}', + request: { params: z.object({ id: z.string() }) }, + responses: { + 200: { description: 'the secret', content: { 'application/json': { schema: Secret } } }, + ...errorResponses, + }, +}) + +const app = new OpenAPIHono() +app.openapi(getSecret, (c) => c.json({ id: c.req.valid('param').id }, 200)) +export default app diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/handlers.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/handlers.ts new file mode 100644 index 000000000..0a780d22a --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/handlers.ts @@ -0,0 +1,4 @@ +import type { Context } from 'hono' + +export const getTicket = async (c: Context) => c.json({ id: String(c.req.param('id')), title: 't' }, 200) +export const createTicket = async (c: Context) => c.json({ id: '2', title: 'new' }, 201) diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/index.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/index.ts new file mode 100644 index 000000000..f775dd8c7 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/index.ts @@ -0,0 +1,2 @@ +export { default as jsonBody } from './json-body' +export { default as jsonBodyRequired } from './json-body-required' diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/json-body-required.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/json-body-required.ts new file mode 100644 index 000000000..a21d77963 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/json-body-required.ts @@ -0,0 +1,10 @@ +import jsonBody from './json-body' + +const jsonBodyRequired = (schema: T, description: string) => { + return { + ...jsonBody(schema, description), + required: true, + } +} + +export default jsonBodyRequired diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/json-body.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/json-body.ts new file mode 100644 index 000000000..cbe3f4406 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/helpers/json-body.ts @@ -0,0 +1,12 @@ +const jsonBody = (schema: T, description: string) => { + return { + content: { + 'application/json': { + schema, + }, + }, + description, + } +} + +export default jsonBody diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/index.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/index.ts new file mode 100644 index 000000000..00a820eeb --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/index.ts @@ -0,0 +1,12 @@ +// census: create_route (stress-4 mutation m26 shape; violation hono-3-04 reopened) +// Responses keyed by a namespace constant (`[Status.OK]`) and written through helpers re-exported as named +// defaults from a barrel; routes and handlers come from namespace imports. Every slot names the helper's argument. +import { OpenAPIHono } from '@hono/zod-openapi' +import * as routes from './routes' +import * as handlers from './handlers' + +const app = new OpenAPIHono() + .openapi(routes.getTicket, handlers.getTicket) + .openapi(routes.createTicket, handlers.createTicket) + +export default app diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/routes.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/routes.ts new file mode 100644 index 000000000..50a8ab96b --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/routes.ts @@ -0,0 +1,26 @@ +import { createRoute, z } from '@hono/zod-openapi' +import * as Status from './status' +import { jsonBody, jsonBodyRequired } from './helpers' + +const Ticket = z.object({ id: z.string(), title: z.string() }) +const Missing = z.object({ message: z.string() }) +const TicketInput = z.object({ title: z.string() }) + +export const getTicket = createRoute({ + path: '/tickets/{id}', + method: 'get', + request: { params: z.object({ id: z.string() }) }, + responses: { + [Status.OK]: jsonBody(Ticket, 'the ticket'), + [Status.NOT_FOUND]: jsonBody(Missing, 'no such ticket'), + }, +}) + +export const createTicket = createRoute({ + path: '/tickets', + method: 'post', + request: { body: jsonBodyRequired(TicketInput, 'a new ticket') }, + responses: { + [Status.CREATED]: jsonBody(Ticket, 'created'), + }, +}) diff --git a/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/status.ts b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/status.ts new file mode 100644 index 000000000..3ed237128 --- /dev/null +++ b/graph/test/typescript/hono/cases/openapi/status-key-helpers/src/status.ts @@ -0,0 +1,3 @@ +export const OK = 200 +export const CREATED = 201 +export const NOT_FOUND = 404 diff --git a/graph/test/typescript/hono/cases/routing/all-and-any/src/index.ts b/graph/test/typescript/hono/cases/routing/all-and-any/src/index.ts new file mode 100644 index 000000000..d28b63ced --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/all-and-any/src/index.ts @@ -0,0 +1,10 @@ +// census: verb_literal_path, path_wildcard +// `all` is verb ANY; an `all('*')` handler that never calls next is a handler, not middleware. +import { Hono } from 'hono' + +const app = new Hono() + +app.all('/proxy/*', (c) => c.text('proxied')) +app.get('/proxy/health', (c) => c.text('shadowed but registered')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/conditional-loop/src/index.ts b/graph/test/typescript/hono/cases/routing/conditional-loop/src/index.ts new file mode 100644 index 000000000..794efc742 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/conditional-loop/src/index.ts @@ -0,0 +1,20 @@ +// census: verb_literal_path (registrations behind a condition / in a loop, SPEC 3.1) +// Still emitted, each with a declared conditional_registration / loop_registration. +import { Hono } from 'hono' + +const app = new Hono() +const debug = Date.now() < 0 + +if (debug) { + app.get('/debug', (c) => c.text('debug only')) +} else { + app.get('/prod', (c) => c.text('prod only')) +} + +for (const name of ['a', 'b']) { + app.get('/loop', (c) => c.text('registered per iteration ' + name)) +} + +app.get('/always', (c) => c.text('always')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/const-paths/src/index.ts b/graph/test/typescript/hono/cases/routing/const-paths/src/index.ts new file mode 100644 index 000000000..5e4fe3948 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/const-paths/src/index.ts @@ -0,0 +1,14 @@ +// census: verb_const_path, verb_template_path +// A path built from consts (local, imported, a const-object member, a template over consts) is decidable. +import { Hono } from 'hono' +import { USERS, PATHS } from './paths' + +const ID = ':id' +const app = new Hono() + +app.get(USERS, (c) => c.text('users')) +app.get(`${USERS}/${ID}`, (c) => c.text('one user')) +app.get(PATHS.health, (c) => c.text('ok')) +app.get('/api' + PATHS.version, (c) => c.text('1')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/const-paths/src/paths.ts b/graph/test/typescript/hono/cases/routing/const-paths/src/paths.ts new file mode 100644 index 000000000..c3e291119 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/const-paths/src/paths.ts @@ -0,0 +1,2 @@ +export const USERS = '/users' +export const PATHS = { health: '/health', version: '/version' } as const diff --git a/graph/test/typescript/hono/cases/routing/dynamic-path/src/index.ts b/graph/test/typescript/hono/cases/routing/dynamic-path/src/index.ts new file mode 100644 index 000000000..91dd61da2 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/dynamic-path/src/index.ts @@ -0,0 +1,11 @@ +// census: verb_template_path (non-decidable partition) +// A path from a run-time value is declared undetermined, never guessed and never dropped. +import { Hono } from 'hono' + +const app = new Hono() +const version = String(Date.now() % 2) + +app.get(`/v${version}/status`, (c) => c.text('status')) +app.get('/fixed', (c) => c.text('fixed')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/every-verb/src/index.ts b/graph/test/typescript/hono/cases/routing/every-verb/src/index.ts new file mode 100644 index 000000000..8b8ed4a0d --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/every-verb/src/index.ts @@ -0,0 +1,20 @@ +// census: verb_literal_path, verb_chained, on_method, export_default_app +// One app, every verb Hono generates, `all`, a custom method through `on`, and a chain. +import { Hono } from 'hono' + +const app = new Hono() + +app.get('/items', (c) => c.json([])) +app.post('/items', (c) => c.json({ created: true }, 201)) +app.put('/items/:id', (c) => c.text('replaced')) +app.delete('/items/:id', (c) => c.body(null, 204)) +app.patch('/items/:id', (c) => c.text('patched')) +app.options('/items', (c) => c.body(null, 204)) +app.all('/health', (c) => c.text('ok')) +app.on('PURGE', '/cache', (c) => c.text('purged')) + +app + .get('/chain', (c) => c.text('get')) + .post((c) => c.text('post on the same path')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/library-handler/src/index.ts b/graph/test/typescript/hono/cases/routing/library-handler/src/index.ts new file mode 100644 index 000000000..96b0a0d03 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/library-handler/src/index.ts @@ -0,0 +1,14 @@ +// census: verb_literal_path (violation hono-1-03; SPEC R5) +// A route whose handler is a library call result: a route keyed at the call, never dropped. +import { Hono } from 'hono' +import { serveStatic } from '@hono/node-server/serve-static' +import { serveStatic as serveStaticAlt } from 'hono/serve-static' + +const app = new Hono() +app.get('/favicon.ico', serveStatic({ path: './favicon.ico' })) +app.all( + '/assets/*', + serveStaticAlt({ root: './public', getContent: async () => null }) +) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/mts-source/src/server.mts b/graph/test/typescript/hono/cases/routing/mts-source/src/server.mts new file mode 100644 index 000000000..69f09255f --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/mts-source/src/server.mts @@ -0,0 +1,7 @@ +// census: new_hono, verb_literal_path (an .mts module) +import { Hono } from 'hono' + +export const app = new Hono() + +app.get('/mts', (c) => c.text('from an mts module')) +app.post('/mts', (c) => c.text('posted')) diff --git a/graph/test/typescript/hono/cases/routing/multi-handler/src/index.ts b/graph/test/typescript/hono/cases/routing/multi-handler/src/index.ts new file mode 100644 index 000000000..e13950c79 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/multi-handler/src/index.ts @@ -0,0 +1,23 @@ +// census: verb_multi_handler, await_next +// Every argument but the last is per-route middleware; the last is the route handler. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const requireJson: MiddlewareHandler = async (c, next) => { + await next() +} +const audit: MiddlewareHandler = async (c, next) => { + await next() +} + +function createOrder(c: any) { + return c.json({ ok: true }, 201) +} + +const app = new Hono() + +app.post('/orders', requireJson, audit, createOrder) +app.get('/orders', audit, (c) => c.json([])) +app.get('/plain', (c) => c.text('no middleware')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/named-handlers/src/handlers.ts b/graph/test/typescript/hono/cases/routing/named-handlers/src/handlers.ts new file mode 100644 index 000000000..1cfd61a7d --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/named-handlers/src/handlers.ts @@ -0,0 +1,11 @@ +import type { Context } from 'hono' + +export function listProjects(c: Context) { + return c.json([]) +} + +export const getProject = (c: Context) => c.json({ id: c.req.param('id') }) + +export default async function deleteProject(c: Context) { + return c.body(null, 204) +} diff --git a/graph/test/typescript/hono/cases/routing/named-handlers/src/index.ts b/graph/test/typescript/hono/cases/routing/named-handlers/src/index.ts new file mode 100644 index 000000000..288f5b25f --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/named-handlers/src/index.ts @@ -0,0 +1,12 @@ +// census: verb_literal_path, export_default_app +// Handlers declared elsewhere (function declaration, const arrow, default export) are the route handlers. +import { Hono } from 'hono' +import deleteProject, { listProjects, getProject } from './handlers' + +const app = new Hono() + +app.get('/projects', listProjects) +app.get('/projects/:id', getProject) +app.delete('/projects/:id', deleteProject) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/on-arrays/src/index.ts b/graph/test/typescript/hono/cases/routing/on-arrays/src/index.ts new file mode 100644 index 000000000..719675be8 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/on-arrays/src/index.ts @@ -0,0 +1,11 @@ +// census: on_method_array, on_method +// `on` with a verb list and a path list registers the cross product; a single custom verb too. +import { Hono } from 'hono' + +const app = new Hono() + +app.on(['GET', 'POST'], ['/form', '/form/legacy'], (c) => c.text('form')) +app.on('PURGE', '/cache/:key', (c) => c.text('purged')) +app.on(['put'], '/lower', (c) => c.text('upper-cased verb')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/partial-route-scope/src/index.ts b/graph/test/typescript/hono/cases/routing/partial-route-scope/src/index.ts new file mode 100644 index 000000000..00eb7ca5f --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/partial-route-scope/src/index.ts @@ -0,0 +1,16 @@ +// census: use_scoped, route_mount_nonliteral (SPEC 3.3 [iter2] partial_route_scope) +// A scoped use cannot be decided against routes mounted under an unknown prefix: declared, never "no middleware". +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const versioned: MiddlewareHandler = async (c, next) => { await next() } + +const items = new Hono() +items.get('/list', (c) => c.json([])) + +const VERSION = String(Date.now() % 3) +const app = new Hono() +app.use('/v1/*', versioned) +app.route(`/v${VERSION}`, items) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/path-shapes/src/index.ts b/graph/test/typescript/hono/cases/routing/path-shapes/src/index.ts new file mode 100644 index 000000000..74448a6cd --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/path-shapes/src/index.ts @@ -0,0 +1,16 @@ +// census: path_param, path_optional_param, path_regex_param, path_wildcard +// Paths are kept as written: params, optional, regex, wildcard, a suffix after a param, a dot, a trailing slash. +import { Hono } from 'hono' + +const app = new Hono() + +app.get('/users/:id', (c) => c.text(c.req.param('id'))) +app.get('/posts/:year?', (c) => c.text('posts')) +app.get('/items/:id{[0-9]+}', (c) => c.text('numeric item')) +app.get('/files/*', (c) => c.text('any file')) +app.get('/img/:slug.png', (c) => c.text('png')) +app.get('/v1/keys.getKey', (c) => c.text('dotted')) +app.get('/trailing/', (c) => c.text('trailing slash kept')) +app.get('/a/:x/b/:y', (c) => c.text('two params')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/pathless-chain/src/index.ts b/graph/test/typescript/hono/cases/routing/pathless-chain/src/index.ts new file mode 100644 index 000000000..0fb926485 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/pathless-chain/src/index.ts @@ -0,0 +1,16 @@ +// census: verb_chained +// A path-less verb continues the previous path of the same app; the very first one is `/`. +import { Hono } from 'hono' + +const app = new Hono() + +app.get((c) => c.text('root, no path written')) + +app + .get('/book', (c) => c.text('list')) + .post((c) => c.text('create')) + .put((c) => c.text('replace')) + +app.delete('/book/:id', (c) => c.text('gone')).patch((c) => c.text('patched')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/scope-table/src/index.ts b/graph/test/typescript/hono/cases/routing/scope-table/src/index.ts new file mode 100644 index 000000000..e603d0671 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/scope-table/src/index.ts @@ -0,0 +1,23 @@ +// census: use_scoped, path_wildcard (SPEC 3.3 [iter2] QD09 table, settled against the pinned hono routers) +// /x/* reaches /x, /x/ and /x/a but not /xy; /x* reaches /xy; a mid-path * is exactly one segment. +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const slashStar: MiddlewareHandler = async (c, next) => { await next() } +const bareStar: MiddlewareHandler = async (c, next) => { await next() } +const midStar: MiddlewareHandler = async (c, next) => { await next() } + +const app = new Hono() +app.use('/x/*', slashStar) +app.use('/x*', bareStar) +app.use('/a/*/c', midStar) + +app.get('/x', (c) => c.text('x')) +app.get('/x/', (c) => c.text('x slash')) +app.get('/x/a', (c) => c.text('x a')) +app.get('/xy', (c) => c.text('xy')) +app.get('/a/b/c', (c) => c.text('one segment')) +app.get('/a/c', (c) => c.text('zero segments')) +app.get('/a/b/d/c', (c) => c.text('two segments')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/strict-false/src/index.ts b/graph/test/typescript/hono/cases/routing/strict-false/src/index.ts new file mode 100644 index 000000000..e32ed631a --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/strict-false/src/index.ts @@ -0,0 +1,10 @@ +// census: strict_false, new_hono_options +// `strict: false` changes matching, not the registered path: the route table keeps what is written. +import { Hono } from 'hono' + +const app = new Hono({ strict: false }) + +app.get('/about/', (c) => c.text('about')) +app.get('/contact', (c) => c.text('contact')) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/websocket-project-module/src/chat.ts b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/chat.ts new file mode 100644 index 000000000..e0be8783f --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/chat.ts @@ -0,0 +1,15 @@ +import { Hono } from 'hono' +import { upgradeWebSocket } from '@/utils/websocket' + +export const chat = new Hono().get( + '/ws', + async (c, next) => { + c.header('x-chat', '1') + await next() + }, + upgradeWebSocket(() => ({ + onMessage(event, ws) { + ws.send(String(event.data)) + }, + })) +) diff --git a/graph/test/typescript/hono/cases/routing/websocket-project-module/src/index.ts b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/index.ts new file mode 100644 index 000000000..2080af800 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/index.ts @@ -0,0 +1,12 @@ +// census: verb_multi_handler (oracle gap O10 residual; SPEC R5) +// upgradeWebSocket taken from a PROJECT module that destructures createBunWebSocket() (imported relatively and +// through a tsconfig path alias): a library-call handler keyed at the call, after its per-route middleware. +import { Hono } from 'hono' +import { upgradeWebSocket } from './utils/websocket' +import { chat } from './chat' + +const app = new Hono() +app.get('/live', upgradeWebSocket(() => ({ onOpen() {} }))) +app.route('/chat', chat) + +export default app diff --git a/graph/test/typescript/hono/cases/routing/websocket-project-module/src/tsconfig.json b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/tsconfig.json new file mode 100644 index 000000000..af19c36a1 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "strict": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "baseUrl": ".", + "paths": { "@/*": ["./*"] } + } +} diff --git a/graph/test/typescript/hono/cases/routing/websocket-project-module/src/utils/websocket.ts b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/utils/websocket.ts new file mode 100644 index 000000000..26e194bd7 --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/websocket-project-module/src/utils/websocket.ts @@ -0,0 +1,3 @@ +import { createBunWebSocket } from 'hono/bun' + +export const { upgradeWebSocket, websocket } = createBunWebSocket() diff --git a/graph/test/typescript/hono/cases/routing/websocket-sse/src/index.ts b/graph/test/typescript/hono/cases/routing/websocket-sse/src/index.ts new file mode 100644 index 000000000..f579ba20d --- /dev/null +++ b/graph/test/typescript/hono/cases/routing/websocket-sse/src/index.ts @@ -0,0 +1,23 @@ +// census: verb_literal_path (oracle gap O10; SPEC R5 library-call handlers) +// upgradeWebSocket(...) as the route handler is a library-call handler keyed at the call; a project handler +// returning streamSSE(...) is an ordinary project handler. +import { Hono } from 'hono' +import { upgradeWebSocket } from 'hono/cloudflare-workers' +import { streamSSE } from 'hono/streaming' + +const app = new Hono() +app.get( + '/ws', + upgradeWebSocket(() => ({ + onMessage(event, ws) { + ws.send(String(event.data)) + }, + })) +) +app.get('/sse', (c) => + streamSSE(c, async (stream) => { + await stream.writeSSE({ data: 'tick' }) + }) +) + +export default app diff --git a/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/client.ts b/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/client.ts new file mode 100644 index 000000000..1ed96a92e --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/client.ts @@ -0,0 +1,19 @@ +export async function listUsers(base: string) { + return fetch(`${base}/api/users`) +} + +export async function probe(base: string) { + return fetch(`${base}/__test/probe`) +} + +export async function landing(base: string) { + return fetch(`${base}/pricing/enterprise`) +} + +export async function loadFont() { + return fetch(new URL('./fonts/inter.woff2', import.meta.url)) +} + +export async function byKey(base: string, key: string) { + return fetch(`${base}/${key}`) +} diff --git a/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/server.test.ts b/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/server.test.ts new file mode 100644 index 000000000..47ea304f6 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/server.test.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +declare function it(name: string, fn: () => unknown): void + +it('serves a probe route on a test app', async () => { + const app = new Hono() + app.get('/__test/probe', (c) => c.text('probe')) + await app.request('/__test/probe') +}) diff --git a/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/server.ts b/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/server.ts new file mode 100644 index 000000000..6713c5ffb --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/base-unknown-implausible/src/server.ts @@ -0,0 +1,13 @@ +// census: request_fetch, app_request_test (SPEC R14; oracle rule O21) +// Requests whose base the program does not spell join a route on the composed full path as base_unknown (R14), but +// four shapes join nothing: (1) a non-test request never reaches an app only a test builds; (2) a request that only +// a catch-all handler would match names no route; (3) `new URL(rel, import.meta.url)` is a file next to the module, +// not a request; (4) a path with no literal segment (`${base}/${key}`) names no route. +import { Hono } from 'hono' + +const app = new Hono() +app.get('/api/users', (c) => c.json([])) +app.get('/api/users/:id', (c) => c.json({ id: c.req.param('id') })) +app.get('*', (c) => c.text('spa shell')) + +export default app diff --git a/graph/test/typescript/hono/cases/rpc/fetch-unknown-base/src/api.ts b/graph/test/typescript/hono/cases/rpc/fetch-unknown-base/src/api.ts new file mode 100644 index 000000000..faf298307 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/fetch-unknown-base/src/api.ts @@ -0,0 +1,11 @@ +// census: request_fetch (SPEC R14; oracle gap O18) +// Requests whose base the program does not spell may reach this program's routes: they join on the composed full +// path with confidence base_unknown. A literal external host never joins. +import { Hono } from 'hono' + +const app = new Hono().basePath('/api') +app.post('/oauth/register', (c) => c.json({ ok: true }, 201)) +app.get('/projects/:id', (c) => c.json({ id: c.req.param('id') })) +app.get('/health', (c) => c.text('ok')) + +export default app diff --git a/graph/test/typescript/hono/cases/rpc/fetch-unknown-base/src/cli.ts b/graph/test/typescript/hono/cases/rpc/fetch-unknown-base/src/cli.ts new file mode 100644 index 000000000..b1dc05d01 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/fetch-unknown-base/src/cli.ts @@ -0,0 +1,17 @@ +declare const process: { env: Record } + +export async function register(apiUrl: string) { + return fetch(`${apiUrl}/api/oauth/register`, { method: 'POST' }) +} + +export async function project(base: string, id: string) { + return fetch(new URL(`/api/projects/${id}`, base)) +} + +export async function health() { + return fetch((process.env.API_URL ?? 'http://localhost:3003') + '/api/health') +} + +export async function upstream() { + return fetch('https://status.example.com/api/health') +} diff --git a/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/discovery.ts b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/discovery.ts new file mode 100644 index 000000000..0129db5e9 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/discovery.ts @@ -0,0 +1,8 @@ +// the method is set on the init only inside a branch: GET or POST, decided at run time +export async function poll(push: boolean) { + const init: RequestInit = { headers: { accept: 'application/json' } } + if (push) { + init.method = 'POST' + } + return fetch('http://localhost:8787/_discovery', init) +} diff --git a/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/server.test.ts b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/server.test.ts new file mode 100644 index 000000000..c0ab1878f --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/server.test.ts @@ -0,0 +1,18 @@ +import app from './server' + +declare function it(name: string, fn: () => unknown): void + +async function hit(path: string, init?: RequestInit) { + return app.request(path, init) +} + +it('reads a skill', async () => { + await hit('/api/skills/1') +}) + +declare const recorded: string + +it('replays a recorded request', async () => { + const init = JSON.parse(recorded) as RequestInit + await hit('/api/skills/2', init) +}) diff --git a/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/server.ts b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/server.ts new file mode 100644 index 000000000..854c5479c --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/server.ts @@ -0,0 +1,14 @@ +// census: request_fetch, app_request_test (SPEC R17; stress-6 oracle note O25; violation hono-6-03) +// A request whose HTTP method the program does not decide joins EVERY route on its composed path, on any verb, +// with Confidence method_unknown; when the base is also unknown, base_unknown wins. A literal method still joins +// only its own verb. +import { Hono } from 'hono' + +const app = new Hono() +app.get('/api/skills/:id', (c) => c.json({ id: c.req.param('id') })) +app.put('/api/skills/:id', (c) => c.json({ ok: true })) +app.delete('/api/skills/:id', (c) => c.body(null, 204)) +app.get('/_discovery', (c) => c.json([])) +app.post('/_discovery', (c) => c.json([])) + +export default app diff --git a/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/skills-client.ts b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/skills-client.ts new file mode 100644 index 000000000..966fd04d0 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/fetch-verb-parameter/src/skills-client.ts @@ -0,0 +1,14 @@ +// the verb travels in an options object the helper is handed (and never inspects) +export async function skillRequest(baseUrl: string, path: string, options?: RequestInit) { + return fetch(`${baseUrl}/api/skills${path}`, options) +} + +// the verb is a parameter written into the init +export async function call(method: string, id: string) { + return fetch(`http://localhost:8787/api/skills/${id}`, { method, headers: { accept: 'application/json' } }) +} + +// control: a literal verb joins only its own route +export async function remove(id: string) { + return fetch(`http://localhost:8787/api/skills/${id}`, { method: 'DELETE' }) +} diff --git a/graph/test/typescript/hono/cases/rpc/hc-basic/src/client.ts b/graph/test/typescript/hono/cases/rpc/hc-basic/src/client.ts new file mode 100644 index 000000000..3864700c0 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/hc-basic/src/client.ts @@ -0,0 +1,22 @@ +// census: hc_client, hc_dollar_call, hc_element_param, apptype_typeof +// A typed client: each property is a path segment, [':id'] the literal param, index is `/`, $verb the call. +import { hc } from 'hono/client' +import type { AppType } from './server' + +const client = hc('http://localhost:8787') + +export async function listUsers() { + return (await client.users.$get()).json() +} +export async function oneUser(id: string) { + return (await client.users[':id'].$get({ param: { id } })).json() +} +export async function createUser() { + return client.users.$post() +} +export async function home() { + return client.index.$get() +} +export function userUrl() { + return client.users[':id'].$url({ param: { id: '1' } }) +} diff --git a/graph/test/typescript/hono/cases/rpc/hc-basic/src/server.ts b/graph/test/typescript/hono/cases/rpc/hc-basic/src/server.ts new file mode 100644 index 000000000..487852d4c --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/hc-basic/src/server.ts @@ -0,0 +1,12 @@ +import { Hono } from 'hono' + +const users = new Hono() + .get('/', (c) => c.json([{ id: '1' }])) + .get('/:id', (c) => c.json({ id: c.req.param('id') })) + .post('/', (c) => c.json({ id: '2' }, 201)) + +const app = new Hono() +const routes = app.route('/users', users).get('/', (c) => c.text('index')) + +export type AppType = typeof routes +export default app diff --git a/graph/test/typescript/hono/cases/rpc/helper-request-method/src/__tests__/auth.test.ts b/graph/test/typescript/hono/cases/rpc/helper-request-method/src/__tests__/auth.test.ts new file mode 100644 index 000000000..3e480b228 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/helper-request-method/src/__tests__/auth.test.ts @@ -0,0 +1,32 @@ +// census: app_request_test (violation hono-7-02: a literal method in the init object of app.request inside a +// test helper that takes the path from its callers) +// `post` sends with `method: 'POST'`: each call joins the POST route on its path, never GET. Control: `get` +// passes no init, so its calls join GET; both helpers reach /auth/login, each on its own verb. +import { Hono } from 'hono' +import authRoutes from '../auth' + +declare function it(name: string, fn: () => unknown): void + +async function post(path: string, body: Record) { + const app = new Hono() + app.route('/auth', authRoutes) + const headers: Record = { 'Content-Type': 'application/json' } + const payload = JSON.stringify(body) + return app.request(path, { method: 'POST', headers, body: payload }, { DB: 1 }) +} + +async function get(path: string) { + const app = new Hono() + app.route('/auth', authRoutes) + return app.request(path) +} + +it('logs in', async () => { + await post('/auth/login', { user: 'a' }) + await post('/auth/login/form', { user: 'a' }) +}) + +it('reads pages', async () => { + await get('/auth/login') + await get('/auth/session') +}) diff --git a/graph/test/typescript/hono/cases/rpc/helper-request-method/src/auth.ts b/graph/test/typescript/hono/cases/rpc/helper-request-method/src/auth.ts new file mode 100644 index 000000000..cb93b8ea9 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/helper-request-method/src/auth.ts @@ -0,0 +1,9 @@ +import { Hono } from 'hono' + +const authRoutes = new Hono() +authRoutes.get('/login', (c) => c.text('form')) +authRoutes.post('/login', (c) => c.json({ ok: true })) +authRoutes.post('/login/form', (c) => c.text('ok')) +authRoutes.get('/session', (c) => c.json({ user: null })) + +export default authRoutes diff --git a/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/api.ts b/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/api.ts new file mode 100644 index 000000000..0f5432540 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/api.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +export const api = new Hono() + .basePath('/api') + .get('/ready', (c) => c.json({ ready: true })) + .get('/version', (c) => c.json({ v: 1 })) diff --git a/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/main.ts b/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/main.ts new file mode 100644 index 000000000..65562f962 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/main.ts @@ -0,0 +1,11 @@ +// census: route_mount_root (violation hono-3-02) +// A fetch to this machine is matched on the COMPOSED full paths: /ready is served only by the root app, the +// basePath'd sub-app serves /api/ready and /api/version. +import { Hono } from 'hono' +import { api } from './api' + +const root = new Hono() +root.get('/ready', (c) => c.text('ok')) +root.route('/', api) + +export default root diff --git a/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/probe.ts b/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/probe.ts new file mode 100644 index 000000000..c533e6085 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/local-fetch-full-path/src/probe.ts @@ -0,0 +1,17 @@ +declare const process: { env: Record } + +export async function waitReady(): Promise { + const port = process.env.PORT ?? '3000' + const res = await fetch(`http://localhost:${port}/ready`) + return res.ok +} + +export async function apiVersion(): Promise { + const res = await fetch('http://127.0.0.1:3000/api/version') + return res.json() +} + +export async function notServedHere(): Promise { + const res = await fetch('http://localhost:3000/version') + return res.ok +} diff --git a/graph/test/typescript/hono/cases/rpc/mixed-segment-hole/src/index.ts b/graph/test/typescript/hono/cases/rpc/mixed-segment-hole/src/index.ts new file mode 100644 index 000000000..5c455f76f --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/mixed-segment-hole/src/index.ts @@ -0,0 +1,16 @@ +// census: request_fetch (stress-5 mutation m39 shape; violation hono-5-07) +// A segment that mixes literal text and a hole (`/api/skills${path}`) matches routes whose segment starts with that +// text (/api/skills/:id), never a sibling (/api/agents). +import { Hono } from 'hono' + +const app = new Hono() +app.get('/api/agents', (c) => c.json([])) +app.get('/api/skills/:id', (c) => c.json({})) +export default app + +export async function skillsApi(base: string, path: string) { + return fetch(`${base}/api/skills${path}`) +} +export async function skillsLocal(path: string) { + return fetch(`http://localhost:3000/api/skills${path}`) +} diff --git a/graph/test/typescript/hono/cases/rpc/monorepo-client/src/server/app.ts b/graph/test/typescript/hono/cases/rpc/monorepo-client/src/server/app.ts new file mode 100644 index 000000000..8016393f1 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/monorepo-client/src/server/app.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +export const api = new Hono().basePath('/api') + .get('/orders', (c) => c.json([])) + .post('/orders/:orderId/cancel', (c) => c.json({ cancelled: c.req.param('orderId') })) + +export type Api = typeof api diff --git a/graph/test/typescript/hono/cases/rpc/monorepo-client/src/web/orders.ts b/graph/test/typescript/hono/cases/rpc/monorepo-client/src/web/orders.ts new file mode 100644 index 000000000..bc2ce8c60 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/monorepo-client/src/web/orders.ts @@ -0,0 +1,16 @@ +// census: hc_client, hc_dollar_call, hc_element_param +// The client lives in another package of the workspace and imports only the server's TYPE. +import { hc } from 'hono/client' +import type { Api } from '../server/app' + +function makeClient() { + return hc('/') +} + +export async function cancelOrder(orderId: string) { + const c = makeClient() + return c.api.orders[':orderId'].cancel.$post({ param: { orderId } }) +} +export async function listOrders() { + return hc('/').api.orders.$get() +} diff --git a/graph/test/typescript/hono/cases/rpc/query-string/src/app.test.ts b/graph/test/typescript/hono/cases/rpc/query-string/src/app.test.ts new file mode 100644 index 000000000..20682330e --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/query-string/src/app.test.ts @@ -0,0 +1,10 @@ +// census: app_request_test (violation hono-2-05, SPEC R9) +// The query string and fragment are stripped before matching: both requests reach the /file handler exactly. +import { app } from './app' + +export async function withEncodedQuery(rel: string) { + return app.request(`http://localhost/sessions/S1/file?path=${encodeURIComponent(rel)}`) +} +export async function withLiteralQuery() { + return app.request('http://localhost/sessions/S1/file?path=..%2Fsecret.png#top') +} diff --git a/graph/test/typescript/hono/cases/rpc/query-string/src/app.ts b/graph/test/typescript/hono/cases/rpc/query-string/src/app.ts new file mode 100644 index 000000000..dd9f76038 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/query-string/src/app.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +export const app = new Hono() +app.get('/sessions/:id/file', (c) => c.text('file')) +app.get('/sessions/:id/objective', (c) => c.text('objective')) diff --git a/graph/test/typescript/hono/cases/rpc/reassigned-let/src/api.test.ts b/graph/test/typescript/hono/cases/rpc/reassigned-let/src/api.test.ts new file mode 100644 index 000000000..a01de4a32 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/reassigned-let/src/api.test.ts @@ -0,0 +1,21 @@ +// census: app_request_test (violation hono-2-03, SPEC R7; oracle gap O13) +// A `let` reassigned in another test is not a constant: in the request path it is a one-segment hole. +import api from './api' + +declare function test(name: string, fn: () => Promise): void + +let postId = '' +const fixed = 'p1' + +test('create', async () => { + postId = String(Date.now()) +}) +test('read', async () => { + await api.request(`/posts/${postId}`) +}) +test('update', async () => { + await api.request(`/posts/${postId}`, { method: 'PUT' }) +}) +test('fixed', async () => { + await api.request(`/posts/${fixed}`) +}) diff --git a/graph/test/typescript/hono/cases/rpc/reassigned-let/src/api.ts b/graph/test/typescript/hono/cases/rpc/reassigned-let/src/api.ts new file mode 100644 index 000000000..ec2b2c96d --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/reassigned-let/src/api.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +const api = new Hono() +api.get('/posts', (c) => c.json([])) +api.get('/posts/:id', (c) => c.json({})) +api.put('/posts/:id', (c) => c.json({})) + +export default api diff --git a/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/api.test.ts b/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/api.test.ts new file mode 100644 index 000000000..e5bc609dc --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/api.test.ts @@ -0,0 +1,10 @@ +import { hc } from 'hono/client' +import worker, { todos } from './api' + +export async function postsViaRequest() { + return worker.request('/posts', {}, {}) +} + +export async function todosViaClient() { + return hc('/api').todos.$get() +} diff --git a/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/api.ts b/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/api.ts new file mode 100644 index 000000000..506e7c750 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/api.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +const api = new Hono() +api.get('/posts', (c) => c.json([])) +export const todos = new Hono().get('/todos', (c) => c.json([])) +api.route('/', todos) + +export default api diff --git a/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/index.ts b/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/index.ts new file mode 100644 index 000000000..5926299cf --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/request-on-mounted-subapp/src/index.ts @@ -0,0 +1,10 @@ +// census: app_request_test, hc_client (violation hono-1-05) +// A request or client rooted at a sub-app that is ALSO mounted elsewhere is matched against that sub-app's +// own routes (relative to it), not the root's full paths. +import { Hono } from 'hono' +import api from './api' + +const app = new Hono() +app.route('/api', api) + +export default app diff --git a/graph/test/typescript/hono/cases/rpc/single-label-host/src/index.ts b/graph/test/typescript/hono/cases/rpc/single-label-host/src/index.ts new file mode 100644 index 000000000..f227658a7 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/single-label-host/src/index.ts @@ -0,0 +1,19 @@ +// census: request_fetch (stress-5 mutation m37 shape; violation hono-5-08, SPEC R14a) +// A literal single-label host (a service name inside the deployment) may reach this program's routes: joined with +// confidence base_unknown. A dotted external host never joins; an unknown base joins as base_unknown. +import { Hono } from 'hono' + +const app = new Hono() +app.get('/api/invoices', (c) => c.json([])) +app.get('/api/health', (c) => c.text('ok')) +export default app + +export async function listInvoices() { + return fetch('http://billing:9000/api/invoices') +} +export async function external() { + return fetch('https://api.example.com/api/health') +} +export async function viaBase(base: string) { + return fetch(`${base}/api/health`) +} diff --git a/graph/test/typescript/hono/cases/rpc/template-holes/src/app.test.ts b/graph/test/typescript/hono/cases/rpc/template-holes/src/app.test.ts new file mode 100644 index 000000000..38e974e0c --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/template-holes/src/app.test.ts @@ -0,0 +1,18 @@ +// census: app_request_test, hc_element_param (SPEC 3.5 [iter2] template holes and absolute URLs) +// A `${id}` hole is exactly one segment: it matches /posts/:id AND /posts/latest by shape; a hole no route +// shape fits is dynamic_rpc_path, never unserved; an absolute URL uses its pathname. +import { hc } from 'hono/client' +import { app } from './app' + +export async function oneByHole(id: string) { + return app.request(`/posts/${id}`) +} +export async function clientByHole(id: string) { + return (hc('http://api.example').posts as any)[id].$get() +} +export async function noShapeFits(id: string) { + return app.request(`/comments/${id}`) +} +export async function absoluteUrl() { + return app.request('http://localhost/posts') +} diff --git a/graph/test/typescript/hono/cases/rpc/template-holes/src/app.ts b/graph/test/typescript/hono/cases/rpc/template-holes/src/app.ts new file mode 100644 index 000000000..43a7e4c65 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/template-holes/src/app.ts @@ -0,0 +1,6 @@ +import { Hono } from 'hono' + +export const app = new Hono() + .get('/posts', (c) => c.json([])) + .get('/posts/latest', (c) => c.json({})) + .get('/posts/:id', (c) => c.json({ id: c.req.param('id') })) diff --git a/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/apps/api/package.json b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/apps/api/package.json new file mode 100644 index 000000000..8232df626 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/apps/api/package.json @@ -0,0 +1 @@ +{ "name": "@acme/api", "private": true, "type": "module" } diff --git a/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/apps/api/src/index.ts b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/apps/api/src/index.ts new file mode 100644 index 000000000..d7fe3ec66 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/apps/api/src/index.ts @@ -0,0 +1,11 @@ +// census: route_mount_literal (oracle gap O3b) +// A workspace package whose `exports` point at an unbuilt ./dist/ file: in a checkout the import is the package's +// source (src/adapters/hono.ts), so the dashboard is mounted under /admin and is no root of its own. +import { Hono } from 'hono' +import { dashboard } from '@acme/routes/hono' + +const app = new Hono() +app.get('/health', (c) => c.text('ok')) +app.route('/admin', dashboard({ title: 'Ops' })) + +export default app diff --git a/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/package.json b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/package.json new file mode 100644 index 000000000..f99862cd5 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/package.json @@ -0,0 +1,11 @@ +{ + "name": "@acme/routes", + "private": true, + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" }, + "./hono": { "types": "./dist/adapters/hono.d.ts", "import": "./dist/adapters/hono.js" } + } +} diff --git a/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/src/adapters/hono.ts b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/src/adapters/hono.ts new file mode 100644 index 000000000..ff930fe60 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/src/adapters/hono.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function dashboard(opts: { title: string }) { + const ui = new Hono() + ui.get('/', (c) => c.html(`

${opts.title}

`)) + ui.get('/api/activity', (c) => c.json([])) + return ui +} diff --git a/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/src/index.ts b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/src/index.ts new file mode 100644 index 000000000..5a52d1123 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-dist-exports/src/packages/routes/src/index.ts @@ -0,0 +1 @@ +export const VERSION = '1.0.0' diff --git a/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/lib/client.ts b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/lib/client.ts new file mode 100644 index 000000000..f49261d95 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/lib/client.ts @@ -0,0 +1,6 @@ +// census: hc_client (violation hono-2-08; oracle gap O3: a workspace package subpath through package.json exports) +import { client as v2 } from '@scope/client/v2' + +export function listSessions() { + return v2.sessions.$get() +} diff --git a/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/lib/v2/index.ts b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/lib/v2/index.ts new file mode 100644 index 000000000..5b6cb50f2 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/lib/v2/index.ts @@ -0,0 +1,4 @@ +import { hc } from 'hono/client' +import type { AppType } from '@scope/server' + +export const client = hc('http://localhost') diff --git a/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/package.json b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/package.json new file mode 100644 index 000000000..6172e6542 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/client/package.json @@ -0,0 +1 @@ +{ "name": "@scope/client", "private": true, "exports": { "./v2": { "types": "./lib/v2/index.ts", "import": "./lib/v2/index.ts" } } } diff --git a/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/server/package.json b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/server/package.json new file mode 100644 index 000000000..7831a25bb --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/server/package.json @@ -0,0 +1 @@ +{ "name": "@scope/server", "private": true, "exports": { ".": { "types": "./src/app.ts" } } } diff --git a/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/server/src/app.ts b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/server/src/app.ts new file mode 100644 index 000000000..612877f55 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-exports/src/packages/server/src/app.ts @@ -0,0 +1,7 @@ +import { Hono } from 'hono' + +const app = new Hono() +const routes = app.get('/sessions', (c) => c.json([])) + +export type AppType = typeof routes +export default app diff --git a/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/admin/package.json b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/admin/package.json new file mode 100644 index 000000000..0a0c85eb5 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/admin/package.json @@ -0,0 +1 @@ +{ "name": "@acme/admin", "private": true } diff --git a/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/admin/routes.ts b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/admin/routes.ts new file mode 100644 index 000000000..8f02ba76b --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/admin/routes.ts @@ -0,0 +1,3 @@ +import { Hono } from 'hono' + +export const admin = new Hono().get('/users', (c) => c.json([])) diff --git a/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/server/package.json b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/server/package.json new file mode 100644 index 000000000..399928b37 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/server/package.json @@ -0,0 +1 @@ +{ "name": "@acme/server", "private": true, "types": "src/index.ts" } diff --git a/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/server/src/index.ts b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/server/src/index.ts new file mode 100644 index 000000000..a6857d8b7 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/server/src/index.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' +import { admin } from '@acme/admin/routes' + +const app = new Hono() +const routes = app.get('/ping', (c) => c.text('pong')).route('/admin', admin) + +export type AppType = typeof routes +export default app diff --git a/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/web/client.ts b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/web/client.ts new file mode 100644 index 000000000..6a845f924 --- /dev/null +++ b/graph/test/typescript/hono/cases/rpc/workspace-package/src/packages/web/client.ts @@ -0,0 +1,13 @@ +// census: hc_client, route_mount_literal (oracle gap O3: workspace package imports in a monorepo) +// Packages import each other by workspace package name: the mount and the typed client both cross them. +import { hc } from 'hono/client' +import type { AppType } from '@acme/server' + +const client = hc('/') + +export function ping() { + return client.ping.$get() +} +export function adminUsers() { + return client.admin.users.$get() +} diff --git a/graph/test/typescript/hono/cases/scale/deep-mount/budget b/graph/test/typescript/hono/cases/scale/deep-mount/budget new file mode 100644 index 000000000..e536b1826 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/deep-mount/budget @@ -0,0 +1,2 @@ +120 +rss_mb 2048 diff --git a/graph/test/typescript/hono/cases/scale/deep-mount/src/index.ts b/graph/test/typescript/hono/cases/scale/deep-mount/src/index.ts new file mode 100644 index 000000000..02cf67b37 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/deep-mount/src/index.ts @@ -0,0 +1,34 @@ +// census: route_mount_literal (scale: 10-deep mounting; generated by tools/gen-scale.mjs) +import { Hono } from 'hono' + +const l0 = new Hono() +l0.get('/here', (c) => c.text('level 0')) +const l1 = new Hono() +l1.get('/here', (c) => c.text('level 1')) +const l2 = new Hono() +l2.get('/here', (c) => c.text('level 2')) +const l3 = new Hono() +l3.get('/here', (c) => c.text('level 3')) +const l4 = new Hono() +l4.get('/here', (c) => c.text('level 4')) +const l5 = new Hono() +l5.get('/here', (c) => c.text('level 5')) +const l6 = new Hono() +l6.get('/here', (c) => c.text('level 6')) +const l7 = new Hono() +l7.get('/here', (c) => c.text('level 7')) +const l8 = new Hono() +l8.get('/here', (c) => c.text('level 8')) +const l9 = new Hono() +l9.get('/here', (c) => c.text('level 9')) +l8.route('/d9', l9) +l7.route('/d8', l8) +l6.route('/d7', l7) +l5.route('/d6', l6) +l4.route('/d5', l5) +l3.route('/d4', l4) +l2.route('/d3', l3) +l1.route('/d2', l2) +l0.route('/d1', l1) + +export default l0 diff --git a/graph/test/typescript/hono/cases/scale/mw-200/budget b/graph/test/typescript/hono/cases/scale/mw-200/budget new file mode 100644 index 000000000..ae729d3cc --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/mw-200/budget @@ -0,0 +1,2 @@ +300 +rss_mb 2048 diff --git a/graph/test/typescript/hono/cases/scale/mw-200/src/index.ts b/graph/test/typescript/hono/cases/scale/mw-200/src/index.ts new file mode 100644 index 000000000..366b8f2c4 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/mw-200/src/index.ts @@ -0,0 +1,417 @@ +// census: use_global, await_next (scale: 200 middleware x 10 routes; generated by tools/gen-scale.mjs) +import { Hono } from 'hono' +import type { MiddlewareHandler } from 'hono' + +const app = new Hono() +const m0: MiddlewareHandler = async (c, next) => { await next() } +app.use(m0) +const m1: MiddlewareHandler = async (c, next) => { await next() } +app.use(m1) +const m2: MiddlewareHandler = async (c, next) => { await next() } +app.use(m2) +const m3: MiddlewareHandler = async (c, next) => { await next() } +app.use(m3) +const m4: MiddlewareHandler = async (c, next) => { await next() } +app.use(m4) +const m5: MiddlewareHandler = async (c, next) => { await next() } +app.use(m5) +const m6: MiddlewareHandler = async (c, next) => { await next() } +app.use(m6) +const m7: MiddlewareHandler = async (c, next) => { await next() } +app.use(m7) +const m8: MiddlewareHandler = async (c, next) => { await next() } +app.use(m8) +const m9: MiddlewareHandler = async (c, next) => { await next() } +app.use(m9) +const m10: MiddlewareHandler = async (c, next) => { await next() } +app.use(m10) +const m11: MiddlewareHandler = async (c, next) => { await next() } +app.use(m11) +const m12: MiddlewareHandler = async (c, next) => { await next() } +app.use(m12) +const m13: MiddlewareHandler = async (c, next) => { await next() } +app.use(m13) +const m14: MiddlewareHandler = async (c, next) => { await next() } +app.use(m14) +const m15: MiddlewareHandler = async (c, next) => { await next() } +app.use(m15) +const m16: MiddlewareHandler = async (c, next) => { await next() } +app.use(m16) +const m17: MiddlewareHandler = async (c, next) => { await next() } +app.use(m17) +const m18: MiddlewareHandler = async (c, next) => { await next() } +app.use(m18) +const m19: MiddlewareHandler = async (c, next) => { await next() } +app.use(m19) +const m20: MiddlewareHandler = async (c, next) => { await next() } +app.use(m20) +const m21: MiddlewareHandler = async (c, next) => { await next() } +app.use(m21) +const m22: MiddlewareHandler = async (c, next) => { await next() } +app.use(m22) +const m23: MiddlewareHandler = async (c, next) => { await next() } +app.use(m23) +const m24: MiddlewareHandler = async (c, next) => { await next() } +app.use(m24) +const m25: MiddlewareHandler = async (c, next) => { await next() } +app.use(m25) +const m26: MiddlewareHandler = async (c, next) => { await next() } +app.use(m26) +const m27: MiddlewareHandler = async (c, next) => { await next() } +app.use(m27) +const m28: MiddlewareHandler = async (c, next) => { await next() } +app.use(m28) +const m29: MiddlewareHandler = async (c, next) => { await next() } +app.use(m29) +const m30: MiddlewareHandler = async (c, next) => { await next() } +app.use(m30) +const m31: MiddlewareHandler = async (c, next) => { await next() } +app.use(m31) +const m32: MiddlewareHandler = async (c, next) => { await next() } +app.use(m32) +const m33: MiddlewareHandler = async (c, next) => { await next() } +app.use(m33) +const m34: MiddlewareHandler = async (c, next) => { await next() } +app.use(m34) +const m35: MiddlewareHandler = async (c, next) => { await next() } +app.use(m35) +const m36: MiddlewareHandler = async (c, next) => { await next() } +app.use(m36) +const m37: MiddlewareHandler = async (c, next) => { await next() } +app.use(m37) +const m38: MiddlewareHandler = async (c, next) => { await next() } +app.use(m38) +const m39: MiddlewareHandler = async (c, next) => { await next() } +app.use(m39) +const m40: MiddlewareHandler = async (c, next) => { await next() } +app.use(m40) +const m41: MiddlewareHandler = async (c, next) => { await next() } +app.use(m41) +const m42: MiddlewareHandler = async (c, next) => { await next() } +app.use(m42) +const m43: MiddlewareHandler = async (c, next) => { await next() } +app.use(m43) +const m44: MiddlewareHandler = async (c, next) => { await next() } +app.use(m44) +const m45: MiddlewareHandler = async (c, next) => { await next() } +app.use(m45) +const m46: MiddlewareHandler = async (c, next) => { await next() } +app.use(m46) +const m47: MiddlewareHandler = async (c, next) => { await next() } +app.use(m47) +const m48: MiddlewareHandler = async (c, next) => { await next() } +app.use(m48) +const m49: MiddlewareHandler = async (c, next) => { await next() } +app.use(m49) +const m50: MiddlewareHandler = async (c, next) => { await next() } +app.use(m50) +const m51: MiddlewareHandler = async (c, next) => { await next() } +app.use(m51) +const m52: MiddlewareHandler = async (c, next) => { await next() } +app.use(m52) +const m53: MiddlewareHandler = async (c, next) => { await next() } +app.use(m53) +const m54: MiddlewareHandler = async (c, next) => { await next() } +app.use(m54) +const m55: MiddlewareHandler = async (c, next) => { await next() } +app.use(m55) +const m56: MiddlewareHandler = async (c, next) => { await next() } +app.use(m56) +const m57: MiddlewareHandler = async (c, next) => { await next() } +app.use(m57) +const m58: MiddlewareHandler = async (c, next) => { await next() } +app.use(m58) +const m59: MiddlewareHandler = async (c, next) => { await next() } +app.use(m59) +const m60: MiddlewareHandler = async (c, next) => { await next() } +app.use(m60) +const m61: MiddlewareHandler = async (c, next) => { await next() } +app.use(m61) +const m62: MiddlewareHandler = async (c, next) => { await next() } +app.use(m62) +const m63: MiddlewareHandler = async (c, next) => { await next() } +app.use(m63) +const m64: MiddlewareHandler = async (c, next) => { await next() } +app.use(m64) +const m65: MiddlewareHandler = async (c, next) => { await next() } +app.use(m65) +const m66: MiddlewareHandler = async (c, next) => { await next() } +app.use(m66) +const m67: MiddlewareHandler = async (c, next) => { await next() } +app.use(m67) +const m68: MiddlewareHandler = async (c, next) => { await next() } +app.use(m68) +const m69: MiddlewareHandler = async (c, next) => { await next() } +app.use(m69) +const m70: MiddlewareHandler = async (c, next) => { await next() } +app.use(m70) +const m71: MiddlewareHandler = async (c, next) => { await next() } +app.use(m71) +const m72: MiddlewareHandler = async (c, next) => { await next() } +app.use(m72) +const m73: MiddlewareHandler = async (c, next) => { await next() } +app.use(m73) +const m74: MiddlewareHandler = async (c, next) => { await next() } +app.use(m74) +const m75: MiddlewareHandler = async (c, next) => { await next() } +app.use(m75) +const m76: MiddlewareHandler = async (c, next) => { await next() } +app.use(m76) +const m77: MiddlewareHandler = async (c, next) => { await next() } +app.use(m77) +const m78: MiddlewareHandler = async (c, next) => { await next() } +app.use(m78) +const m79: MiddlewareHandler = async (c, next) => { await next() } +app.use(m79) +const m80: MiddlewareHandler = async (c, next) => { await next() } +app.use(m80) +const m81: MiddlewareHandler = async (c, next) => { await next() } +app.use(m81) +const m82: MiddlewareHandler = async (c, next) => { await next() } +app.use(m82) +const m83: MiddlewareHandler = async (c, next) => { await next() } +app.use(m83) +const m84: MiddlewareHandler = async (c, next) => { await next() } +app.use(m84) +const m85: MiddlewareHandler = async (c, next) => { await next() } +app.use(m85) +const m86: MiddlewareHandler = async (c, next) => { await next() } +app.use(m86) +const m87: MiddlewareHandler = async (c, next) => { await next() } +app.use(m87) +const m88: MiddlewareHandler = async (c, next) => { await next() } +app.use(m88) +const m89: MiddlewareHandler = async (c, next) => { await next() } +app.use(m89) +const m90: MiddlewareHandler = async (c, next) => { await next() } +app.use(m90) +const m91: MiddlewareHandler = async (c, next) => { await next() } +app.use(m91) +const m92: MiddlewareHandler = async (c, next) => { await next() } +app.use(m92) +const m93: MiddlewareHandler = async (c, next) => { await next() } +app.use(m93) +const m94: MiddlewareHandler = async (c, next) => { await next() } +app.use(m94) +const m95: MiddlewareHandler = async (c, next) => { await next() } +app.use(m95) +const m96: MiddlewareHandler = async (c, next) => { await next() } +app.use(m96) +const m97: MiddlewareHandler = async (c, next) => { await next() } +app.use(m97) +const m98: MiddlewareHandler = async (c, next) => { await next() } +app.use(m98) +const m99: MiddlewareHandler = async (c, next) => { await next() } +app.use(m99) +const m100: MiddlewareHandler = async (c, next) => { await next() } +app.use(m100) +const m101: MiddlewareHandler = async (c, next) => { await next() } +app.use(m101) +const m102: MiddlewareHandler = async (c, next) => { await next() } +app.use(m102) +const m103: MiddlewareHandler = async (c, next) => { await next() } +app.use(m103) +const m104: MiddlewareHandler = async (c, next) => { await next() } +app.use(m104) +const m105: MiddlewareHandler = async (c, next) => { await next() } +app.use(m105) +const m106: MiddlewareHandler = async (c, next) => { await next() } +app.use(m106) +const m107: MiddlewareHandler = async (c, next) => { await next() } +app.use(m107) +const m108: MiddlewareHandler = async (c, next) => { await next() } +app.use(m108) +const m109: MiddlewareHandler = async (c, next) => { await next() } +app.use(m109) +const m110: MiddlewareHandler = async (c, next) => { await next() } +app.use(m110) +const m111: MiddlewareHandler = async (c, next) => { await next() } +app.use(m111) +const m112: MiddlewareHandler = async (c, next) => { await next() } +app.use(m112) +const m113: MiddlewareHandler = async (c, next) => { await next() } +app.use(m113) +const m114: MiddlewareHandler = async (c, next) => { await next() } +app.use(m114) +const m115: MiddlewareHandler = async (c, next) => { await next() } +app.use(m115) +const m116: MiddlewareHandler = async (c, next) => { await next() } +app.use(m116) +const m117: MiddlewareHandler = async (c, next) => { await next() } +app.use(m117) +const m118: MiddlewareHandler = async (c, next) => { await next() } +app.use(m118) +const m119: MiddlewareHandler = async (c, next) => { await next() } +app.use(m119) +const m120: MiddlewareHandler = async (c, next) => { await next() } +app.use(m120) +const m121: MiddlewareHandler = async (c, next) => { await next() } +app.use(m121) +const m122: MiddlewareHandler = async (c, next) => { await next() } +app.use(m122) +const m123: MiddlewareHandler = async (c, next) => { await next() } +app.use(m123) +const m124: MiddlewareHandler = async (c, next) => { await next() } +app.use(m124) +const m125: MiddlewareHandler = async (c, next) => { await next() } +app.use(m125) +const m126: MiddlewareHandler = async (c, next) => { await next() } +app.use(m126) +const m127: MiddlewareHandler = async (c, next) => { await next() } +app.use(m127) +const m128: MiddlewareHandler = async (c, next) => { await next() } +app.use(m128) +const m129: MiddlewareHandler = async (c, next) => { await next() } +app.use(m129) +const m130: MiddlewareHandler = async (c, next) => { await next() } +app.use(m130) +const m131: MiddlewareHandler = async (c, next) => { await next() } +app.use(m131) +const m132: MiddlewareHandler = async (c, next) => { await next() } +app.use(m132) +const m133: MiddlewareHandler = async (c, next) => { await next() } +app.use(m133) +const m134: MiddlewareHandler = async (c, next) => { await next() } +app.use(m134) +const m135: MiddlewareHandler = async (c, next) => { await next() } +app.use(m135) +const m136: MiddlewareHandler = async (c, next) => { await next() } +app.use(m136) +const m137: MiddlewareHandler = async (c, next) => { await next() } +app.use(m137) +const m138: MiddlewareHandler = async (c, next) => { await next() } +app.use(m138) +const m139: MiddlewareHandler = async (c, next) => { await next() } +app.use(m139) +const m140: MiddlewareHandler = async (c, next) => { await next() } +app.use(m140) +const m141: MiddlewareHandler = async (c, next) => { await next() } +app.use(m141) +const m142: MiddlewareHandler = async (c, next) => { await next() } +app.use(m142) +const m143: MiddlewareHandler = async (c, next) => { await next() } +app.use(m143) +const m144: MiddlewareHandler = async (c, next) => { await next() } +app.use(m144) +const m145: MiddlewareHandler = async (c, next) => { await next() } +app.use(m145) +const m146: MiddlewareHandler = async (c, next) => { await next() } +app.use(m146) +const m147: MiddlewareHandler = async (c, next) => { await next() } +app.use(m147) +const m148: MiddlewareHandler = async (c, next) => { await next() } +app.use(m148) +const m149: MiddlewareHandler = async (c, next) => { await next() } +app.use(m149) +const m150: MiddlewareHandler = async (c, next) => { await next() } +app.use(m150) +const m151: MiddlewareHandler = async (c, next) => { await next() } +app.use(m151) +const m152: MiddlewareHandler = async (c, next) => { await next() } +app.use(m152) +const m153: MiddlewareHandler = async (c, next) => { await next() } +app.use(m153) +const m154: MiddlewareHandler = async (c, next) => { await next() } +app.use(m154) +const m155: MiddlewareHandler = async (c, next) => { await next() } +app.use(m155) +const m156: MiddlewareHandler = async (c, next) => { await next() } +app.use(m156) +const m157: MiddlewareHandler = async (c, next) => { await next() } +app.use(m157) +const m158: MiddlewareHandler = async (c, next) => { await next() } +app.use(m158) +const m159: MiddlewareHandler = async (c, next) => { await next() } +app.use(m159) +const m160: MiddlewareHandler = async (c, next) => { await next() } +app.use(m160) +const m161: MiddlewareHandler = async (c, next) => { await next() } +app.use(m161) +const m162: MiddlewareHandler = async (c, next) => { await next() } +app.use(m162) +const m163: MiddlewareHandler = async (c, next) => { await next() } +app.use(m163) +const m164: MiddlewareHandler = async (c, next) => { await next() } +app.use(m164) +const m165: MiddlewareHandler = async (c, next) => { await next() } +app.use(m165) +const m166: MiddlewareHandler = async (c, next) => { await next() } +app.use(m166) +const m167: MiddlewareHandler = async (c, next) => { await next() } +app.use(m167) +const m168: MiddlewareHandler = async (c, next) => { await next() } +app.use(m168) +const m169: MiddlewareHandler = async (c, next) => { await next() } +app.use(m169) +const m170: MiddlewareHandler = async (c, next) => { await next() } +app.use(m170) +const m171: MiddlewareHandler = async (c, next) => { await next() } +app.use(m171) +const m172: MiddlewareHandler = async (c, next) => { await next() } +app.use(m172) +const m173: MiddlewareHandler = async (c, next) => { await next() } +app.use(m173) +const m174: MiddlewareHandler = async (c, next) => { await next() } +app.use(m174) +const m175: MiddlewareHandler = async (c, next) => { await next() } +app.use(m175) +const m176: MiddlewareHandler = async (c, next) => { await next() } +app.use(m176) +const m177: MiddlewareHandler = async (c, next) => { await next() } +app.use(m177) +const m178: MiddlewareHandler = async (c, next) => { await next() } +app.use(m178) +const m179: MiddlewareHandler = async (c, next) => { await next() } +app.use(m179) +const m180: MiddlewareHandler = async (c, next) => { await next() } +app.use(m180) +const m181: MiddlewareHandler = async (c, next) => { await next() } +app.use(m181) +const m182: MiddlewareHandler = async (c, next) => { await next() } +app.use(m182) +const m183: MiddlewareHandler = async (c, next) => { await next() } +app.use(m183) +const m184: MiddlewareHandler = async (c, next) => { await next() } +app.use(m184) +const m185: MiddlewareHandler = async (c, next) => { await next() } +app.use(m185) +const m186: MiddlewareHandler = async (c, next) => { await next() } +app.use(m186) +const m187: MiddlewareHandler = async (c, next) => { await next() } +app.use(m187) +const m188: MiddlewareHandler = async (c, next) => { await next() } +app.use(m188) +const m189: MiddlewareHandler = async (c, next) => { await next() } +app.use(m189) +const m190: MiddlewareHandler = async (c, next) => { await next() } +app.use(m190) +const m191: MiddlewareHandler = async (c, next) => { await next() } +app.use(m191) +const m192: MiddlewareHandler = async (c, next) => { await next() } +app.use(m192) +const m193: MiddlewareHandler = async (c, next) => { await next() } +app.use(m193) +const m194: MiddlewareHandler = async (c, next) => { await next() } +app.use(m194) +const m195: MiddlewareHandler = async (c, next) => { await next() } +app.use(m195) +const m196: MiddlewareHandler = async (c, next) => { await next() } +app.use(m196) +const m197: MiddlewareHandler = async (c, next) => { await next() } +app.use(m197) +const m198: MiddlewareHandler = async (c, next) => { await next() } +app.use(m198) +const m199: MiddlewareHandler = async (c, next) => { await next() } +app.use(m199) +app.get('/r0', (c) => c.text('0')) +app.get('/r1', (c) => c.text('1')) +app.get('/r2', (c) => c.text('2')) +app.get('/r3', (c) => c.text('3')) +app.get('/r4', (c) => c.text('4')) +app.get('/r5', (c) => c.text('5')) +app.get('/r6', (c) => c.text('6')) +app.get('/r7', (c) => c.text('7')) +app.get('/r8', (c) => c.text('8')) +app.get('/r9', (c) => c.text('9')) + +export default app diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/budget b/graph/test/typescript/hono/cases/scale/routes-2k/budget new file mode 100644 index 000000000..ae729d3cc --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/budget @@ -0,0 +1,2 @@ +300 +rss_mb 2048 diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/index.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/index.ts new file mode 100644 index 000000000..9aaa7b83e --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/index.ts @@ -0,0 +1,46 @@ +// census: route_mount_literal, verb_literal_path (scale: 2,000 routes; generated by tools/gen-scale.mjs) +import { Hono } from 'hono' +import { r0 } from './mod0' +import { r1 } from './mod1' +import { r2 } from './mod2' +import { r3 } from './mod3' +import { r4 } from './mod4' +import { r5 } from './mod5' +import { r6 } from './mod6' +import { r7 } from './mod7' +import { r8 } from './mod8' +import { r9 } from './mod9' +import { r10 } from './mod10' +import { r11 } from './mod11' +import { r12 } from './mod12' +import { r13 } from './mod13' +import { r14 } from './mod14' +import { r15 } from './mod15' +import { r16 } from './mod16' +import { r17 } from './mod17' +import { r18 } from './mod18' +import { r19 } from './mod19' + +const app = new Hono() +app.route('/m0', r0) +app.route('/m1', r1) +app.route('/m2', r2) +app.route('/m3', r3) +app.route('/m4', r4) +app.route('/m5', r5) +app.route('/m6', r6) +app.route('/m7', r7) +app.route('/m8', r8) +app.route('/m9', r9) +app.route('/m10', r10) +app.route('/m11', r11) +app.route('/m12', r12) +app.route('/m13', r13) +app.route('/m14', r14) +app.route('/m15', r15) +app.route('/m16', r16) +app.route('/m17', r17) +app.route('/m18', r18) +app.route('/m19', r19) + +export default app diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod0.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod0.ts new file mode 100644 index 000000000..f488457ef --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod0.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r0 = new Hono() +r0.get('/res0/:id', (c) => c.text('m0 r0')) +r0.post('/res1/:id', (c) => c.text('m0 r1')) +r0.put('/res2/:id', (c) => c.text('m0 r2')) +r0.delete('/res3/:id', (c) => c.text('m0 r3')) +r0.patch('/res4/:id', (c) => c.text('m0 r4')) +r0.get('/res5/:id', (c) => c.text('m0 r5')) +r0.post('/res6/:id', (c) => c.text('m0 r6')) +r0.put('/res7/:id', (c) => c.text('m0 r7')) +r0.delete('/res8/:id', (c) => c.text('m0 r8')) +r0.patch('/res9/:id', (c) => c.text('m0 r9')) +r0.get('/res10/:id', (c) => c.text('m0 r10')) +r0.post('/res11/:id', (c) => c.text('m0 r11')) +r0.put('/res12/:id', (c) => c.text('m0 r12')) +r0.delete('/res13/:id', (c) => c.text('m0 r13')) +r0.patch('/res14/:id', (c) => c.text('m0 r14')) +r0.get('/res15/:id', (c) => c.text('m0 r15')) +r0.post('/res16/:id', (c) => c.text('m0 r16')) +r0.put('/res17/:id', (c) => c.text('m0 r17')) +r0.delete('/res18/:id', (c) => c.text('m0 r18')) +r0.patch('/res19/:id', (c) => c.text('m0 r19')) +r0.get('/res20/:id', (c) => c.text('m0 r20')) +r0.post('/res21/:id', (c) => c.text('m0 r21')) +r0.put('/res22/:id', (c) => c.text('m0 r22')) +r0.delete('/res23/:id', (c) => c.text('m0 r23')) +r0.patch('/res24/:id', (c) => c.text('m0 r24')) +r0.get('/res25/:id', (c) => c.text('m0 r25')) +r0.post('/res26/:id', (c) => c.text('m0 r26')) +r0.put('/res27/:id', (c) => c.text('m0 r27')) +r0.delete('/res28/:id', (c) => c.text('m0 r28')) +r0.patch('/res29/:id', (c) => c.text('m0 r29')) +r0.get('/res30/:id', (c) => c.text('m0 r30')) +r0.post('/res31/:id', (c) => c.text('m0 r31')) +r0.put('/res32/:id', (c) => c.text('m0 r32')) +r0.delete('/res33/:id', (c) => c.text('m0 r33')) +r0.patch('/res34/:id', (c) => c.text('m0 r34')) +r0.get('/res35/:id', (c) => c.text('m0 r35')) +r0.post('/res36/:id', (c) => c.text('m0 r36')) +r0.put('/res37/:id', (c) => c.text('m0 r37')) +r0.delete('/res38/:id', (c) => c.text('m0 r38')) +r0.patch('/res39/:id', (c) => c.text('m0 r39')) +r0.get('/res40/:id', (c) => c.text('m0 r40')) +r0.post('/res41/:id', (c) => c.text('m0 r41')) +r0.put('/res42/:id', (c) => c.text('m0 r42')) +r0.delete('/res43/:id', (c) => c.text('m0 r43')) +r0.patch('/res44/:id', (c) => c.text('m0 r44')) +r0.get('/res45/:id', (c) => c.text('m0 r45')) +r0.post('/res46/:id', (c) => c.text('m0 r46')) +r0.put('/res47/:id', (c) => c.text('m0 r47')) +r0.delete('/res48/:id', (c) => c.text('m0 r48')) +r0.patch('/res49/:id', (c) => c.text('m0 r49')) +r0.get('/res50/:id', (c) => c.text('m0 r50')) +r0.post('/res51/:id', (c) => c.text('m0 r51')) +r0.put('/res52/:id', (c) => c.text('m0 r52')) +r0.delete('/res53/:id', (c) => c.text('m0 r53')) +r0.patch('/res54/:id', (c) => c.text('m0 r54')) +r0.get('/res55/:id', (c) => c.text('m0 r55')) +r0.post('/res56/:id', (c) => c.text('m0 r56')) +r0.put('/res57/:id', (c) => c.text('m0 r57')) +r0.delete('/res58/:id', (c) => c.text('m0 r58')) +r0.patch('/res59/:id', (c) => c.text('m0 r59')) +r0.get('/res60/:id', (c) => c.text('m0 r60')) +r0.post('/res61/:id', (c) => c.text('m0 r61')) +r0.put('/res62/:id', (c) => c.text('m0 r62')) +r0.delete('/res63/:id', (c) => c.text('m0 r63')) +r0.patch('/res64/:id', (c) => c.text('m0 r64')) +r0.get('/res65/:id', (c) => c.text('m0 r65')) +r0.post('/res66/:id', (c) => c.text('m0 r66')) +r0.put('/res67/:id', (c) => c.text('m0 r67')) +r0.delete('/res68/:id', (c) => c.text('m0 r68')) +r0.patch('/res69/:id', (c) => c.text('m0 r69')) +r0.get('/res70/:id', (c) => c.text('m0 r70')) +r0.post('/res71/:id', (c) => c.text('m0 r71')) +r0.put('/res72/:id', (c) => c.text('m0 r72')) +r0.delete('/res73/:id', (c) => c.text('m0 r73')) +r0.patch('/res74/:id', (c) => c.text('m0 r74')) +r0.get('/res75/:id', (c) => c.text('m0 r75')) +r0.post('/res76/:id', (c) => c.text('m0 r76')) +r0.put('/res77/:id', (c) => c.text('m0 r77')) +r0.delete('/res78/:id', (c) => c.text('m0 r78')) +r0.patch('/res79/:id', (c) => c.text('m0 r79')) +r0.get('/res80/:id', (c) => c.text('m0 r80')) +r0.post('/res81/:id', (c) => c.text('m0 r81')) +r0.put('/res82/:id', (c) => c.text('m0 r82')) +r0.delete('/res83/:id', (c) => c.text('m0 r83')) +r0.patch('/res84/:id', (c) => c.text('m0 r84')) +r0.get('/res85/:id', (c) => c.text('m0 r85')) +r0.post('/res86/:id', (c) => c.text('m0 r86')) +r0.put('/res87/:id', (c) => c.text('m0 r87')) +r0.delete('/res88/:id', (c) => c.text('m0 r88')) +r0.patch('/res89/:id', (c) => c.text('m0 r89')) +r0.get('/res90/:id', (c) => c.text('m0 r90')) +r0.post('/res91/:id', (c) => c.text('m0 r91')) +r0.put('/res92/:id', (c) => c.text('m0 r92')) +r0.delete('/res93/:id', (c) => c.text('m0 r93')) +r0.patch('/res94/:id', (c) => c.text('m0 r94')) +r0.get('/res95/:id', (c) => c.text('m0 r95')) +r0.post('/res96/:id', (c) => c.text('m0 r96')) +r0.put('/res97/:id', (c) => c.text('m0 r97')) +r0.delete('/res98/:id', (c) => c.text('m0 r98')) +r0.patch('/res99/:id', (c) => c.text('m0 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod1.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod1.ts new file mode 100644 index 000000000..8f6c72ba7 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod1.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r1 = new Hono() +r1.get('/res0/:id', (c) => c.text('m1 r0')) +r1.post('/res1/:id', (c) => c.text('m1 r1')) +r1.put('/res2/:id', (c) => c.text('m1 r2')) +r1.delete('/res3/:id', (c) => c.text('m1 r3')) +r1.patch('/res4/:id', (c) => c.text('m1 r4')) +r1.get('/res5/:id', (c) => c.text('m1 r5')) +r1.post('/res6/:id', (c) => c.text('m1 r6')) +r1.put('/res7/:id', (c) => c.text('m1 r7')) +r1.delete('/res8/:id', (c) => c.text('m1 r8')) +r1.patch('/res9/:id', (c) => c.text('m1 r9')) +r1.get('/res10/:id', (c) => c.text('m1 r10')) +r1.post('/res11/:id', (c) => c.text('m1 r11')) +r1.put('/res12/:id', (c) => c.text('m1 r12')) +r1.delete('/res13/:id', (c) => c.text('m1 r13')) +r1.patch('/res14/:id', (c) => c.text('m1 r14')) +r1.get('/res15/:id', (c) => c.text('m1 r15')) +r1.post('/res16/:id', (c) => c.text('m1 r16')) +r1.put('/res17/:id', (c) => c.text('m1 r17')) +r1.delete('/res18/:id', (c) => c.text('m1 r18')) +r1.patch('/res19/:id', (c) => c.text('m1 r19')) +r1.get('/res20/:id', (c) => c.text('m1 r20')) +r1.post('/res21/:id', (c) => c.text('m1 r21')) +r1.put('/res22/:id', (c) => c.text('m1 r22')) +r1.delete('/res23/:id', (c) => c.text('m1 r23')) +r1.patch('/res24/:id', (c) => c.text('m1 r24')) +r1.get('/res25/:id', (c) => c.text('m1 r25')) +r1.post('/res26/:id', (c) => c.text('m1 r26')) +r1.put('/res27/:id', (c) => c.text('m1 r27')) +r1.delete('/res28/:id', (c) => c.text('m1 r28')) +r1.patch('/res29/:id', (c) => c.text('m1 r29')) +r1.get('/res30/:id', (c) => c.text('m1 r30')) +r1.post('/res31/:id', (c) => c.text('m1 r31')) +r1.put('/res32/:id', (c) => c.text('m1 r32')) +r1.delete('/res33/:id', (c) => c.text('m1 r33')) +r1.patch('/res34/:id', (c) => c.text('m1 r34')) +r1.get('/res35/:id', (c) => c.text('m1 r35')) +r1.post('/res36/:id', (c) => c.text('m1 r36')) +r1.put('/res37/:id', (c) => c.text('m1 r37')) +r1.delete('/res38/:id', (c) => c.text('m1 r38')) +r1.patch('/res39/:id', (c) => c.text('m1 r39')) +r1.get('/res40/:id', (c) => c.text('m1 r40')) +r1.post('/res41/:id', (c) => c.text('m1 r41')) +r1.put('/res42/:id', (c) => c.text('m1 r42')) +r1.delete('/res43/:id', (c) => c.text('m1 r43')) +r1.patch('/res44/:id', (c) => c.text('m1 r44')) +r1.get('/res45/:id', (c) => c.text('m1 r45')) +r1.post('/res46/:id', (c) => c.text('m1 r46')) +r1.put('/res47/:id', (c) => c.text('m1 r47')) +r1.delete('/res48/:id', (c) => c.text('m1 r48')) +r1.patch('/res49/:id', (c) => c.text('m1 r49')) +r1.get('/res50/:id', (c) => c.text('m1 r50')) +r1.post('/res51/:id', (c) => c.text('m1 r51')) +r1.put('/res52/:id', (c) => c.text('m1 r52')) +r1.delete('/res53/:id', (c) => c.text('m1 r53')) +r1.patch('/res54/:id', (c) => c.text('m1 r54')) +r1.get('/res55/:id', (c) => c.text('m1 r55')) +r1.post('/res56/:id', (c) => c.text('m1 r56')) +r1.put('/res57/:id', (c) => c.text('m1 r57')) +r1.delete('/res58/:id', (c) => c.text('m1 r58')) +r1.patch('/res59/:id', (c) => c.text('m1 r59')) +r1.get('/res60/:id', (c) => c.text('m1 r60')) +r1.post('/res61/:id', (c) => c.text('m1 r61')) +r1.put('/res62/:id', (c) => c.text('m1 r62')) +r1.delete('/res63/:id', (c) => c.text('m1 r63')) +r1.patch('/res64/:id', (c) => c.text('m1 r64')) +r1.get('/res65/:id', (c) => c.text('m1 r65')) +r1.post('/res66/:id', (c) => c.text('m1 r66')) +r1.put('/res67/:id', (c) => c.text('m1 r67')) +r1.delete('/res68/:id', (c) => c.text('m1 r68')) +r1.patch('/res69/:id', (c) => c.text('m1 r69')) +r1.get('/res70/:id', (c) => c.text('m1 r70')) +r1.post('/res71/:id', (c) => c.text('m1 r71')) +r1.put('/res72/:id', (c) => c.text('m1 r72')) +r1.delete('/res73/:id', (c) => c.text('m1 r73')) +r1.patch('/res74/:id', (c) => c.text('m1 r74')) +r1.get('/res75/:id', (c) => c.text('m1 r75')) +r1.post('/res76/:id', (c) => c.text('m1 r76')) +r1.put('/res77/:id', (c) => c.text('m1 r77')) +r1.delete('/res78/:id', (c) => c.text('m1 r78')) +r1.patch('/res79/:id', (c) => c.text('m1 r79')) +r1.get('/res80/:id', (c) => c.text('m1 r80')) +r1.post('/res81/:id', (c) => c.text('m1 r81')) +r1.put('/res82/:id', (c) => c.text('m1 r82')) +r1.delete('/res83/:id', (c) => c.text('m1 r83')) +r1.patch('/res84/:id', (c) => c.text('m1 r84')) +r1.get('/res85/:id', (c) => c.text('m1 r85')) +r1.post('/res86/:id', (c) => c.text('m1 r86')) +r1.put('/res87/:id', (c) => c.text('m1 r87')) +r1.delete('/res88/:id', (c) => c.text('m1 r88')) +r1.patch('/res89/:id', (c) => c.text('m1 r89')) +r1.get('/res90/:id', (c) => c.text('m1 r90')) +r1.post('/res91/:id', (c) => c.text('m1 r91')) +r1.put('/res92/:id', (c) => c.text('m1 r92')) +r1.delete('/res93/:id', (c) => c.text('m1 r93')) +r1.patch('/res94/:id', (c) => c.text('m1 r94')) +r1.get('/res95/:id', (c) => c.text('m1 r95')) +r1.post('/res96/:id', (c) => c.text('m1 r96')) +r1.put('/res97/:id', (c) => c.text('m1 r97')) +r1.delete('/res98/:id', (c) => c.text('m1 r98')) +r1.patch('/res99/:id', (c) => c.text('m1 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod10.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod10.ts new file mode 100644 index 000000000..675db665a --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod10.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r10 = new Hono() +r10.get('/res0/:id', (c) => c.text('m10 r0')) +r10.post('/res1/:id', (c) => c.text('m10 r1')) +r10.put('/res2/:id', (c) => c.text('m10 r2')) +r10.delete('/res3/:id', (c) => c.text('m10 r3')) +r10.patch('/res4/:id', (c) => c.text('m10 r4')) +r10.get('/res5/:id', (c) => c.text('m10 r5')) +r10.post('/res6/:id', (c) => c.text('m10 r6')) +r10.put('/res7/:id', (c) => c.text('m10 r7')) +r10.delete('/res8/:id', (c) => c.text('m10 r8')) +r10.patch('/res9/:id', (c) => c.text('m10 r9')) +r10.get('/res10/:id', (c) => c.text('m10 r10')) +r10.post('/res11/:id', (c) => c.text('m10 r11')) +r10.put('/res12/:id', (c) => c.text('m10 r12')) +r10.delete('/res13/:id', (c) => c.text('m10 r13')) +r10.patch('/res14/:id', (c) => c.text('m10 r14')) +r10.get('/res15/:id', (c) => c.text('m10 r15')) +r10.post('/res16/:id', (c) => c.text('m10 r16')) +r10.put('/res17/:id', (c) => c.text('m10 r17')) +r10.delete('/res18/:id', (c) => c.text('m10 r18')) +r10.patch('/res19/:id', (c) => c.text('m10 r19')) +r10.get('/res20/:id', (c) => c.text('m10 r20')) +r10.post('/res21/:id', (c) => c.text('m10 r21')) +r10.put('/res22/:id', (c) => c.text('m10 r22')) +r10.delete('/res23/:id', (c) => c.text('m10 r23')) +r10.patch('/res24/:id', (c) => c.text('m10 r24')) +r10.get('/res25/:id', (c) => c.text('m10 r25')) +r10.post('/res26/:id', (c) => c.text('m10 r26')) +r10.put('/res27/:id', (c) => c.text('m10 r27')) +r10.delete('/res28/:id', (c) => c.text('m10 r28')) +r10.patch('/res29/:id', (c) => c.text('m10 r29')) +r10.get('/res30/:id', (c) => c.text('m10 r30')) +r10.post('/res31/:id', (c) => c.text('m10 r31')) +r10.put('/res32/:id', (c) => c.text('m10 r32')) +r10.delete('/res33/:id', (c) => c.text('m10 r33')) +r10.patch('/res34/:id', (c) => c.text('m10 r34')) +r10.get('/res35/:id', (c) => c.text('m10 r35')) +r10.post('/res36/:id', (c) => c.text('m10 r36')) +r10.put('/res37/:id', (c) => c.text('m10 r37')) +r10.delete('/res38/:id', (c) => c.text('m10 r38')) +r10.patch('/res39/:id', (c) => c.text('m10 r39')) +r10.get('/res40/:id', (c) => c.text('m10 r40')) +r10.post('/res41/:id', (c) => c.text('m10 r41')) +r10.put('/res42/:id', (c) => c.text('m10 r42')) +r10.delete('/res43/:id', (c) => c.text('m10 r43')) +r10.patch('/res44/:id', (c) => c.text('m10 r44')) +r10.get('/res45/:id', (c) => c.text('m10 r45')) +r10.post('/res46/:id', (c) => c.text('m10 r46')) +r10.put('/res47/:id', (c) => c.text('m10 r47')) +r10.delete('/res48/:id', (c) => c.text('m10 r48')) +r10.patch('/res49/:id', (c) => c.text('m10 r49')) +r10.get('/res50/:id', (c) => c.text('m10 r50')) +r10.post('/res51/:id', (c) => c.text('m10 r51')) +r10.put('/res52/:id', (c) => c.text('m10 r52')) +r10.delete('/res53/:id', (c) => c.text('m10 r53')) +r10.patch('/res54/:id', (c) => c.text('m10 r54')) +r10.get('/res55/:id', (c) => c.text('m10 r55')) +r10.post('/res56/:id', (c) => c.text('m10 r56')) +r10.put('/res57/:id', (c) => c.text('m10 r57')) +r10.delete('/res58/:id', (c) => c.text('m10 r58')) +r10.patch('/res59/:id', (c) => c.text('m10 r59')) +r10.get('/res60/:id', (c) => c.text('m10 r60')) +r10.post('/res61/:id', (c) => c.text('m10 r61')) +r10.put('/res62/:id', (c) => c.text('m10 r62')) +r10.delete('/res63/:id', (c) => c.text('m10 r63')) +r10.patch('/res64/:id', (c) => c.text('m10 r64')) +r10.get('/res65/:id', (c) => c.text('m10 r65')) +r10.post('/res66/:id', (c) => c.text('m10 r66')) +r10.put('/res67/:id', (c) => c.text('m10 r67')) +r10.delete('/res68/:id', (c) => c.text('m10 r68')) +r10.patch('/res69/:id', (c) => c.text('m10 r69')) +r10.get('/res70/:id', (c) => c.text('m10 r70')) +r10.post('/res71/:id', (c) => c.text('m10 r71')) +r10.put('/res72/:id', (c) => c.text('m10 r72')) +r10.delete('/res73/:id', (c) => c.text('m10 r73')) +r10.patch('/res74/:id', (c) => c.text('m10 r74')) +r10.get('/res75/:id', (c) => c.text('m10 r75')) +r10.post('/res76/:id', (c) => c.text('m10 r76')) +r10.put('/res77/:id', (c) => c.text('m10 r77')) +r10.delete('/res78/:id', (c) => c.text('m10 r78')) +r10.patch('/res79/:id', (c) => c.text('m10 r79')) +r10.get('/res80/:id', (c) => c.text('m10 r80')) +r10.post('/res81/:id', (c) => c.text('m10 r81')) +r10.put('/res82/:id', (c) => c.text('m10 r82')) +r10.delete('/res83/:id', (c) => c.text('m10 r83')) +r10.patch('/res84/:id', (c) => c.text('m10 r84')) +r10.get('/res85/:id', (c) => c.text('m10 r85')) +r10.post('/res86/:id', (c) => c.text('m10 r86')) +r10.put('/res87/:id', (c) => c.text('m10 r87')) +r10.delete('/res88/:id', (c) => c.text('m10 r88')) +r10.patch('/res89/:id', (c) => c.text('m10 r89')) +r10.get('/res90/:id', (c) => c.text('m10 r90')) +r10.post('/res91/:id', (c) => c.text('m10 r91')) +r10.put('/res92/:id', (c) => c.text('m10 r92')) +r10.delete('/res93/:id', (c) => c.text('m10 r93')) +r10.patch('/res94/:id', (c) => c.text('m10 r94')) +r10.get('/res95/:id', (c) => c.text('m10 r95')) +r10.post('/res96/:id', (c) => c.text('m10 r96')) +r10.put('/res97/:id', (c) => c.text('m10 r97')) +r10.delete('/res98/:id', (c) => c.text('m10 r98')) +r10.patch('/res99/:id', (c) => c.text('m10 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod11.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod11.ts new file mode 100644 index 000000000..54bd32283 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod11.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r11 = new Hono() +r11.get('/res0/:id', (c) => c.text('m11 r0')) +r11.post('/res1/:id', (c) => c.text('m11 r1')) +r11.put('/res2/:id', (c) => c.text('m11 r2')) +r11.delete('/res3/:id', (c) => c.text('m11 r3')) +r11.patch('/res4/:id', (c) => c.text('m11 r4')) +r11.get('/res5/:id', (c) => c.text('m11 r5')) +r11.post('/res6/:id', (c) => c.text('m11 r6')) +r11.put('/res7/:id', (c) => c.text('m11 r7')) +r11.delete('/res8/:id', (c) => c.text('m11 r8')) +r11.patch('/res9/:id', (c) => c.text('m11 r9')) +r11.get('/res10/:id', (c) => c.text('m11 r10')) +r11.post('/res11/:id', (c) => c.text('m11 r11')) +r11.put('/res12/:id', (c) => c.text('m11 r12')) +r11.delete('/res13/:id', (c) => c.text('m11 r13')) +r11.patch('/res14/:id', (c) => c.text('m11 r14')) +r11.get('/res15/:id', (c) => c.text('m11 r15')) +r11.post('/res16/:id', (c) => c.text('m11 r16')) +r11.put('/res17/:id', (c) => c.text('m11 r17')) +r11.delete('/res18/:id', (c) => c.text('m11 r18')) +r11.patch('/res19/:id', (c) => c.text('m11 r19')) +r11.get('/res20/:id', (c) => c.text('m11 r20')) +r11.post('/res21/:id', (c) => c.text('m11 r21')) +r11.put('/res22/:id', (c) => c.text('m11 r22')) +r11.delete('/res23/:id', (c) => c.text('m11 r23')) +r11.patch('/res24/:id', (c) => c.text('m11 r24')) +r11.get('/res25/:id', (c) => c.text('m11 r25')) +r11.post('/res26/:id', (c) => c.text('m11 r26')) +r11.put('/res27/:id', (c) => c.text('m11 r27')) +r11.delete('/res28/:id', (c) => c.text('m11 r28')) +r11.patch('/res29/:id', (c) => c.text('m11 r29')) +r11.get('/res30/:id', (c) => c.text('m11 r30')) +r11.post('/res31/:id', (c) => c.text('m11 r31')) +r11.put('/res32/:id', (c) => c.text('m11 r32')) +r11.delete('/res33/:id', (c) => c.text('m11 r33')) +r11.patch('/res34/:id', (c) => c.text('m11 r34')) +r11.get('/res35/:id', (c) => c.text('m11 r35')) +r11.post('/res36/:id', (c) => c.text('m11 r36')) +r11.put('/res37/:id', (c) => c.text('m11 r37')) +r11.delete('/res38/:id', (c) => c.text('m11 r38')) +r11.patch('/res39/:id', (c) => c.text('m11 r39')) +r11.get('/res40/:id', (c) => c.text('m11 r40')) +r11.post('/res41/:id', (c) => c.text('m11 r41')) +r11.put('/res42/:id', (c) => c.text('m11 r42')) +r11.delete('/res43/:id', (c) => c.text('m11 r43')) +r11.patch('/res44/:id', (c) => c.text('m11 r44')) +r11.get('/res45/:id', (c) => c.text('m11 r45')) +r11.post('/res46/:id', (c) => c.text('m11 r46')) +r11.put('/res47/:id', (c) => c.text('m11 r47')) +r11.delete('/res48/:id', (c) => c.text('m11 r48')) +r11.patch('/res49/:id', (c) => c.text('m11 r49')) +r11.get('/res50/:id', (c) => c.text('m11 r50')) +r11.post('/res51/:id', (c) => c.text('m11 r51')) +r11.put('/res52/:id', (c) => c.text('m11 r52')) +r11.delete('/res53/:id', (c) => c.text('m11 r53')) +r11.patch('/res54/:id', (c) => c.text('m11 r54')) +r11.get('/res55/:id', (c) => c.text('m11 r55')) +r11.post('/res56/:id', (c) => c.text('m11 r56')) +r11.put('/res57/:id', (c) => c.text('m11 r57')) +r11.delete('/res58/:id', (c) => c.text('m11 r58')) +r11.patch('/res59/:id', (c) => c.text('m11 r59')) +r11.get('/res60/:id', (c) => c.text('m11 r60')) +r11.post('/res61/:id', (c) => c.text('m11 r61')) +r11.put('/res62/:id', (c) => c.text('m11 r62')) +r11.delete('/res63/:id', (c) => c.text('m11 r63')) +r11.patch('/res64/:id', (c) => c.text('m11 r64')) +r11.get('/res65/:id', (c) => c.text('m11 r65')) +r11.post('/res66/:id', (c) => c.text('m11 r66')) +r11.put('/res67/:id', (c) => c.text('m11 r67')) +r11.delete('/res68/:id', (c) => c.text('m11 r68')) +r11.patch('/res69/:id', (c) => c.text('m11 r69')) +r11.get('/res70/:id', (c) => c.text('m11 r70')) +r11.post('/res71/:id', (c) => c.text('m11 r71')) +r11.put('/res72/:id', (c) => c.text('m11 r72')) +r11.delete('/res73/:id', (c) => c.text('m11 r73')) +r11.patch('/res74/:id', (c) => c.text('m11 r74')) +r11.get('/res75/:id', (c) => c.text('m11 r75')) +r11.post('/res76/:id', (c) => c.text('m11 r76')) +r11.put('/res77/:id', (c) => c.text('m11 r77')) +r11.delete('/res78/:id', (c) => c.text('m11 r78')) +r11.patch('/res79/:id', (c) => c.text('m11 r79')) +r11.get('/res80/:id', (c) => c.text('m11 r80')) +r11.post('/res81/:id', (c) => c.text('m11 r81')) +r11.put('/res82/:id', (c) => c.text('m11 r82')) +r11.delete('/res83/:id', (c) => c.text('m11 r83')) +r11.patch('/res84/:id', (c) => c.text('m11 r84')) +r11.get('/res85/:id', (c) => c.text('m11 r85')) +r11.post('/res86/:id', (c) => c.text('m11 r86')) +r11.put('/res87/:id', (c) => c.text('m11 r87')) +r11.delete('/res88/:id', (c) => c.text('m11 r88')) +r11.patch('/res89/:id', (c) => c.text('m11 r89')) +r11.get('/res90/:id', (c) => c.text('m11 r90')) +r11.post('/res91/:id', (c) => c.text('m11 r91')) +r11.put('/res92/:id', (c) => c.text('m11 r92')) +r11.delete('/res93/:id', (c) => c.text('m11 r93')) +r11.patch('/res94/:id', (c) => c.text('m11 r94')) +r11.get('/res95/:id', (c) => c.text('m11 r95')) +r11.post('/res96/:id', (c) => c.text('m11 r96')) +r11.put('/res97/:id', (c) => c.text('m11 r97')) +r11.delete('/res98/:id', (c) => c.text('m11 r98')) +r11.patch('/res99/:id', (c) => c.text('m11 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod12.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod12.ts new file mode 100644 index 000000000..f5abe1102 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod12.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r12 = new Hono() +r12.get('/res0/:id', (c) => c.text('m12 r0')) +r12.post('/res1/:id', (c) => c.text('m12 r1')) +r12.put('/res2/:id', (c) => c.text('m12 r2')) +r12.delete('/res3/:id', (c) => c.text('m12 r3')) +r12.patch('/res4/:id', (c) => c.text('m12 r4')) +r12.get('/res5/:id', (c) => c.text('m12 r5')) +r12.post('/res6/:id', (c) => c.text('m12 r6')) +r12.put('/res7/:id', (c) => c.text('m12 r7')) +r12.delete('/res8/:id', (c) => c.text('m12 r8')) +r12.patch('/res9/:id', (c) => c.text('m12 r9')) +r12.get('/res10/:id', (c) => c.text('m12 r10')) +r12.post('/res11/:id', (c) => c.text('m12 r11')) +r12.put('/res12/:id', (c) => c.text('m12 r12')) +r12.delete('/res13/:id', (c) => c.text('m12 r13')) +r12.patch('/res14/:id', (c) => c.text('m12 r14')) +r12.get('/res15/:id', (c) => c.text('m12 r15')) +r12.post('/res16/:id', (c) => c.text('m12 r16')) +r12.put('/res17/:id', (c) => c.text('m12 r17')) +r12.delete('/res18/:id', (c) => c.text('m12 r18')) +r12.patch('/res19/:id', (c) => c.text('m12 r19')) +r12.get('/res20/:id', (c) => c.text('m12 r20')) +r12.post('/res21/:id', (c) => c.text('m12 r21')) +r12.put('/res22/:id', (c) => c.text('m12 r22')) +r12.delete('/res23/:id', (c) => c.text('m12 r23')) +r12.patch('/res24/:id', (c) => c.text('m12 r24')) +r12.get('/res25/:id', (c) => c.text('m12 r25')) +r12.post('/res26/:id', (c) => c.text('m12 r26')) +r12.put('/res27/:id', (c) => c.text('m12 r27')) +r12.delete('/res28/:id', (c) => c.text('m12 r28')) +r12.patch('/res29/:id', (c) => c.text('m12 r29')) +r12.get('/res30/:id', (c) => c.text('m12 r30')) +r12.post('/res31/:id', (c) => c.text('m12 r31')) +r12.put('/res32/:id', (c) => c.text('m12 r32')) +r12.delete('/res33/:id', (c) => c.text('m12 r33')) +r12.patch('/res34/:id', (c) => c.text('m12 r34')) +r12.get('/res35/:id', (c) => c.text('m12 r35')) +r12.post('/res36/:id', (c) => c.text('m12 r36')) +r12.put('/res37/:id', (c) => c.text('m12 r37')) +r12.delete('/res38/:id', (c) => c.text('m12 r38')) +r12.patch('/res39/:id', (c) => c.text('m12 r39')) +r12.get('/res40/:id', (c) => c.text('m12 r40')) +r12.post('/res41/:id', (c) => c.text('m12 r41')) +r12.put('/res42/:id', (c) => c.text('m12 r42')) +r12.delete('/res43/:id', (c) => c.text('m12 r43')) +r12.patch('/res44/:id', (c) => c.text('m12 r44')) +r12.get('/res45/:id', (c) => c.text('m12 r45')) +r12.post('/res46/:id', (c) => c.text('m12 r46')) +r12.put('/res47/:id', (c) => c.text('m12 r47')) +r12.delete('/res48/:id', (c) => c.text('m12 r48')) +r12.patch('/res49/:id', (c) => c.text('m12 r49')) +r12.get('/res50/:id', (c) => c.text('m12 r50')) +r12.post('/res51/:id', (c) => c.text('m12 r51')) +r12.put('/res52/:id', (c) => c.text('m12 r52')) +r12.delete('/res53/:id', (c) => c.text('m12 r53')) +r12.patch('/res54/:id', (c) => c.text('m12 r54')) +r12.get('/res55/:id', (c) => c.text('m12 r55')) +r12.post('/res56/:id', (c) => c.text('m12 r56')) +r12.put('/res57/:id', (c) => c.text('m12 r57')) +r12.delete('/res58/:id', (c) => c.text('m12 r58')) +r12.patch('/res59/:id', (c) => c.text('m12 r59')) +r12.get('/res60/:id', (c) => c.text('m12 r60')) +r12.post('/res61/:id', (c) => c.text('m12 r61')) +r12.put('/res62/:id', (c) => c.text('m12 r62')) +r12.delete('/res63/:id', (c) => c.text('m12 r63')) +r12.patch('/res64/:id', (c) => c.text('m12 r64')) +r12.get('/res65/:id', (c) => c.text('m12 r65')) +r12.post('/res66/:id', (c) => c.text('m12 r66')) +r12.put('/res67/:id', (c) => c.text('m12 r67')) +r12.delete('/res68/:id', (c) => c.text('m12 r68')) +r12.patch('/res69/:id', (c) => c.text('m12 r69')) +r12.get('/res70/:id', (c) => c.text('m12 r70')) +r12.post('/res71/:id', (c) => c.text('m12 r71')) +r12.put('/res72/:id', (c) => c.text('m12 r72')) +r12.delete('/res73/:id', (c) => c.text('m12 r73')) +r12.patch('/res74/:id', (c) => c.text('m12 r74')) +r12.get('/res75/:id', (c) => c.text('m12 r75')) +r12.post('/res76/:id', (c) => c.text('m12 r76')) +r12.put('/res77/:id', (c) => c.text('m12 r77')) +r12.delete('/res78/:id', (c) => c.text('m12 r78')) +r12.patch('/res79/:id', (c) => c.text('m12 r79')) +r12.get('/res80/:id', (c) => c.text('m12 r80')) +r12.post('/res81/:id', (c) => c.text('m12 r81')) +r12.put('/res82/:id', (c) => c.text('m12 r82')) +r12.delete('/res83/:id', (c) => c.text('m12 r83')) +r12.patch('/res84/:id', (c) => c.text('m12 r84')) +r12.get('/res85/:id', (c) => c.text('m12 r85')) +r12.post('/res86/:id', (c) => c.text('m12 r86')) +r12.put('/res87/:id', (c) => c.text('m12 r87')) +r12.delete('/res88/:id', (c) => c.text('m12 r88')) +r12.patch('/res89/:id', (c) => c.text('m12 r89')) +r12.get('/res90/:id', (c) => c.text('m12 r90')) +r12.post('/res91/:id', (c) => c.text('m12 r91')) +r12.put('/res92/:id', (c) => c.text('m12 r92')) +r12.delete('/res93/:id', (c) => c.text('m12 r93')) +r12.patch('/res94/:id', (c) => c.text('m12 r94')) +r12.get('/res95/:id', (c) => c.text('m12 r95')) +r12.post('/res96/:id', (c) => c.text('m12 r96')) +r12.put('/res97/:id', (c) => c.text('m12 r97')) +r12.delete('/res98/:id', (c) => c.text('m12 r98')) +r12.patch('/res99/:id', (c) => c.text('m12 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod13.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod13.ts new file mode 100644 index 000000000..b208542f7 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod13.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r13 = new Hono() +r13.get('/res0/:id', (c) => c.text('m13 r0')) +r13.post('/res1/:id', (c) => c.text('m13 r1')) +r13.put('/res2/:id', (c) => c.text('m13 r2')) +r13.delete('/res3/:id', (c) => c.text('m13 r3')) +r13.patch('/res4/:id', (c) => c.text('m13 r4')) +r13.get('/res5/:id', (c) => c.text('m13 r5')) +r13.post('/res6/:id', (c) => c.text('m13 r6')) +r13.put('/res7/:id', (c) => c.text('m13 r7')) +r13.delete('/res8/:id', (c) => c.text('m13 r8')) +r13.patch('/res9/:id', (c) => c.text('m13 r9')) +r13.get('/res10/:id', (c) => c.text('m13 r10')) +r13.post('/res11/:id', (c) => c.text('m13 r11')) +r13.put('/res12/:id', (c) => c.text('m13 r12')) +r13.delete('/res13/:id', (c) => c.text('m13 r13')) +r13.patch('/res14/:id', (c) => c.text('m13 r14')) +r13.get('/res15/:id', (c) => c.text('m13 r15')) +r13.post('/res16/:id', (c) => c.text('m13 r16')) +r13.put('/res17/:id', (c) => c.text('m13 r17')) +r13.delete('/res18/:id', (c) => c.text('m13 r18')) +r13.patch('/res19/:id', (c) => c.text('m13 r19')) +r13.get('/res20/:id', (c) => c.text('m13 r20')) +r13.post('/res21/:id', (c) => c.text('m13 r21')) +r13.put('/res22/:id', (c) => c.text('m13 r22')) +r13.delete('/res23/:id', (c) => c.text('m13 r23')) +r13.patch('/res24/:id', (c) => c.text('m13 r24')) +r13.get('/res25/:id', (c) => c.text('m13 r25')) +r13.post('/res26/:id', (c) => c.text('m13 r26')) +r13.put('/res27/:id', (c) => c.text('m13 r27')) +r13.delete('/res28/:id', (c) => c.text('m13 r28')) +r13.patch('/res29/:id', (c) => c.text('m13 r29')) +r13.get('/res30/:id', (c) => c.text('m13 r30')) +r13.post('/res31/:id', (c) => c.text('m13 r31')) +r13.put('/res32/:id', (c) => c.text('m13 r32')) +r13.delete('/res33/:id', (c) => c.text('m13 r33')) +r13.patch('/res34/:id', (c) => c.text('m13 r34')) +r13.get('/res35/:id', (c) => c.text('m13 r35')) +r13.post('/res36/:id', (c) => c.text('m13 r36')) +r13.put('/res37/:id', (c) => c.text('m13 r37')) +r13.delete('/res38/:id', (c) => c.text('m13 r38')) +r13.patch('/res39/:id', (c) => c.text('m13 r39')) +r13.get('/res40/:id', (c) => c.text('m13 r40')) +r13.post('/res41/:id', (c) => c.text('m13 r41')) +r13.put('/res42/:id', (c) => c.text('m13 r42')) +r13.delete('/res43/:id', (c) => c.text('m13 r43')) +r13.patch('/res44/:id', (c) => c.text('m13 r44')) +r13.get('/res45/:id', (c) => c.text('m13 r45')) +r13.post('/res46/:id', (c) => c.text('m13 r46')) +r13.put('/res47/:id', (c) => c.text('m13 r47')) +r13.delete('/res48/:id', (c) => c.text('m13 r48')) +r13.patch('/res49/:id', (c) => c.text('m13 r49')) +r13.get('/res50/:id', (c) => c.text('m13 r50')) +r13.post('/res51/:id', (c) => c.text('m13 r51')) +r13.put('/res52/:id', (c) => c.text('m13 r52')) +r13.delete('/res53/:id', (c) => c.text('m13 r53')) +r13.patch('/res54/:id', (c) => c.text('m13 r54')) +r13.get('/res55/:id', (c) => c.text('m13 r55')) +r13.post('/res56/:id', (c) => c.text('m13 r56')) +r13.put('/res57/:id', (c) => c.text('m13 r57')) +r13.delete('/res58/:id', (c) => c.text('m13 r58')) +r13.patch('/res59/:id', (c) => c.text('m13 r59')) +r13.get('/res60/:id', (c) => c.text('m13 r60')) +r13.post('/res61/:id', (c) => c.text('m13 r61')) +r13.put('/res62/:id', (c) => c.text('m13 r62')) +r13.delete('/res63/:id', (c) => c.text('m13 r63')) +r13.patch('/res64/:id', (c) => c.text('m13 r64')) +r13.get('/res65/:id', (c) => c.text('m13 r65')) +r13.post('/res66/:id', (c) => c.text('m13 r66')) +r13.put('/res67/:id', (c) => c.text('m13 r67')) +r13.delete('/res68/:id', (c) => c.text('m13 r68')) +r13.patch('/res69/:id', (c) => c.text('m13 r69')) +r13.get('/res70/:id', (c) => c.text('m13 r70')) +r13.post('/res71/:id', (c) => c.text('m13 r71')) +r13.put('/res72/:id', (c) => c.text('m13 r72')) +r13.delete('/res73/:id', (c) => c.text('m13 r73')) +r13.patch('/res74/:id', (c) => c.text('m13 r74')) +r13.get('/res75/:id', (c) => c.text('m13 r75')) +r13.post('/res76/:id', (c) => c.text('m13 r76')) +r13.put('/res77/:id', (c) => c.text('m13 r77')) +r13.delete('/res78/:id', (c) => c.text('m13 r78')) +r13.patch('/res79/:id', (c) => c.text('m13 r79')) +r13.get('/res80/:id', (c) => c.text('m13 r80')) +r13.post('/res81/:id', (c) => c.text('m13 r81')) +r13.put('/res82/:id', (c) => c.text('m13 r82')) +r13.delete('/res83/:id', (c) => c.text('m13 r83')) +r13.patch('/res84/:id', (c) => c.text('m13 r84')) +r13.get('/res85/:id', (c) => c.text('m13 r85')) +r13.post('/res86/:id', (c) => c.text('m13 r86')) +r13.put('/res87/:id', (c) => c.text('m13 r87')) +r13.delete('/res88/:id', (c) => c.text('m13 r88')) +r13.patch('/res89/:id', (c) => c.text('m13 r89')) +r13.get('/res90/:id', (c) => c.text('m13 r90')) +r13.post('/res91/:id', (c) => c.text('m13 r91')) +r13.put('/res92/:id', (c) => c.text('m13 r92')) +r13.delete('/res93/:id', (c) => c.text('m13 r93')) +r13.patch('/res94/:id', (c) => c.text('m13 r94')) +r13.get('/res95/:id', (c) => c.text('m13 r95')) +r13.post('/res96/:id', (c) => c.text('m13 r96')) +r13.put('/res97/:id', (c) => c.text('m13 r97')) +r13.delete('/res98/:id', (c) => c.text('m13 r98')) +r13.patch('/res99/:id', (c) => c.text('m13 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod14.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod14.ts new file mode 100644 index 000000000..234c69bfd --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod14.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r14 = new Hono() +r14.get('/res0/:id', (c) => c.text('m14 r0')) +r14.post('/res1/:id', (c) => c.text('m14 r1')) +r14.put('/res2/:id', (c) => c.text('m14 r2')) +r14.delete('/res3/:id', (c) => c.text('m14 r3')) +r14.patch('/res4/:id', (c) => c.text('m14 r4')) +r14.get('/res5/:id', (c) => c.text('m14 r5')) +r14.post('/res6/:id', (c) => c.text('m14 r6')) +r14.put('/res7/:id', (c) => c.text('m14 r7')) +r14.delete('/res8/:id', (c) => c.text('m14 r8')) +r14.patch('/res9/:id', (c) => c.text('m14 r9')) +r14.get('/res10/:id', (c) => c.text('m14 r10')) +r14.post('/res11/:id', (c) => c.text('m14 r11')) +r14.put('/res12/:id', (c) => c.text('m14 r12')) +r14.delete('/res13/:id', (c) => c.text('m14 r13')) +r14.patch('/res14/:id', (c) => c.text('m14 r14')) +r14.get('/res15/:id', (c) => c.text('m14 r15')) +r14.post('/res16/:id', (c) => c.text('m14 r16')) +r14.put('/res17/:id', (c) => c.text('m14 r17')) +r14.delete('/res18/:id', (c) => c.text('m14 r18')) +r14.patch('/res19/:id', (c) => c.text('m14 r19')) +r14.get('/res20/:id', (c) => c.text('m14 r20')) +r14.post('/res21/:id', (c) => c.text('m14 r21')) +r14.put('/res22/:id', (c) => c.text('m14 r22')) +r14.delete('/res23/:id', (c) => c.text('m14 r23')) +r14.patch('/res24/:id', (c) => c.text('m14 r24')) +r14.get('/res25/:id', (c) => c.text('m14 r25')) +r14.post('/res26/:id', (c) => c.text('m14 r26')) +r14.put('/res27/:id', (c) => c.text('m14 r27')) +r14.delete('/res28/:id', (c) => c.text('m14 r28')) +r14.patch('/res29/:id', (c) => c.text('m14 r29')) +r14.get('/res30/:id', (c) => c.text('m14 r30')) +r14.post('/res31/:id', (c) => c.text('m14 r31')) +r14.put('/res32/:id', (c) => c.text('m14 r32')) +r14.delete('/res33/:id', (c) => c.text('m14 r33')) +r14.patch('/res34/:id', (c) => c.text('m14 r34')) +r14.get('/res35/:id', (c) => c.text('m14 r35')) +r14.post('/res36/:id', (c) => c.text('m14 r36')) +r14.put('/res37/:id', (c) => c.text('m14 r37')) +r14.delete('/res38/:id', (c) => c.text('m14 r38')) +r14.patch('/res39/:id', (c) => c.text('m14 r39')) +r14.get('/res40/:id', (c) => c.text('m14 r40')) +r14.post('/res41/:id', (c) => c.text('m14 r41')) +r14.put('/res42/:id', (c) => c.text('m14 r42')) +r14.delete('/res43/:id', (c) => c.text('m14 r43')) +r14.patch('/res44/:id', (c) => c.text('m14 r44')) +r14.get('/res45/:id', (c) => c.text('m14 r45')) +r14.post('/res46/:id', (c) => c.text('m14 r46')) +r14.put('/res47/:id', (c) => c.text('m14 r47')) +r14.delete('/res48/:id', (c) => c.text('m14 r48')) +r14.patch('/res49/:id', (c) => c.text('m14 r49')) +r14.get('/res50/:id', (c) => c.text('m14 r50')) +r14.post('/res51/:id', (c) => c.text('m14 r51')) +r14.put('/res52/:id', (c) => c.text('m14 r52')) +r14.delete('/res53/:id', (c) => c.text('m14 r53')) +r14.patch('/res54/:id', (c) => c.text('m14 r54')) +r14.get('/res55/:id', (c) => c.text('m14 r55')) +r14.post('/res56/:id', (c) => c.text('m14 r56')) +r14.put('/res57/:id', (c) => c.text('m14 r57')) +r14.delete('/res58/:id', (c) => c.text('m14 r58')) +r14.patch('/res59/:id', (c) => c.text('m14 r59')) +r14.get('/res60/:id', (c) => c.text('m14 r60')) +r14.post('/res61/:id', (c) => c.text('m14 r61')) +r14.put('/res62/:id', (c) => c.text('m14 r62')) +r14.delete('/res63/:id', (c) => c.text('m14 r63')) +r14.patch('/res64/:id', (c) => c.text('m14 r64')) +r14.get('/res65/:id', (c) => c.text('m14 r65')) +r14.post('/res66/:id', (c) => c.text('m14 r66')) +r14.put('/res67/:id', (c) => c.text('m14 r67')) +r14.delete('/res68/:id', (c) => c.text('m14 r68')) +r14.patch('/res69/:id', (c) => c.text('m14 r69')) +r14.get('/res70/:id', (c) => c.text('m14 r70')) +r14.post('/res71/:id', (c) => c.text('m14 r71')) +r14.put('/res72/:id', (c) => c.text('m14 r72')) +r14.delete('/res73/:id', (c) => c.text('m14 r73')) +r14.patch('/res74/:id', (c) => c.text('m14 r74')) +r14.get('/res75/:id', (c) => c.text('m14 r75')) +r14.post('/res76/:id', (c) => c.text('m14 r76')) +r14.put('/res77/:id', (c) => c.text('m14 r77')) +r14.delete('/res78/:id', (c) => c.text('m14 r78')) +r14.patch('/res79/:id', (c) => c.text('m14 r79')) +r14.get('/res80/:id', (c) => c.text('m14 r80')) +r14.post('/res81/:id', (c) => c.text('m14 r81')) +r14.put('/res82/:id', (c) => c.text('m14 r82')) +r14.delete('/res83/:id', (c) => c.text('m14 r83')) +r14.patch('/res84/:id', (c) => c.text('m14 r84')) +r14.get('/res85/:id', (c) => c.text('m14 r85')) +r14.post('/res86/:id', (c) => c.text('m14 r86')) +r14.put('/res87/:id', (c) => c.text('m14 r87')) +r14.delete('/res88/:id', (c) => c.text('m14 r88')) +r14.patch('/res89/:id', (c) => c.text('m14 r89')) +r14.get('/res90/:id', (c) => c.text('m14 r90')) +r14.post('/res91/:id', (c) => c.text('m14 r91')) +r14.put('/res92/:id', (c) => c.text('m14 r92')) +r14.delete('/res93/:id', (c) => c.text('m14 r93')) +r14.patch('/res94/:id', (c) => c.text('m14 r94')) +r14.get('/res95/:id', (c) => c.text('m14 r95')) +r14.post('/res96/:id', (c) => c.text('m14 r96')) +r14.put('/res97/:id', (c) => c.text('m14 r97')) +r14.delete('/res98/:id', (c) => c.text('m14 r98')) +r14.patch('/res99/:id', (c) => c.text('m14 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod15.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod15.ts new file mode 100644 index 000000000..57475d2a5 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod15.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r15 = new Hono() +r15.get('/res0/:id', (c) => c.text('m15 r0')) +r15.post('/res1/:id', (c) => c.text('m15 r1')) +r15.put('/res2/:id', (c) => c.text('m15 r2')) +r15.delete('/res3/:id', (c) => c.text('m15 r3')) +r15.patch('/res4/:id', (c) => c.text('m15 r4')) +r15.get('/res5/:id', (c) => c.text('m15 r5')) +r15.post('/res6/:id', (c) => c.text('m15 r6')) +r15.put('/res7/:id', (c) => c.text('m15 r7')) +r15.delete('/res8/:id', (c) => c.text('m15 r8')) +r15.patch('/res9/:id', (c) => c.text('m15 r9')) +r15.get('/res10/:id', (c) => c.text('m15 r10')) +r15.post('/res11/:id', (c) => c.text('m15 r11')) +r15.put('/res12/:id', (c) => c.text('m15 r12')) +r15.delete('/res13/:id', (c) => c.text('m15 r13')) +r15.patch('/res14/:id', (c) => c.text('m15 r14')) +r15.get('/res15/:id', (c) => c.text('m15 r15')) +r15.post('/res16/:id', (c) => c.text('m15 r16')) +r15.put('/res17/:id', (c) => c.text('m15 r17')) +r15.delete('/res18/:id', (c) => c.text('m15 r18')) +r15.patch('/res19/:id', (c) => c.text('m15 r19')) +r15.get('/res20/:id', (c) => c.text('m15 r20')) +r15.post('/res21/:id', (c) => c.text('m15 r21')) +r15.put('/res22/:id', (c) => c.text('m15 r22')) +r15.delete('/res23/:id', (c) => c.text('m15 r23')) +r15.patch('/res24/:id', (c) => c.text('m15 r24')) +r15.get('/res25/:id', (c) => c.text('m15 r25')) +r15.post('/res26/:id', (c) => c.text('m15 r26')) +r15.put('/res27/:id', (c) => c.text('m15 r27')) +r15.delete('/res28/:id', (c) => c.text('m15 r28')) +r15.patch('/res29/:id', (c) => c.text('m15 r29')) +r15.get('/res30/:id', (c) => c.text('m15 r30')) +r15.post('/res31/:id', (c) => c.text('m15 r31')) +r15.put('/res32/:id', (c) => c.text('m15 r32')) +r15.delete('/res33/:id', (c) => c.text('m15 r33')) +r15.patch('/res34/:id', (c) => c.text('m15 r34')) +r15.get('/res35/:id', (c) => c.text('m15 r35')) +r15.post('/res36/:id', (c) => c.text('m15 r36')) +r15.put('/res37/:id', (c) => c.text('m15 r37')) +r15.delete('/res38/:id', (c) => c.text('m15 r38')) +r15.patch('/res39/:id', (c) => c.text('m15 r39')) +r15.get('/res40/:id', (c) => c.text('m15 r40')) +r15.post('/res41/:id', (c) => c.text('m15 r41')) +r15.put('/res42/:id', (c) => c.text('m15 r42')) +r15.delete('/res43/:id', (c) => c.text('m15 r43')) +r15.patch('/res44/:id', (c) => c.text('m15 r44')) +r15.get('/res45/:id', (c) => c.text('m15 r45')) +r15.post('/res46/:id', (c) => c.text('m15 r46')) +r15.put('/res47/:id', (c) => c.text('m15 r47')) +r15.delete('/res48/:id', (c) => c.text('m15 r48')) +r15.patch('/res49/:id', (c) => c.text('m15 r49')) +r15.get('/res50/:id', (c) => c.text('m15 r50')) +r15.post('/res51/:id', (c) => c.text('m15 r51')) +r15.put('/res52/:id', (c) => c.text('m15 r52')) +r15.delete('/res53/:id', (c) => c.text('m15 r53')) +r15.patch('/res54/:id', (c) => c.text('m15 r54')) +r15.get('/res55/:id', (c) => c.text('m15 r55')) +r15.post('/res56/:id', (c) => c.text('m15 r56')) +r15.put('/res57/:id', (c) => c.text('m15 r57')) +r15.delete('/res58/:id', (c) => c.text('m15 r58')) +r15.patch('/res59/:id', (c) => c.text('m15 r59')) +r15.get('/res60/:id', (c) => c.text('m15 r60')) +r15.post('/res61/:id', (c) => c.text('m15 r61')) +r15.put('/res62/:id', (c) => c.text('m15 r62')) +r15.delete('/res63/:id', (c) => c.text('m15 r63')) +r15.patch('/res64/:id', (c) => c.text('m15 r64')) +r15.get('/res65/:id', (c) => c.text('m15 r65')) +r15.post('/res66/:id', (c) => c.text('m15 r66')) +r15.put('/res67/:id', (c) => c.text('m15 r67')) +r15.delete('/res68/:id', (c) => c.text('m15 r68')) +r15.patch('/res69/:id', (c) => c.text('m15 r69')) +r15.get('/res70/:id', (c) => c.text('m15 r70')) +r15.post('/res71/:id', (c) => c.text('m15 r71')) +r15.put('/res72/:id', (c) => c.text('m15 r72')) +r15.delete('/res73/:id', (c) => c.text('m15 r73')) +r15.patch('/res74/:id', (c) => c.text('m15 r74')) +r15.get('/res75/:id', (c) => c.text('m15 r75')) +r15.post('/res76/:id', (c) => c.text('m15 r76')) +r15.put('/res77/:id', (c) => c.text('m15 r77')) +r15.delete('/res78/:id', (c) => c.text('m15 r78')) +r15.patch('/res79/:id', (c) => c.text('m15 r79')) +r15.get('/res80/:id', (c) => c.text('m15 r80')) +r15.post('/res81/:id', (c) => c.text('m15 r81')) +r15.put('/res82/:id', (c) => c.text('m15 r82')) +r15.delete('/res83/:id', (c) => c.text('m15 r83')) +r15.patch('/res84/:id', (c) => c.text('m15 r84')) +r15.get('/res85/:id', (c) => c.text('m15 r85')) +r15.post('/res86/:id', (c) => c.text('m15 r86')) +r15.put('/res87/:id', (c) => c.text('m15 r87')) +r15.delete('/res88/:id', (c) => c.text('m15 r88')) +r15.patch('/res89/:id', (c) => c.text('m15 r89')) +r15.get('/res90/:id', (c) => c.text('m15 r90')) +r15.post('/res91/:id', (c) => c.text('m15 r91')) +r15.put('/res92/:id', (c) => c.text('m15 r92')) +r15.delete('/res93/:id', (c) => c.text('m15 r93')) +r15.patch('/res94/:id', (c) => c.text('m15 r94')) +r15.get('/res95/:id', (c) => c.text('m15 r95')) +r15.post('/res96/:id', (c) => c.text('m15 r96')) +r15.put('/res97/:id', (c) => c.text('m15 r97')) +r15.delete('/res98/:id', (c) => c.text('m15 r98')) +r15.patch('/res99/:id', (c) => c.text('m15 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod16.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod16.ts new file mode 100644 index 000000000..a3d03cbe5 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod16.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r16 = new Hono() +r16.get('/res0/:id', (c) => c.text('m16 r0')) +r16.post('/res1/:id', (c) => c.text('m16 r1')) +r16.put('/res2/:id', (c) => c.text('m16 r2')) +r16.delete('/res3/:id', (c) => c.text('m16 r3')) +r16.patch('/res4/:id', (c) => c.text('m16 r4')) +r16.get('/res5/:id', (c) => c.text('m16 r5')) +r16.post('/res6/:id', (c) => c.text('m16 r6')) +r16.put('/res7/:id', (c) => c.text('m16 r7')) +r16.delete('/res8/:id', (c) => c.text('m16 r8')) +r16.patch('/res9/:id', (c) => c.text('m16 r9')) +r16.get('/res10/:id', (c) => c.text('m16 r10')) +r16.post('/res11/:id', (c) => c.text('m16 r11')) +r16.put('/res12/:id', (c) => c.text('m16 r12')) +r16.delete('/res13/:id', (c) => c.text('m16 r13')) +r16.patch('/res14/:id', (c) => c.text('m16 r14')) +r16.get('/res15/:id', (c) => c.text('m16 r15')) +r16.post('/res16/:id', (c) => c.text('m16 r16')) +r16.put('/res17/:id', (c) => c.text('m16 r17')) +r16.delete('/res18/:id', (c) => c.text('m16 r18')) +r16.patch('/res19/:id', (c) => c.text('m16 r19')) +r16.get('/res20/:id', (c) => c.text('m16 r20')) +r16.post('/res21/:id', (c) => c.text('m16 r21')) +r16.put('/res22/:id', (c) => c.text('m16 r22')) +r16.delete('/res23/:id', (c) => c.text('m16 r23')) +r16.patch('/res24/:id', (c) => c.text('m16 r24')) +r16.get('/res25/:id', (c) => c.text('m16 r25')) +r16.post('/res26/:id', (c) => c.text('m16 r26')) +r16.put('/res27/:id', (c) => c.text('m16 r27')) +r16.delete('/res28/:id', (c) => c.text('m16 r28')) +r16.patch('/res29/:id', (c) => c.text('m16 r29')) +r16.get('/res30/:id', (c) => c.text('m16 r30')) +r16.post('/res31/:id', (c) => c.text('m16 r31')) +r16.put('/res32/:id', (c) => c.text('m16 r32')) +r16.delete('/res33/:id', (c) => c.text('m16 r33')) +r16.patch('/res34/:id', (c) => c.text('m16 r34')) +r16.get('/res35/:id', (c) => c.text('m16 r35')) +r16.post('/res36/:id', (c) => c.text('m16 r36')) +r16.put('/res37/:id', (c) => c.text('m16 r37')) +r16.delete('/res38/:id', (c) => c.text('m16 r38')) +r16.patch('/res39/:id', (c) => c.text('m16 r39')) +r16.get('/res40/:id', (c) => c.text('m16 r40')) +r16.post('/res41/:id', (c) => c.text('m16 r41')) +r16.put('/res42/:id', (c) => c.text('m16 r42')) +r16.delete('/res43/:id', (c) => c.text('m16 r43')) +r16.patch('/res44/:id', (c) => c.text('m16 r44')) +r16.get('/res45/:id', (c) => c.text('m16 r45')) +r16.post('/res46/:id', (c) => c.text('m16 r46')) +r16.put('/res47/:id', (c) => c.text('m16 r47')) +r16.delete('/res48/:id', (c) => c.text('m16 r48')) +r16.patch('/res49/:id', (c) => c.text('m16 r49')) +r16.get('/res50/:id', (c) => c.text('m16 r50')) +r16.post('/res51/:id', (c) => c.text('m16 r51')) +r16.put('/res52/:id', (c) => c.text('m16 r52')) +r16.delete('/res53/:id', (c) => c.text('m16 r53')) +r16.patch('/res54/:id', (c) => c.text('m16 r54')) +r16.get('/res55/:id', (c) => c.text('m16 r55')) +r16.post('/res56/:id', (c) => c.text('m16 r56')) +r16.put('/res57/:id', (c) => c.text('m16 r57')) +r16.delete('/res58/:id', (c) => c.text('m16 r58')) +r16.patch('/res59/:id', (c) => c.text('m16 r59')) +r16.get('/res60/:id', (c) => c.text('m16 r60')) +r16.post('/res61/:id', (c) => c.text('m16 r61')) +r16.put('/res62/:id', (c) => c.text('m16 r62')) +r16.delete('/res63/:id', (c) => c.text('m16 r63')) +r16.patch('/res64/:id', (c) => c.text('m16 r64')) +r16.get('/res65/:id', (c) => c.text('m16 r65')) +r16.post('/res66/:id', (c) => c.text('m16 r66')) +r16.put('/res67/:id', (c) => c.text('m16 r67')) +r16.delete('/res68/:id', (c) => c.text('m16 r68')) +r16.patch('/res69/:id', (c) => c.text('m16 r69')) +r16.get('/res70/:id', (c) => c.text('m16 r70')) +r16.post('/res71/:id', (c) => c.text('m16 r71')) +r16.put('/res72/:id', (c) => c.text('m16 r72')) +r16.delete('/res73/:id', (c) => c.text('m16 r73')) +r16.patch('/res74/:id', (c) => c.text('m16 r74')) +r16.get('/res75/:id', (c) => c.text('m16 r75')) +r16.post('/res76/:id', (c) => c.text('m16 r76')) +r16.put('/res77/:id', (c) => c.text('m16 r77')) +r16.delete('/res78/:id', (c) => c.text('m16 r78')) +r16.patch('/res79/:id', (c) => c.text('m16 r79')) +r16.get('/res80/:id', (c) => c.text('m16 r80')) +r16.post('/res81/:id', (c) => c.text('m16 r81')) +r16.put('/res82/:id', (c) => c.text('m16 r82')) +r16.delete('/res83/:id', (c) => c.text('m16 r83')) +r16.patch('/res84/:id', (c) => c.text('m16 r84')) +r16.get('/res85/:id', (c) => c.text('m16 r85')) +r16.post('/res86/:id', (c) => c.text('m16 r86')) +r16.put('/res87/:id', (c) => c.text('m16 r87')) +r16.delete('/res88/:id', (c) => c.text('m16 r88')) +r16.patch('/res89/:id', (c) => c.text('m16 r89')) +r16.get('/res90/:id', (c) => c.text('m16 r90')) +r16.post('/res91/:id', (c) => c.text('m16 r91')) +r16.put('/res92/:id', (c) => c.text('m16 r92')) +r16.delete('/res93/:id', (c) => c.text('m16 r93')) +r16.patch('/res94/:id', (c) => c.text('m16 r94')) +r16.get('/res95/:id', (c) => c.text('m16 r95')) +r16.post('/res96/:id', (c) => c.text('m16 r96')) +r16.put('/res97/:id', (c) => c.text('m16 r97')) +r16.delete('/res98/:id', (c) => c.text('m16 r98')) +r16.patch('/res99/:id', (c) => c.text('m16 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod17.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod17.ts new file mode 100644 index 000000000..0925b07ca --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod17.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r17 = new Hono() +r17.get('/res0/:id', (c) => c.text('m17 r0')) +r17.post('/res1/:id', (c) => c.text('m17 r1')) +r17.put('/res2/:id', (c) => c.text('m17 r2')) +r17.delete('/res3/:id', (c) => c.text('m17 r3')) +r17.patch('/res4/:id', (c) => c.text('m17 r4')) +r17.get('/res5/:id', (c) => c.text('m17 r5')) +r17.post('/res6/:id', (c) => c.text('m17 r6')) +r17.put('/res7/:id', (c) => c.text('m17 r7')) +r17.delete('/res8/:id', (c) => c.text('m17 r8')) +r17.patch('/res9/:id', (c) => c.text('m17 r9')) +r17.get('/res10/:id', (c) => c.text('m17 r10')) +r17.post('/res11/:id', (c) => c.text('m17 r11')) +r17.put('/res12/:id', (c) => c.text('m17 r12')) +r17.delete('/res13/:id', (c) => c.text('m17 r13')) +r17.patch('/res14/:id', (c) => c.text('m17 r14')) +r17.get('/res15/:id', (c) => c.text('m17 r15')) +r17.post('/res16/:id', (c) => c.text('m17 r16')) +r17.put('/res17/:id', (c) => c.text('m17 r17')) +r17.delete('/res18/:id', (c) => c.text('m17 r18')) +r17.patch('/res19/:id', (c) => c.text('m17 r19')) +r17.get('/res20/:id', (c) => c.text('m17 r20')) +r17.post('/res21/:id', (c) => c.text('m17 r21')) +r17.put('/res22/:id', (c) => c.text('m17 r22')) +r17.delete('/res23/:id', (c) => c.text('m17 r23')) +r17.patch('/res24/:id', (c) => c.text('m17 r24')) +r17.get('/res25/:id', (c) => c.text('m17 r25')) +r17.post('/res26/:id', (c) => c.text('m17 r26')) +r17.put('/res27/:id', (c) => c.text('m17 r27')) +r17.delete('/res28/:id', (c) => c.text('m17 r28')) +r17.patch('/res29/:id', (c) => c.text('m17 r29')) +r17.get('/res30/:id', (c) => c.text('m17 r30')) +r17.post('/res31/:id', (c) => c.text('m17 r31')) +r17.put('/res32/:id', (c) => c.text('m17 r32')) +r17.delete('/res33/:id', (c) => c.text('m17 r33')) +r17.patch('/res34/:id', (c) => c.text('m17 r34')) +r17.get('/res35/:id', (c) => c.text('m17 r35')) +r17.post('/res36/:id', (c) => c.text('m17 r36')) +r17.put('/res37/:id', (c) => c.text('m17 r37')) +r17.delete('/res38/:id', (c) => c.text('m17 r38')) +r17.patch('/res39/:id', (c) => c.text('m17 r39')) +r17.get('/res40/:id', (c) => c.text('m17 r40')) +r17.post('/res41/:id', (c) => c.text('m17 r41')) +r17.put('/res42/:id', (c) => c.text('m17 r42')) +r17.delete('/res43/:id', (c) => c.text('m17 r43')) +r17.patch('/res44/:id', (c) => c.text('m17 r44')) +r17.get('/res45/:id', (c) => c.text('m17 r45')) +r17.post('/res46/:id', (c) => c.text('m17 r46')) +r17.put('/res47/:id', (c) => c.text('m17 r47')) +r17.delete('/res48/:id', (c) => c.text('m17 r48')) +r17.patch('/res49/:id', (c) => c.text('m17 r49')) +r17.get('/res50/:id', (c) => c.text('m17 r50')) +r17.post('/res51/:id', (c) => c.text('m17 r51')) +r17.put('/res52/:id', (c) => c.text('m17 r52')) +r17.delete('/res53/:id', (c) => c.text('m17 r53')) +r17.patch('/res54/:id', (c) => c.text('m17 r54')) +r17.get('/res55/:id', (c) => c.text('m17 r55')) +r17.post('/res56/:id', (c) => c.text('m17 r56')) +r17.put('/res57/:id', (c) => c.text('m17 r57')) +r17.delete('/res58/:id', (c) => c.text('m17 r58')) +r17.patch('/res59/:id', (c) => c.text('m17 r59')) +r17.get('/res60/:id', (c) => c.text('m17 r60')) +r17.post('/res61/:id', (c) => c.text('m17 r61')) +r17.put('/res62/:id', (c) => c.text('m17 r62')) +r17.delete('/res63/:id', (c) => c.text('m17 r63')) +r17.patch('/res64/:id', (c) => c.text('m17 r64')) +r17.get('/res65/:id', (c) => c.text('m17 r65')) +r17.post('/res66/:id', (c) => c.text('m17 r66')) +r17.put('/res67/:id', (c) => c.text('m17 r67')) +r17.delete('/res68/:id', (c) => c.text('m17 r68')) +r17.patch('/res69/:id', (c) => c.text('m17 r69')) +r17.get('/res70/:id', (c) => c.text('m17 r70')) +r17.post('/res71/:id', (c) => c.text('m17 r71')) +r17.put('/res72/:id', (c) => c.text('m17 r72')) +r17.delete('/res73/:id', (c) => c.text('m17 r73')) +r17.patch('/res74/:id', (c) => c.text('m17 r74')) +r17.get('/res75/:id', (c) => c.text('m17 r75')) +r17.post('/res76/:id', (c) => c.text('m17 r76')) +r17.put('/res77/:id', (c) => c.text('m17 r77')) +r17.delete('/res78/:id', (c) => c.text('m17 r78')) +r17.patch('/res79/:id', (c) => c.text('m17 r79')) +r17.get('/res80/:id', (c) => c.text('m17 r80')) +r17.post('/res81/:id', (c) => c.text('m17 r81')) +r17.put('/res82/:id', (c) => c.text('m17 r82')) +r17.delete('/res83/:id', (c) => c.text('m17 r83')) +r17.patch('/res84/:id', (c) => c.text('m17 r84')) +r17.get('/res85/:id', (c) => c.text('m17 r85')) +r17.post('/res86/:id', (c) => c.text('m17 r86')) +r17.put('/res87/:id', (c) => c.text('m17 r87')) +r17.delete('/res88/:id', (c) => c.text('m17 r88')) +r17.patch('/res89/:id', (c) => c.text('m17 r89')) +r17.get('/res90/:id', (c) => c.text('m17 r90')) +r17.post('/res91/:id', (c) => c.text('m17 r91')) +r17.put('/res92/:id', (c) => c.text('m17 r92')) +r17.delete('/res93/:id', (c) => c.text('m17 r93')) +r17.patch('/res94/:id', (c) => c.text('m17 r94')) +r17.get('/res95/:id', (c) => c.text('m17 r95')) +r17.post('/res96/:id', (c) => c.text('m17 r96')) +r17.put('/res97/:id', (c) => c.text('m17 r97')) +r17.delete('/res98/:id', (c) => c.text('m17 r98')) +r17.patch('/res99/:id', (c) => c.text('m17 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod18.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod18.ts new file mode 100644 index 000000000..a5feedcbb --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod18.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r18 = new Hono() +r18.get('/res0/:id', (c) => c.text('m18 r0')) +r18.post('/res1/:id', (c) => c.text('m18 r1')) +r18.put('/res2/:id', (c) => c.text('m18 r2')) +r18.delete('/res3/:id', (c) => c.text('m18 r3')) +r18.patch('/res4/:id', (c) => c.text('m18 r4')) +r18.get('/res5/:id', (c) => c.text('m18 r5')) +r18.post('/res6/:id', (c) => c.text('m18 r6')) +r18.put('/res7/:id', (c) => c.text('m18 r7')) +r18.delete('/res8/:id', (c) => c.text('m18 r8')) +r18.patch('/res9/:id', (c) => c.text('m18 r9')) +r18.get('/res10/:id', (c) => c.text('m18 r10')) +r18.post('/res11/:id', (c) => c.text('m18 r11')) +r18.put('/res12/:id', (c) => c.text('m18 r12')) +r18.delete('/res13/:id', (c) => c.text('m18 r13')) +r18.patch('/res14/:id', (c) => c.text('m18 r14')) +r18.get('/res15/:id', (c) => c.text('m18 r15')) +r18.post('/res16/:id', (c) => c.text('m18 r16')) +r18.put('/res17/:id', (c) => c.text('m18 r17')) +r18.delete('/res18/:id', (c) => c.text('m18 r18')) +r18.patch('/res19/:id', (c) => c.text('m18 r19')) +r18.get('/res20/:id', (c) => c.text('m18 r20')) +r18.post('/res21/:id', (c) => c.text('m18 r21')) +r18.put('/res22/:id', (c) => c.text('m18 r22')) +r18.delete('/res23/:id', (c) => c.text('m18 r23')) +r18.patch('/res24/:id', (c) => c.text('m18 r24')) +r18.get('/res25/:id', (c) => c.text('m18 r25')) +r18.post('/res26/:id', (c) => c.text('m18 r26')) +r18.put('/res27/:id', (c) => c.text('m18 r27')) +r18.delete('/res28/:id', (c) => c.text('m18 r28')) +r18.patch('/res29/:id', (c) => c.text('m18 r29')) +r18.get('/res30/:id', (c) => c.text('m18 r30')) +r18.post('/res31/:id', (c) => c.text('m18 r31')) +r18.put('/res32/:id', (c) => c.text('m18 r32')) +r18.delete('/res33/:id', (c) => c.text('m18 r33')) +r18.patch('/res34/:id', (c) => c.text('m18 r34')) +r18.get('/res35/:id', (c) => c.text('m18 r35')) +r18.post('/res36/:id', (c) => c.text('m18 r36')) +r18.put('/res37/:id', (c) => c.text('m18 r37')) +r18.delete('/res38/:id', (c) => c.text('m18 r38')) +r18.patch('/res39/:id', (c) => c.text('m18 r39')) +r18.get('/res40/:id', (c) => c.text('m18 r40')) +r18.post('/res41/:id', (c) => c.text('m18 r41')) +r18.put('/res42/:id', (c) => c.text('m18 r42')) +r18.delete('/res43/:id', (c) => c.text('m18 r43')) +r18.patch('/res44/:id', (c) => c.text('m18 r44')) +r18.get('/res45/:id', (c) => c.text('m18 r45')) +r18.post('/res46/:id', (c) => c.text('m18 r46')) +r18.put('/res47/:id', (c) => c.text('m18 r47')) +r18.delete('/res48/:id', (c) => c.text('m18 r48')) +r18.patch('/res49/:id', (c) => c.text('m18 r49')) +r18.get('/res50/:id', (c) => c.text('m18 r50')) +r18.post('/res51/:id', (c) => c.text('m18 r51')) +r18.put('/res52/:id', (c) => c.text('m18 r52')) +r18.delete('/res53/:id', (c) => c.text('m18 r53')) +r18.patch('/res54/:id', (c) => c.text('m18 r54')) +r18.get('/res55/:id', (c) => c.text('m18 r55')) +r18.post('/res56/:id', (c) => c.text('m18 r56')) +r18.put('/res57/:id', (c) => c.text('m18 r57')) +r18.delete('/res58/:id', (c) => c.text('m18 r58')) +r18.patch('/res59/:id', (c) => c.text('m18 r59')) +r18.get('/res60/:id', (c) => c.text('m18 r60')) +r18.post('/res61/:id', (c) => c.text('m18 r61')) +r18.put('/res62/:id', (c) => c.text('m18 r62')) +r18.delete('/res63/:id', (c) => c.text('m18 r63')) +r18.patch('/res64/:id', (c) => c.text('m18 r64')) +r18.get('/res65/:id', (c) => c.text('m18 r65')) +r18.post('/res66/:id', (c) => c.text('m18 r66')) +r18.put('/res67/:id', (c) => c.text('m18 r67')) +r18.delete('/res68/:id', (c) => c.text('m18 r68')) +r18.patch('/res69/:id', (c) => c.text('m18 r69')) +r18.get('/res70/:id', (c) => c.text('m18 r70')) +r18.post('/res71/:id', (c) => c.text('m18 r71')) +r18.put('/res72/:id', (c) => c.text('m18 r72')) +r18.delete('/res73/:id', (c) => c.text('m18 r73')) +r18.patch('/res74/:id', (c) => c.text('m18 r74')) +r18.get('/res75/:id', (c) => c.text('m18 r75')) +r18.post('/res76/:id', (c) => c.text('m18 r76')) +r18.put('/res77/:id', (c) => c.text('m18 r77')) +r18.delete('/res78/:id', (c) => c.text('m18 r78')) +r18.patch('/res79/:id', (c) => c.text('m18 r79')) +r18.get('/res80/:id', (c) => c.text('m18 r80')) +r18.post('/res81/:id', (c) => c.text('m18 r81')) +r18.put('/res82/:id', (c) => c.text('m18 r82')) +r18.delete('/res83/:id', (c) => c.text('m18 r83')) +r18.patch('/res84/:id', (c) => c.text('m18 r84')) +r18.get('/res85/:id', (c) => c.text('m18 r85')) +r18.post('/res86/:id', (c) => c.text('m18 r86')) +r18.put('/res87/:id', (c) => c.text('m18 r87')) +r18.delete('/res88/:id', (c) => c.text('m18 r88')) +r18.patch('/res89/:id', (c) => c.text('m18 r89')) +r18.get('/res90/:id', (c) => c.text('m18 r90')) +r18.post('/res91/:id', (c) => c.text('m18 r91')) +r18.put('/res92/:id', (c) => c.text('m18 r92')) +r18.delete('/res93/:id', (c) => c.text('m18 r93')) +r18.patch('/res94/:id', (c) => c.text('m18 r94')) +r18.get('/res95/:id', (c) => c.text('m18 r95')) +r18.post('/res96/:id', (c) => c.text('m18 r96')) +r18.put('/res97/:id', (c) => c.text('m18 r97')) +r18.delete('/res98/:id', (c) => c.text('m18 r98')) +r18.patch('/res99/:id', (c) => c.text('m18 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod19.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod19.ts new file mode 100644 index 000000000..e0b28ede7 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod19.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r19 = new Hono() +r19.get('/res0/:id', (c) => c.text('m19 r0')) +r19.post('/res1/:id', (c) => c.text('m19 r1')) +r19.put('/res2/:id', (c) => c.text('m19 r2')) +r19.delete('/res3/:id', (c) => c.text('m19 r3')) +r19.patch('/res4/:id', (c) => c.text('m19 r4')) +r19.get('/res5/:id', (c) => c.text('m19 r5')) +r19.post('/res6/:id', (c) => c.text('m19 r6')) +r19.put('/res7/:id', (c) => c.text('m19 r7')) +r19.delete('/res8/:id', (c) => c.text('m19 r8')) +r19.patch('/res9/:id', (c) => c.text('m19 r9')) +r19.get('/res10/:id', (c) => c.text('m19 r10')) +r19.post('/res11/:id', (c) => c.text('m19 r11')) +r19.put('/res12/:id', (c) => c.text('m19 r12')) +r19.delete('/res13/:id', (c) => c.text('m19 r13')) +r19.patch('/res14/:id', (c) => c.text('m19 r14')) +r19.get('/res15/:id', (c) => c.text('m19 r15')) +r19.post('/res16/:id', (c) => c.text('m19 r16')) +r19.put('/res17/:id', (c) => c.text('m19 r17')) +r19.delete('/res18/:id', (c) => c.text('m19 r18')) +r19.patch('/res19/:id', (c) => c.text('m19 r19')) +r19.get('/res20/:id', (c) => c.text('m19 r20')) +r19.post('/res21/:id', (c) => c.text('m19 r21')) +r19.put('/res22/:id', (c) => c.text('m19 r22')) +r19.delete('/res23/:id', (c) => c.text('m19 r23')) +r19.patch('/res24/:id', (c) => c.text('m19 r24')) +r19.get('/res25/:id', (c) => c.text('m19 r25')) +r19.post('/res26/:id', (c) => c.text('m19 r26')) +r19.put('/res27/:id', (c) => c.text('m19 r27')) +r19.delete('/res28/:id', (c) => c.text('m19 r28')) +r19.patch('/res29/:id', (c) => c.text('m19 r29')) +r19.get('/res30/:id', (c) => c.text('m19 r30')) +r19.post('/res31/:id', (c) => c.text('m19 r31')) +r19.put('/res32/:id', (c) => c.text('m19 r32')) +r19.delete('/res33/:id', (c) => c.text('m19 r33')) +r19.patch('/res34/:id', (c) => c.text('m19 r34')) +r19.get('/res35/:id', (c) => c.text('m19 r35')) +r19.post('/res36/:id', (c) => c.text('m19 r36')) +r19.put('/res37/:id', (c) => c.text('m19 r37')) +r19.delete('/res38/:id', (c) => c.text('m19 r38')) +r19.patch('/res39/:id', (c) => c.text('m19 r39')) +r19.get('/res40/:id', (c) => c.text('m19 r40')) +r19.post('/res41/:id', (c) => c.text('m19 r41')) +r19.put('/res42/:id', (c) => c.text('m19 r42')) +r19.delete('/res43/:id', (c) => c.text('m19 r43')) +r19.patch('/res44/:id', (c) => c.text('m19 r44')) +r19.get('/res45/:id', (c) => c.text('m19 r45')) +r19.post('/res46/:id', (c) => c.text('m19 r46')) +r19.put('/res47/:id', (c) => c.text('m19 r47')) +r19.delete('/res48/:id', (c) => c.text('m19 r48')) +r19.patch('/res49/:id', (c) => c.text('m19 r49')) +r19.get('/res50/:id', (c) => c.text('m19 r50')) +r19.post('/res51/:id', (c) => c.text('m19 r51')) +r19.put('/res52/:id', (c) => c.text('m19 r52')) +r19.delete('/res53/:id', (c) => c.text('m19 r53')) +r19.patch('/res54/:id', (c) => c.text('m19 r54')) +r19.get('/res55/:id', (c) => c.text('m19 r55')) +r19.post('/res56/:id', (c) => c.text('m19 r56')) +r19.put('/res57/:id', (c) => c.text('m19 r57')) +r19.delete('/res58/:id', (c) => c.text('m19 r58')) +r19.patch('/res59/:id', (c) => c.text('m19 r59')) +r19.get('/res60/:id', (c) => c.text('m19 r60')) +r19.post('/res61/:id', (c) => c.text('m19 r61')) +r19.put('/res62/:id', (c) => c.text('m19 r62')) +r19.delete('/res63/:id', (c) => c.text('m19 r63')) +r19.patch('/res64/:id', (c) => c.text('m19 r64')) +r19.get('/res65/:id', (c) => c.text('m19 r65')) +r19.post('/res66/:id', (c) => c.text('m19 r66')) +r19.put('/res67/:id', (c) => c.text('m19 r67')) +r19.delete('/res68/:id', (c) => c.text('m19 r68')) +r19.patch('/res69/:id', (c) => c.text('m19 r69')) +r19.get('/res70/:id', (c) => c.text('m19 r70')) +r19.post('/res71/:id', (c) => c.text('m19 r71')) +r19.put('/res72/:id', (c) => c.text('m19 r72')) +r19.delete('/res73/:id', (c) => c.text('m19 r73')) +r19.patch('/res74/:id', (c) => c.text('m19 r74')) +r19.get('/res75/:id', (c) => c.text('m19 r75')) +r19.post('/res76/:id', (c) => c.text('m19 r76')) +r19.put('/res77/:id', (c) => c.text('m19 r77')) +r19.delete('/res78/:id', (c) => c.text('m19 r78')) +r19.patch('/res79/:id', (c) => c.text('m19 r79')) +r19.get('/res80/:id', (c) => c.text('m19 r80')) +r19.post('/res81/:id', (c) => c.text('m19 r81')) +r19.put('/res82/:id', (c) => c.text('m19 r82')) +r19.delete('/res83/:id', (c) => c.text('m19 r83')) +r19.patch('/res84/:id', (c) => c.text('m19 r84')) +r19.get('/res85/:id', (c) => c.text('m19 r85')) +r19.post('/res86/:id', (c) => c.text('m19 r86')) +r19.put('/res87/:id', (c) => c.text('m19 r87')) +r19.delete('/res88/:id', (c) => c.text('m19 r88')) +r19.patch('/res89/:id', (c) => c.text('m19 r89')) +r19.get('/res90/:id', (c) => c.text('m19 r90')) +r19.post('/res91/:id', (c) => c.text('m19 r91')) +r19.put('/res92/:id', (c) => c.text('m19 r92')) +r19.delete('/res93/:id', (c) => c.text('m19 r93')) +r19.patch('/res94/:id', (c) => c.text('m19 r94')) +r19.get('/res95/:id', (c) => c.text('m19 r95')) +r19.post('/res96/:id', (c) => c.text('m19 r96')) +r19.put('/res97/:id', (c) => c.text('m19 r97')) +r19.delete('/res98/:id', (c) => c.text('m19 r98')) +r19.patch('/res99/:id', (c) => c.text('m19 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod2.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod2.ts new file mode 100644 index 000000000..a01320714 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod2.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r2 = new Hono() +r2.get('/res0/:id', (c) => c.text('m2 r0')) +r2.post('/res1/:id', (c) => c.text('m2 r1')) +r2.put('/res2/:id', (c) => c.text('m2 r2')) +r2.delete('/res3/:id', (c) => c.text('m2 r3')) +r2.patch('/res4/:id', (c) => c.text('m2 r4')) +r2.get('/res5/:id', (c) => c.text('m2 r5')) +r2.post('/res6/:id', (c) => c.text('m2 r6')) +r2.put('/res7/:id', (c) => c.text('m2 r7')) +r2.delete('/res8/:id', (c) => c.text('m2 r8')) +r2.patch('/res9/:id', (c) => c.text('m2 r9')) +r2.get('/res10/:id', (c) => c.text('m2 r10')) +r2.post('/res11/:id', (c) => c.text('m2 r11')) +r2.put('/res12/:id', (c) => c.text('m2 r12')) +r2.delete('/res13/:id', (c) => c.text('m2 r13')) +r2.patch('/res14/:id', (c) => c.text('m2 r14')) +r2.get('/res15/:id', (c) => c.text('m2 r15')) +r2.post('/res16/:id', (c) => c.text('m2 r16')) +r2.put('/res17/:id', (c) => c.text('m2 r17')) +r2.delete('/res18/:id', (c) => c.text('m2 r18')) +r2.patch('/res19/:id', (c) => c.text('m2 r19')) +r2.get('/res20/:id', (c) => c.text('m2 r20')) +r2.post('/res21/:id', (c) => c.text('m2 r21')) +r2.put('/res22/:id', (c) => c.text('m2 r22')) +r2.delete('/res23/:id', (c) => c.text('m2 r23')) +r2.patch('/res24/:id', (c) => c.text('m2 r24')) +r2.get('/res25/:id', (c) => c.text('m2 r25')) +r2.post('/res26/:id', (c) => c.text('m2 r26')) +r2.put('/res27/:id', (c) => c.text('m2 r27')) +r2.delete('/res28/:id', (c) => c.text('m2 r28')) +r2.patch('/res29/:id', (c) => c.text('m2 r29')) +r2.get('/res30/:id', (c) => c.text('m2 r30')) +r2.post('/res31/:id', (c) => c.text('m2 r31')) +r2.put('/res32/:id', (c) => c.text('m2 r32')) +r2.delete('/res33/:id', (c) => c.text('m2 r33')) +r2.patch('/res34/:id', (c) => c.text('m2 r34')) +r2.get('/res35/:id', (c) => c.text('m2 r35')) +r2.post('/res36/:id', (c) => c.text('m2 r36')) +r2.put('/res37/:id', (c) => c.text('m2 r37')) +r2.delete('/res38/:id', (c) => c.text('m2 r38')) +r2.patch('/res39/:id', (c) => c.text('m2 r39')) +r2.get('/res40/:id', (c) => c.text('m2 r40')) +r2.post('/res41/:id', (c) => c.text('m2 r41')) +r2.put('/res42/:id', (c) => c.text('m2 r42')) +r2.delete('/res43/:id', (c) => c.text('m2 r43')) +r2.patch('/res44/:id', (c) => c.text('m2 r44')) +r2.get('/res45/:id', (c) => c.text('m2 r45')) +r2.post('/res46/:id', (c) => c.text('m2 r46')) +r2.put('/res47/:id', (c) => c.text('m2 r47')) +r2.delete('/res48/:id', (c) => c.text('m2 r48')) +r2.patch('/res49/:id', (c) => c.text('m2 r49')) +r2.get('/res50/:id', (c) => c.text('m2 r50')) +r2.post('/res51/:id', (c) => c.text('m2 r51')) +r2.put('/res52/:id', (c) => c.text('m2 r52')) +r2.delete('/res53/:id', (c) => c.text('m2 r53')) +r2.patch('/res54/:id', (c) => c.text('m2 r54')) +r2.get('/res55/:id', (c) => c.text('m2 r55')) +r2.post('/res56/:id', (c) => c.text('m2 r56')) +r2.put('/res57/:id', (c) => c.text('m2 r57')) +r2.delete('/res58/:id', (c) => c.text('m2 r58')) +r2.patch('/res59/:id', (c) => c.text('m2 r59')) +r2.get('/res60/:id', (c) => c.text('m2 r60')) +r2.post('/res61/:id', (c) => c.text('m2 r61')) +r2.put('/res62/:id', (c) => c.text('m2 r62')) +r2.delete('/res63/:id', (c) => c.text('m2 r63')) +r2.patch('/res64/:id', (c) => c.text('m2 r64')) +r2.get('/res65/:id', (c) => c.text('m2 r65')) +r2.post('/res66/:id', (c) => c.text('m2 r66')) +r2.put('/res67/:id', (c) => c.text('m2 r67')) +r2.delete('/res68/:id', (c) => c.text('m2 r68')) +r2.patch('/res69/:id', (c) => c.text('m2 r69')) +r2.get('/res70/:id', (c) => c.text('m2 r70')) +r2.post('/res71/:id', (c) => c.text('m2 r71')) +r2.put('/res72/:id', (c) => c.text('m2 r72')) +r2.delete('/res73/:id', (c) => c.text('m2 r73')) +r2.patch('/res74/:id', (c) => c.text('m2 r74')) +r2.get('/res75/:id', (c) => c.text('m2 r75')) +r2.post('/res76/:id', (c) => c.text('m2 r76')) +r2.put('/res77/:id', (c) => c.text('m2 r77')) +r2.delete('/res78/:id', (c) => c.text('m2 r78')) +r2.patch('/res79/:id', (c) => c.text('m2 r79')) +r2.get('/res80/:id', (c) => c.text('m2 r80')) +r2.post('/res81/:id', (c) => c.text('m2 r81')) +r2.put('/res82/:id', (c) => c.text('m2 r82')) +r2.delete('/res83/:id', (c) => c.text('m2 r83')) +r2.patch('/res84/:id', (c) => c.text('m2 r84')) +r2.get('/res85/:id', (c) => c.text('m2 r85')) +r2.post('/res86/:id', (c) => c.text('m2 r86')) +r2.put('/res87/:id', (c) => c.text('m2 r87')) +r2.delete('/res88/:id', (c) => c.text('m2 r88')) +r2.patch('/res89/:id', (c) => c.text('m2 r89')) +r2.get('/res90/:id', (c) => c.text('m2 r90')) +r2.post('/res91/:id', (c) => c.text('m2 r91')) +r2.put('/res92/:id', (c) => c.text('m2 r92')) +r2.delete('/res93/:id', (c) => c.text('m2 r93')) +r2.patch('/res94/:id', (c) => c.text('m2 r94')) +r2.get('/res95/:id', (c) => c.text('m2 r95')) +r2.post('/res96/:id', (c) => c.text('m2 r96')) +r2.put('/res97/:id', (c) => c.text('m2 r97')) +r2.delete('/res98/:id', (c) => c.text('m2 r98')) +r2.patch('/res99/:id', (c) => c.text('m2 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod3.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod3.ts new file mode 100644 index 000000000..f5acf18e5 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod3.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r3 = new Hono() +r3.get('/res0/:id', (c) => c.text('m3 r0')) +r3.post('/res1/:id', (c) => c.text('m3 r1')) +r3.put('/res2/:id', (c) => c.text('m3 r2')) +r3.delete('/res3/:id', (c) => c.text('m3 r3')) +r3.patch('/res4/:id', (c) => c.text('m3 r4')) +r3.get('/res5/:id', (c) => c.text('m3 r5')) +r3.post('/res6/:id', (c) => c.text('m3 r6')) +r3.put('/res7/:id', (c) => c.text('m3 r7')) +r3.delete('/res8/:id', (c) => c.text('m3 r8')) +r3.patch('/res9/:id', (c) => c.text('m3 r9')) +r3.get('/res10/:id', (c) => c.text('m3 r10')) +r3.post('/res11/:id', (c) => c.text('m3 r11')) +r3.put('/res12/:id', (c) => c.text('m3 r12')) +r3.delete('/res13/:id', (c) => c.text('m3 r13')) +r3.patch('/res14/:id', (c) => c.text('m3 r14')) +r3.get('/res15/:id', (c) => c.text('m3 r15')) +r3.post('/res16/:id', (c) => c.text('m3 r16')) +r3.put('/res17/:id', (c) => c.text('m3 r17')) +r3.delete('/res18/:id', (c) => c.text('m3 r18')) +r3.patch('/res19/:id', (c) => c.text('m3 r19')) +r3.get('/res20/:id', (c) => c.text('m3 r20')) +r3.post('/res21/:id', (c) => c.text('m3 r21')) +r3.put('/res22/:id', (c) => c.text('m3 r22')) +r3.delete('/res23/:id', (c) => c.text('m3 r23')) +r3.patch('/res24/:id', (c) => c.text('m3 r24')) +r3.get('/res25/:id', (c) => c.text('m3 r25')) +r3.post('/res26/:id', (c) => c.text('m3 r26')) +r3.put('/res27/:id', (c) => c.text('m3 r27')) +r3.delete('/res28/:id', (c) => c.text('m3 r28')) +r3.patch('/res29/:id', (c) => c.text('m3 r29')) +r3.get('/res30/:id', (c) => c.text('m3 r30')) +r3.post('/res31/:id', (c) => c.text('m3 r31')) +r3.put('/res32/:id', (c) => c.text('m3 r32')) +r3.delete('/res33/:id', (c) => c.text('m3 r33')) +r3.patch('/res34/:id', (c) => c.text('m3 r34')) +r3.get('/res35/:id', (c) => c.text('m3 r35')) +r3.post('/res36/:id', (c) => c.text('m3 r36')) +r3.put('/res37/:id', (c) => c.text('m3 r37')) +r3.delete('/res38/:id', (c) => c.text('m3 r38')) +r3.patch('/res39/:id', (c) => c.text('m3 r39')) +r3.get('/res40/:id', (c) => c.text('m3 r40')) +r3.post('/res41/:id', (c) => c.text('m3 r41')) +r3.put('/res42/:id', (c) => c.text('m3 r42')) +r3.delete('/res43/:id', (c) => c.text('m3 r43')) +r3.patch('/res44/:id', (c) => c.text('m3 r44')) +r3.get('/res45/:id', (c) => c.text('m3 r45')) +r3.post('/res46/:id', (c) => c.text('m3 r46')) +r3.put('/res47/:id', (c) => c.text('m3 r47')) +r3.delete('/res48/:id', (c) => c.text('m3 r48')) +r3.patch('/res49/:id', (c) => c.text('m3 r49')) +r3.get('/res50/:id', (c) => c.text('m3 r50')) +r3.post('/res51/:id', (c) => c.text('m3 r51')) +r3.put('/res52/:id', (c) => c.text('m3 r52')) +r3.delete('/res53/:id', (c) => c.text('m3 r53')) +r3.patch('/res54/:id', (c) => c.text('m3 r54')) +r3.get('/res55/:id', (c) => c.text('m3 r55')) +r3.post('/res56/:id', (c) => c.text('m3 r56')) +r3.put('/res57/:id', (c) => c.text('m3 r57')) +r3.delete('/res58/:id', (c) => c.text('m3 r58')) +r3.patch('/res59/:id', (c) => c.text('m3 r59')) +r3.get('/res60/:id', (c) => c.text('m3 r60')) +r3.post('/res61/:id', (c) => c.text('m3 r61')) +r3.put('/res62/:id', (c) => c.text('m3 r62')) +r3.delete('/res63/:id', (c) => c.text('m3 r63')) +r3.patch('/res64/:id', (c) => c.text('m3 r64')) +r3.get('/res65/:id', (c) => c.text('m3 r65')) +r3.post('/res66/:id', (c) => c.text('m3 r66')) +r3.put('/res67/:id', (c) => c.text('m3 r67')) +r3.delete('/res68/:id', (c) => c.text('m3 r68')) +r3.patch('/res69/:id', (c) => c.text('m3 r69')) +r3.get('/res70/:id', (c) => c.text('m3 r70')) +r3.post('/res71/:id', (c) => c.text('m3 r71')) +r3.put('/res72/:id', (c) => c.text('m3 r72')) +r3.delete('/res73/:id', (c) => c.text('m3 r73')) +r3.patch('/res74/:id', (c) => c.text('m3 r74')) +r3.get('/res75/:id', (c) => c.text('m3 r75')) +r3.post('/res76/:id', (c) => c.text('m3 r76')) +r3.put('/res77/:id', (c) => c.text('m3 r77')) +r3.delete('/res78/:id', (c) => c.text('m3 r78')) +r3.patch('/res79/:id', (c) => c.text('m3 r79')) +r3.get('/res80/:id', (c) => c.text('m3 r80')) +r3.post('/res81/:id', (c) => c.text('m3 r81')) +r3.put('/res82/:id', (c) => c.text('m3 r82')) +r3.delete('/res83/:id', (c) => c.text('m3 r83')) +r3.patch('/res84/:id', (c) => c.text('m3 r84')) +r3.get('/res85/:id', (c) => c.text('m3 r85')) +r3.post('/res86/:id', (c) => c.text('m3 r86')) +r3.put('/res87/:id', (c) => c.text('m3 r87')) +r3.delete('/res88/:id', (c) => c.text('m3 r88')) +r3.patch('/res89/:id', (c) => c.text('m3 r89')) +r3.get('/res90/:id', (c) => c.text('m3 r90')) +r3.post('/res91/:id', (c) => c.text('m3 r91')) +r3.put('/res92/:id', (c) => c.text('m3 r92')) +r3.delete('/res93/:id', (c) => c.text('m3 r93')) +r3.patch('/res94/:id', (c) => c.text('m3 r94')) +r3.get('/res95/:id', (c) => c.text('m3 r95')) +r3.post('/res96/:id', (c) => c.text('m3 r96')) +r3.put('/res97/:id', (c) => c.text('m3 r97')) +r3.delete('/res98/:id', (c) => c.text('m3 r98')) +r3.patch('/res99/:id', (c) => c.text('m3 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod4.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod4.ts new file mode 100644 index 000000000..bcda49887 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod4.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r4 = new Hono() +r4.get('/res0/:id', (c) => c.text('m4 r0')) +r4.post('/res1/:id', (c) => c.text('m4 r1')) +r4.put('/res2/:id', (c) => c.text('m4 r2')) +r4.delete('/res3/:id', (c) => c.text('m4 r3')) +r4.patch('/res4/:id', (c) => c.text('m4 r4')) +r4.get('/res5/:id', (c) => c.text('m4 r5')) +r4.post('/res6/:id', (c) => c.text('m4 r6')) +r4.put('/res7/:id', (c) => c.text('m4 r7')) +r4.delete('/res8/:id', (c) => c.text('m4 r8')) +r4.patch('/res9/:id', (c) => c.text('m4 r9')) +r4.get('/res10/:id', (c) => c.text('m4 r10')) +r4.post('/res11/:id', (c) => c.text('m4 r11')) +r4.put('/res12/:id', (c) => c.text('m4 r12')) +r4.delete('/res13/:id', (c) => c.text('m4 r13')) +r4.patch('/res14/:id', (c) => c.text('m4 r14')) +r4.get('/res15/:id', (c) => c.text('m4 r15')) +r4.post('/res16/:id', (c) => c.text('m4 r16')) +r4.put('/res17/:id', (c) => c.text('m4 r17')) +r4.delete('/res18/:id', (c) => c.text('m4 r18')) +r4.patch('/res19/:id', (c) => c.text('m4 r19')) +r4.get('/res20/:id', (c) => c.text('m4 r20')) +r4.post('/res21/:id', (c) => c.text('m4 r21')) +r4.put('/res22/:id', (c) => c.text('m4 r22')) +r4.delete('/res23/:id', (c) => c.text('m4 r23')) +r4.patch('/res24/:id', (c) => c.text('m4 r24')) +r4.get('/res25/:id', (c) => c.text('m4 r25')) +r4.post('/res26/:id', (c) => c.text('m4 r26')) +r4.put('/res27/:id', (c) => c.text('m4 r27')) +r4.delete('/res28/:id', (c) => c.text('m4 r28')) +r4.patch('/res29/:id', (c) => c.text('m4 r29')) +r4.get('/res30/:id', (c) => c.text('m4 r30')) +r4.post('/res31/:id', (c) => c.text('m4 r31')) +r4.put('/res32/:id', (c) => c.text('m4 r32')) +r4.delete('/res33/:id', (c) => c.text('m4 r33')) +r4.patch('/res34/:id', (c) => c.text('m4 r34')) +r4.get('/res35/:id', (c) => c.text('m4 r35')) +r4.post('/res36/:id', (c) => c.text('m4 r36')) +r4.put('/res37/:id', (c) => c.text('m4 r37')) +r4.delete('/res38/:id', (c) => c.text('m4 r38')) +r4.patch('/res39/:id', (c) => c.text('m4 r39')) +r4.get('/res40/:id', (c) => c.text('m4 r40')) +r4.post('/res41/:id', (c) => c.text('m4 r41')) +r4.put('/res42/:id', (c) => c.text('m4 r42')) +r4.delete('/res43/:id', (c) => c.text('m4 r43')) +r4.patch('/res44/:id', (c) => c.text('m4 r44')) +r4.get('/res45/:id', (c) => c.text('m4 r45')) +r4.post('/res46/:id', (c) => c.text('m4 r46')) +r4.put('/res47/:id', (c) => c.text('m4 r47')) +r4.delete('/res48/:id', (c) => c.text('m4 r48')) +r4.patch('/res49/:id', (c) => c.text('m4 r49')) +r4.get('/res50/:id', (c) => c.text('m4 r50')) +r4.post('/res51/:id', (c) => c.text('m4 r51')) +r4.put('/res52/:id', (c) => c.text('m4 r52')) +r4.delete('/res53/:id', (c) => c.text('m4 r53')) +r4.patch('/res54/:id', (c) => c.text('m4 r54')) +r4.get('/res55/:id', (c) => c.text('m4 r55')) +r4.post('/res56/:id', (c) => c.text('m4 r56')) +r4.put('/res57/:id', (c) => c.text('m4 r57')) +r4.delete('/res58/:id', (c) => c.text('m4 r58')) +r4.patch('/res59/:id', (c) => c.text('m4 r59')) +r4.get('/res60/:id', (c) => c.text('m4 r60')) +r4.post('/res61/:id', (c) => c.text('m4 r61')) +r4.put('/res62/:id', (c) => c.text('m4 r62')) +r4.delete('/res63/:id', (c) => c.text('m4 r63')) +r4.patch('/res64/:id', (c) => c.text('m4 r64')) +r4.get('/res65/:id', (c) => c.text('m4 r65')) +r4.post('/res66/:id', (c) => c.text('m4 r66')) +r4.put('/res67/:id', (c) => c.text('m4 r67')) +r4.delete('/res68/:id', (c) => c.text('m4 r68')) +r4.patch('/res69/:id', (c) => c.text('m4 r69')) +r4.get('/res70/:id', (c) => c.text('m4 r70')) +r4.post('/res71/:id', (c) => c.text('m4 r71')) +r4.put('/res72/:id', (c) => c.text('m4 r72')) +r4.delete('/res73/:id', (c) => c.text('m4 r73')) +r4.patch('/res74/:id', (c) => c.text('m4 r74')) +r4.get('/res75/:id', (c) => c.text('m4 r75')) +r4.post('/res76/:id', (c) => c.text('m4 r76')) +r4.put('/res77/:id', (c) => c.text('m4 r77')) +r4.delete('/res78/:id', (c) => c.text('m4 r78')) +r4.patch('/res79/:id', (c) => c.text('m4 r79')) +r4.get('/res80/:id', (c) => c.text('m4 r80')) +r4.post('/res81/:id', (c) => c.text('m4 r81')) +r4.put('/res82/:id', (c) => c.text('m4 r82')) +r4.delete('/res83/:id', (c) => c.text('m4 r83')) +r4.patch('/res84/:id', (c) => c.text('m4 r84')) +r4.get('/res85/:id', (c) => c.text('m4 r85')) +r4.post('/res86/:id', (c) => c.text('m4 r86')) +r4.put('/res87/:id', (c) => c.text('m4 r87')) +r4.delete('/res88/:id', (c) => c.text('m4 r88')) +r4.patch('/res89/:id', (c) => c.text('m4 r89')) +r4.get('/res90/:id', (c) => c.text('m4 r90')) +r4.post('/res91/:id', (c) => c.text('m4 r91')) +r4.put('/res92/:id', (c) => c.text('m4 r92')) +r4.delete('/res93/:id', (c) => c.text('m4 r93')) +r4.patch('/res94/:id', (c) => c.text('m4 r94')) +r4.get('/res95/:id', (c) => c.text('m4 r95')) +r4.post('/res96/:id', (c) => c.text('m4 r96')) +r4.put('/res97/:id', (c) => c.text('m4 r97')) +r4.delete('/res98/:id', (c) => c.text('m4 r98')) +r4.patch('/res99/:id', (c) => c.text('m4 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod5.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod5.ts new file mode 100644 index 000000000..7ee8b7d0d --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod5.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r5 = new Hono() +r5.get('/res0/:id', (c) => c.text('m5 r0')) +r5.post('/res1/:id', (c) => c.text('m5 r1')) +r5.put('/res2/:id', (c) => c.text('m5 r2')) +r5.delete('/res3/:id', (c) => c.text('m5 r3')) +r5.patch('/res4/:id', (c) => c.text('m5 r4')) +r5.get('/res5/:id', (c) => c.text('m5 r5')) +r5.post('/res6/:id', (c) => c.text('m5 r6')) +r5.put('/res7/:id', (c) => c.text('m5 r7')) +r5.delete('/res8/:id', (c) => c.text('m5 r8')) +r5.patch('/res9/:id', (c) => c.text('m5 r9')) +r5.get('/res10/:id', (c) => c.text('m5 r10')) +r5.post('/res11/:id', (c) => c.text('m5 r11')) +r5.put('/res12/:id', (c) => c.text('m5 r12')) +r5.delete('/res13/:id', (c) => c.text('m5 r13')) +r5.patch('/res14/:id', (c) => c.text('m5 r14')) +r5.get('/res15/:id', (c) => c.text('m5 r15')) +r5.post('/res16/:id', (c) => c.text('m5 r16')) +r5.put('/res17/:id', (c) => c.text('m5 r17')) +r5.delete('/res18/:id', (c) => c.text('m5 r18')) +r5.patch('/res19/:id', (c) => c.text('m5 r19')) +r5.get('/res20/:id', (c) => c.text('m5 r20')) +r5.post('/res21/:id', (c) => c.text('m5 r21')) +r5.put('/res22/:id', (c) => c.text('m5 r22')) +r5.delete('/res23/:id', (c) => c.text('m5 r23')) +r5.patch('/res24/:id', (c) => c.text('m5 r24')) +r5.get('/res25/:id', (c) => c.text('m5 r25')) +r5.post('/res26/:id', (c) => c.text('m5 r26')) +r5.put('/res27/:id', (c) => c.text('m5 r27')) +r5.delete('/res28/:id', (c) => c.text('m5 r28')) +r5.patch('/res29/:id', (c) => c.text('m5 r29')) +r5.get('/res30/:id', (c) => c.text('m5 r30')) +r5.post('/res31/:id', (c) => c.text('m5 r31')) +r5.put('/res32/:id', (c) => c.text('m5 r32')) +r5.delete('/res33/:id', (c) => c.text('m5 r33')) +r5.patch('/res34/:id', (c) => c.text('m5 r34')) +r5.get('/res35/:id', (c) => c.text('m5 r35')) +r5.post('/res36/:id', (c) => c.text('m5 r36')) +r5.put('/res37/:id', (c) => c.text('m5 r37')) +r5.delete('/res38/:id', (c) => c.text('m5 r38')) +r5.patch('/res39/:id', (c) => c.text('m5 r39')) +r5.get('/res40/:id', (c) => c.text('m5 r40')) +r5.post('/res41/:id', (c) => c.text('m5 r41')) +r5.put('/res42/:id', (c) => c.text('m5 r42')) +r5.delete('/res43/:id', (c) => c.text('m5 r43')) +r5.patch('/res44/:id', (c) => c.text('m5 r44')) +r5.get('/res45/:id', (c) => c.text('m5 r45')) +r5.post('/res46/:id', (c) => c.text('m5 r46')) +r5.put('/res47/:id', (c) => c.text('m5 r47')) +r5.delete('/res48/:id', (c) => c.text('m5 r48')) +r5.patch('/res49/:id', (c) => c.text('m5 r49')) +r5.get('/res50/:id', (c) => c.text('m5 r50')) +r5.post('/res51/:id', (c) => c.text('m5 r51')) +r5.put('/res52/:id', (c) => c.text('m5 r52')) +r5.delete('/res53/:id', (c) => c.text('m5 r53')) +r5.patch('/res54/:id', (c) => c.text('m5 r54')) +r5.get('/res55/:id', (c) => c.text('m5 r55')) +r5.post('/res56/:id', (c) => c.text('m5 r56')) +r5.put('/res57/:id', (c) => c.text('m5 r57')) +r5.delete('/res58/:id', (c) => c.text('m5 r58')) +r5.patch('/res59/:id', (c) => c.text('m5 r59')) +r5.get('/res60/:id', (c) => c.text('m5 r60')) +r5.post('/res61/:id', (c) => c.text('m5 r61')) +r5.put('/res62/:id', (c) => c.text('m5 r62')) +r5.delete('/res63/:id', (c) => c.text('m5 r63')) +r5.patch('/res64/:id', (c) => c.text('m5 r64')) +r5.get('/res65/:id', (c) => c.text('m5 r65')) +r5.post('/res66/:id', (c) => c.text('m5 r66')) +r5.put('/res67/:id', (c) => c.text('m5 r67')) +r5.delete('/res68/:id', (c) => c.text('m5 r68')) +r5.patch('/res69/:id', (c) => c.text('m5 r69')) +r5.get('/res70/:id', (c) => c.text('m5 r70')) +r5.post('/res71/:id', (c) => c.text('m5 r71')) +r5.put('/res72/:id', (c) => c.text('m5 r72')) +r5.delete('/res73/:id', (c) => c.text('m5 r73')) +r5.patch('/res74/:id', (c) => c.text('m5 r74')) +r5.get('/res75/:id', (c) => c.text('m5 r75')) +r5.post('/res76/:id', (c) => c.text('m5 r76')) +r5.put('/res77/:id', (c) => c.text('m5 r77')) +r5.delete('/res78/:id', (c) => c.text('m5 r78')) +r5.patch('/res79/:id', (c) => c.text('m5 r79')) +r5.get('/res80/:id', (c) => c.text('m5 r80')) +r5.post('/res81/:id', (c) => c.text('m5 r81')) +r5.put('/res82/:id', (c) => c.text('m5 r82')) +r5.delete('/res83/:id', (c) => c.text('m5 r83')) +r5.patch('/res84/:id', (c) => c.text('m5 r84')) +r5.get('/res85/:id', (c) => c.text('m5 r85')) +r5.post('/res86/:id', (c) => c.text('m5 r86')) +r5.put('/res87/:id', (c) => c.text('m5 r87')) +r5.delete('/res88/:id', (c) => c.text('m5 r88')) +r5.patch('/res89/:id', (c) => c.text('m5 r89')) +r5.get('/res90/:id', (c) => c.text('m5 r90')) +r5.post('/res91/:id', (c) => c.text('m5 r91')) +r5.put('/res92/:id', (c) => c.text('m5 r92')) +r5.delete('/res93/:id', (c) => c.text('m5 r93')) +r5.patch('/res94/:id', (c) => c.text('m5 r94')) +r5.get('/res95/:id', (c) => c.text('m5 r95')) +r5.post('/res96/:id', (c) => c.text('m5 r96')) +r5.put('/res97/:id', (c) => c.text('m5 r97')) +r5.delete('/res98/:id', (c) => c.text('m5 r98')) +r5.patch('/res99/:id', (c) => c.text('m5 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod6.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod6.ts new file mode 100644 index 000000000..c8bc720de --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod6.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r6 = new Hono() +r6.get('/res0/:id', (c) => c.text('m6 r0')) +r6.post('/res1/:id', (c) => c.text('m6 r1')) +r6.put('/res2/:id', (c) => c.text('m6 r2')) +r6.delete('/res3/:id', (c) => c.text('m6 r3')) +r6.patch('/res4/:id', (c) => c.text('m6 r4')) +r6.get('/res5/:id', (c) => c.text('m6 r5')) +r6.post('/res6/:id', (c) => c.text('m6 r6')) +r6.put('/res7/:id', (c) => c.text('m6 r7')) +r6.delete('/res8/:id', (c) => c.text('m6 r8')) +r6.patch('/res9/:id', (c) => c.text('m6 r9')) +r6.get('/res10/:id', (c) => c.text('m6 r10')) +r6.post('/res11/:id', (c) => c.text('m6 r11')) +r6.put('/res12/:id', (c) => c.text('m6 r12')) +r6.delete('/res13/:id', (c) => c.text('m6 r13')) +r6.patch('/res14/:id', (c) => c.text('m6 r14')) +r6.get('/res15/:id', (c) => c.text('m6 r15')) +r6.post('/res16/:id', (c) => c.text('m6 r16')) +r6.put('/res17/:id', (c) => c.text('m6 r17')) +r6.delete('/res18/:id', (c) => c.text('m6 r18')) +r6.patch('/res19/:id', (c) => c.text('m6 r19')) +r6.get('/res20/:id', (c) => c.text('m6 r20')) +r6.post('/res21/:id', (c) => c.text('m6 r21')) +r6.put('/res22/:id', (c) => c.text('m6 r22')) +r6.delete('/res23/:id', (c) => c.text('m6 r23')) +r6.patch('/res24/:id', (c) => c.text('m6 r24')) +r6.get('/res25/:id', (c) => c.text('m6 r25')) +r6.post('/res26/:id', (c) => c.text('m6 r26')) +r6.put('/res27/:id', (c) => c.text('m6 r27')) +r6.delete('/res28/:id', (c) => c.text('m6 r28')) +r6.patch('/res29/:id', (c) => c.text('m6 r29')) +r6.get('/res30/:id', (c) => c.text('m6 r30')) +r6.post('/res31/:id', (c) => c.text('m6 r31')) +r6.put('/res32/:id', (c) => c.text('m6 r32')) +r6.delete('/res33/:id', (c) => c.text('m6 r33')) +r6.patch('/res34/:id', (c) => c.text('m6 r34')) +r6.get('/res35/:id', (c) => c.text('m6 r35')) +r6.post('/res36/:id', (c) => c.text('m6 r36')) +r6.put('/res37/:id', (c) => c.text('m6 r37')) +r6.delete('/res38/:id', (c) => c.text('m6 r38')) +r6.patch('/res39/:id', (c) => c.text('m6 r39')) +r6.get('/res40/:id', (c) => c.text('m6 r40')) +r6.post('/res41/:id', (c) => c.text('m6 r41')) +r6.put('/res42/:id', (c) => c.text('m6 r42')) +r6.delete('/res43/:id', (c) => c.text('m6 r43')) +r6.patch('/res44/:id', (c) => c.text('m6 r44')) +r6.get('/res45/:id', (c) => c.text('m6 r45')) +r6.post('/res46/:id', (c) => c.text('m6 r46')) +r6.put('/res47/:id', (c) => c.text('m6 r47')) +r6.delete('/res48/:id', (c) => c.text('m6 r48')) +r6.patch('/res49/:id', (c) => c.text('m6 r49')) +r6.get('/res50/:id', (c) => c.text('m6 r50')) +r6.post('/res51/:id', (c) => c.text('m6 r51')) +r6.put('/res52/:id', (c) => c.text('m6 r52')) +r6.delete('/res53/:id', (c) => c.text('m6 r53')) +r6.patch('/res54/:id', (c) => c.text('m6 r54')) +r6.get('/res55/:id', (c) => c.text('m6 r55')) +r6.post('/res56/:id', (c) => c.text('m6 r56')) +r6.put('/res57/:id', (c) => c.text('m6 r57')) +r6.delete('/res58/:id', (c) => c.text('m6 r58')) +r6.patch('/res59/:id', (c) => c.text('m6 r59')) +r6.get('/res60/:id', (c) => c.text('m6 r60')) +r6.post('/res61/:id', (c) => c.text('m6 r61')) +r6.put('/res62/:id', (c) => c.text('m6 r62')) +r6.delete('/res63/:id', (c) => c.text('m6 r63')) +r6.patch('/res64/:id', (c) => c.text('m6 r64')) +r6.get('/res65/:id', (c) => c.text('m6 r65')) +r6.post('/res66/:id', (c) => c.text('m6 r66')) +r6.put('/res67/:id', (c) => c.text('m6 r67')) +r6.delete('/res68/:id', (c) => c.text('m6 r68')) +r6.patch('/res69/:id', (c) => c.text('m6 r69')) +r6.get('/res70/:id', (c) => c.text('m6 r70')) +r6.post('/res71/:id', (c) => c.text('m6 r71')) +r6.put('/res72/:id', (c) => c.text('m6 r72')) +r6.delete('/res73/:id', (c) => c.text('m6 r73')) +r6.patch('/res74/:id', (c) => c.text('m6 r74')) +r6.get('/res75/:id', (c) => c.text('m6 r75')) +r6.post('/res76/:id', (c) => c.text('m6 r76')) +r6.put('/res77/:id', (c) => c.text('m6 r77')) +r6.delete('/res78/:id', (c) => c.text('m6 r78')) +r6.patch('/res79/:id', (c) => c.text('m6 r79')) +r6.get('/res80/:id', (c) => c.text('m6 r80')) +r6.post('/res81/:id', (c) => c.text('m6 r81')) +r6.put('/res82/:id', (c) => c.text('m6 r82')) +r6.delete('/res83/:id', (c) => c.text('m6 r83')) +r6.patch('/res84/:id', (c) => c.text('m6 r84')) +r6.get('/res85/:id', (c) => c.text('m6 r85')) +r6.post('/res86/:id', (c) => c.text('m6 r86')) +r6.put('/res87/:id', (c) => c.text('m6 r87')) +r6.delete('/res88/:id', (c) => c.text('m6 r88')) +r6.patch('/res89/:id', (c) => c.text('m6 r89')) +r6.get('/res90/:id', (c) => c.text('m6 r90')) +r6.post('/res91/:id', (c) => c.text('m6 r91')) +r6.put('/res92/:id', (c) => c.text('m6 r92')) +r6.delete('/res93/:id', (c) => c.text('m6 r93')) +r6.patch('/res94/:id', (c) => c.text('m6 r94')) +r6.get('/res95/:id', (c) => c.text('m6 r95')) +r6.post('/res96/:id', (c) => c.text('m6 r96')) +r6.put('/res97/:id', (c) => c.text('m6 r97')) +r6.delete('/res98/:id', (c) => c.text('m6 r98')) +r6.patch('/res99/:id', (c) => c.text('m6 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod7.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod7.ts new file mode 100644 index 000000000..37d51895b --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod7.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r7 = new Hono() +r7.get('/res0/:id', (c) => c.text('m7 r0')) +r7.post('/res1/:id', (c) => c.text('m7 r1')) +r7.put('/res2/:id', (c) => c.text('m7 r2')) +r7.delete('/res3/:id', (c) => c.text('m7 r3')) +r7.patch('/res4/:id', (c) => c.text('m7 r4')) +r7.get('/res5/:id', (c) => c.text('m7 r5')) +r7.post('/res6/:id', (c) => c.text('m7 r6')) +r7.put('/res7/:id', (c) => c.text('m7 r7')) +r7.delete('/res8/:id', (c) => c.text('m7 r8')) +r7.patch('/res9/:id', (c) => c.text('m7 r9')) +r7.get('/res10/:id', (c) => c.text('m7 r10')) +r7.post('/res11/:id', (c) => c.text('m7 r11')) +r7.put('/res12/:id', (c) => c.text('m7 r12')) +r7.delete('/res13/:id', (c) => c.text('m7 r13')) +r7.patch('/res14/:id', (c) => c.text('m7 r14')) +r7.get('/res15/:id', (c) => c.text('m7 r15')) +r7.post('/res16/:id', (c) => c.text('m7 r16')) +r7.put('/res17/:id', (c) => c.text('m7 r17')) +r7.delete('/res18/:id', (c) => c.text('m7 r18')) +r7.patch('/res19/:id', (c) => c.text('m7 r19')) +r7.get('/res20/:id', (c) => c.text('m7 r20')) +r7.post('/res21/:id', (c) => c.text('m7 r21')) +r7.put('/res22/:id', (c) => c.text('m7 r22')) +r7.delete('/res23/:id', (c) => c.text('m7 r23')) +r7.patch('/res24/:id', (c) => c.text('m7 r24')) +r7.get('/res25/:id', (c) => c.text('m7 r25')) +r7.post('/res26/:id', (c) => c.text('m7 r26')) +r7.put('/res27/:id', (c) => c.text('m7 r27')) +r7.delete('/res28/:id', (c) => c.text('m7 r28')) +r7.patch('/res29/:id', (c) => c.text('m7 r29')) +r7.get('/res30/:id', (c) => c.text('m7 r30')) +r7.post('/res31/:id', (c) => c.text('m7 r31')) +r7.put('/res32/:id', (c) => c.text('m7 r32')) +r7.delete('/res33/:id', (c) => c.text('m7 r33')) +r7.patch('/res34/:id', (c) => c.text('m7 r34')) +r7.get('/res35/:id', (c) => c.text('m7 r35')) +r7.post('/res36/:id', (c) => c.text('m7 r36')) +r7.put('/res37/:id', (c) => c.text('m7 r37')) +r7.delete('/res38/:id', (c) => c.text('m7 r38')) +r7.patch('/res39/:id', (c) => c.text('m7 r39')) +r7.get('/res40/:id', (c) => c.text('m7 r40')) +r7.post('/res41/:id', (c) => c.text('m7 r41')) +r7.put('/res42/:id', (c) => c.text('m7 r42')) +r7.delete('/res43/:id', (c) => c.text('m7 r43')) +r7.patch('/res44/:id', (c) => c.text('m7 r44')) +r7.get('/res45/:id', (c) => c.text('m7 r45')) +r7.post('/res46/:id', (c) => c.text('m7 r46')) +r7.put('/res47/:id', (c) => c.text('m7 r47')) +r7.delete('/res48/:id', (c) => c.text('m7 r48')) +r7.patch('/res49/:id', (c) => c.text('m7 r49')) +r7.get('/res50/:id', (c) => c.text('m7 r50')) +r7.post('/res51/:id', (c) => c.text('m7 r51')) +r7.put('/res52/:id', (c) => c.text('m7 r52')) +r7.delete('/res53/:id', (c) => c.text('m7 r53')) +r7.patch('/res54/:id', (c) => c.text('m7 r54')) +r7.get('/res55/:id', (c) => c.text('m7 r55')) +r7.post('/res56/:id', (c) => c.text('m7 r56')) +r7.put('/res57/:id', (c) => c.text('m7 r57')) +r7.delete('/res58/:id', (c) => c.text('m7 r58')) +r7.patch('/res59/:id', (c) => c.text('m7 r59')) +r7.get('/res60/:id', (c) => c.text('m7 r60')) +r7.post('/res61/:id', (c) => c.text('m7 r61')) +r7.put('/res62/:id', (c) => c.text('m7 r62')) +r7.delete('/res63/:id', (c) => c.text('m7 r63')) +r7.patch('/res64/:id', (c) => c.text('m7 r64')) +r7.get('/res65/:id', (c) => c.text('m7 r65')) +r7.post('/res66/:id', (c) => c.text('m7 r66')) +r7.put('/res67/:id', (c) => c.text('m7 r67')) +r7.delete('/res68/:id', (c) => c.text('m7 r68')) +r7.patch('/res69/:id', (c) => c.text('m7 r69')) +r7.get('/res70/:id', (c) => c.text('m7 r70')) +r7.post('/res71/:id', (c) => c.text('m7 r71')) +r7.put('/res72/:id', (c) => c.text('m7 r72')) +r7.delete('/res73/:id', (c) => c.text('m7 r73')) +r7.patch('/res74/:id', (c) => c.text('m7 r74')) +r7.get('/res75/:id', (c) => c.text('m7 r75')) +r7.post('/res76/:id', (c) => c.text('m7 r76')) +r7.put('/res77/:id', (c) => c.text('m7 r77')) +r7.delete('/res78/:id', (c) => c.text('m7 r78')) +r7.patch('/res79/:id', (c) => c.text('m7 r79')) +r7.get('/res80/:id', (c) => c.text('m7 r80')) +r7.post('/res81/:id', (c) => c.text('m7 r81')) +r7.put('/res82/:id', (c) => c.text('m7 r82')) +r7.delete('/res83/:id', (c) => c.text('m7 r83')) +r7.patch('/res84/:id', (c) => c.text('m7 r84')) +r7.get('/res85/:id', (c) => c.text('m7 r85')) +r7.post('/res86/:id', (c) => c.text('m7 r86')) +r7.put('/res87/:id', (c) => c.text('m7 r87')) +r7.delete('/res88/:id', (c) => c.text('m7 r88')) +r7.patch('/res89/:id', (c) => c.text('m7 r89')) +r7.get('/res90/:id', (c) => c.text('m7 r90')) +r7.post('/res91/:id', (c) => c.text('m7 r91')) +r7.put('/res92/:id', (c) => c.text('m7 r92')) +r7.delete('/res93/:id', (c) => c.text('m7 r93')) +r7.patch('/res94/:id', (c) => c.text('m7 r94')) +r7.get('/res95/:id', (c) => c.text('m7 r95')) +r7.post('/res96/:id', (c) => c.text('m7 r96')) +r7.put('/res97/:id', (c) => c.text('m7 r97')) +r7.delete('/res98/:id', (c) => c.text('m7 r98')) +r7.patch('/res99/:id', (c) => c.text('m7 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod8.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod8.ts new file mode 100644 index 000000000..8ee72ee64 --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod8.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r8 = new Hono() +r8.get('/res0/:id', (c) => c.text('m8 r0')) +r8.post('/res1/:id', (c) => c.text('m8 r1')) +r8.put('/res2/:id', (c) => c.text('m8 r2')) +r8.delete('/res3/:id', (c) => c.text('m8 r3')) +r8.patch('/res4/:id', (c) => c.text('m8 r4')) +r8.get('/res5/:id', (c) => c.text('m8 r5')) +r8.post('/res6/:id', (c) => c.text('m8 r6')) +r8.put('/res7/:id', (c) => c.text('m8 r7')) +r8.delete('/res8/:id', (c) => c.text('m8 r8')) +r8.patch('/res9/:id', (c) => c.text('m8 r9')) +r8.get('/res10/:id', (c) => c.text('m8 r10')) +r8.post('/res11/:id', (c) => c.text('m8 r11')) +r8.put('/res12/:id', (c) => c.text('m8 r12')) +r8.delete('/res13/:id', (c) => c.text('m8 r13')) +r8.patch('/res14/:id', (c) => c.text('m8 r14')) +r8.get('/res15/:id', (c) => c.text('m8 r15')) +r8.post('/res16/:id', (c) => c.text('m8 r16')) +r8.put('/res17/:id', (c) => c.text('m8 r17')) +r8.delete('/res18/:id', (c) => c.text('m8 r18')) +r8.patch('/res19/:id', (c) => c.text('m8 r19')) +r8.get('/res20/:id', (c) => c.text('m8 r20')) +r8.post('/res21/:id', (c) => c.text('m8 r21')) +r8.put('/res22/:id', (c) => c.text('m8 r22')) +r8.delete('/res23/:id', (c) => c.text('m8 r23')) +r8.patch('/res24/:id', (c) => c.text('m8 r24')) +r8.get('/res25/:id', (c) => c.text('m8 r25')) +r8.post('/res26/:id', (c) => c.text('m8 r26')) +r8.put('/res27/:id', (c) => c.text('m8 r27')) +r8.delete('/res28/:id', (c) => c.text('m8 r28')) +r8.patch('/res29/:id', (c) => c.text('m8 r29')) +r8.get('/res30/:id', (c) => c.text('m8 r30')) +r8.post('/res31/:id', (c) => c.text('m8 r31')) +r8.put('/res32/:id', (c) => c.text('m8 r32')) +r8.delete('/res33/:id', (c) => c.text('m8 r33')) +r8.patch('/res34/:id', (c) => c.text('m8 r34')) +r8.get('/res35/:id', (c) => c.text('m8 r35')) +r8.post('/res36/:id', (c) => c.text('m8 r36')) +r8.put('/res37/:id', (c) => c.text('m8 r37')) +r8.delete('/res38/:id', (c) => c.text('m8 r38')) +r8.patch('/res39/:id', (c) => c.text('m8 r39')) +r8.get('/res40/:id', (c) => c.text('m8 r40')) +r8.post('/res41/:id', (c) => c.text('m8 r41')) +r8.put('/res42/:id', (c) => c.text('m8 r42')) +r8.delete('/res43/:id', (c) => c.text('m8 r43')) +r8.patch('/res44/:id', (c) => c.text('m8 r44')) +r8.get('/res45/:id', (c) => c.text('m8 r45')) +r8.post('/res46/:id', (c) => c.text('m8 r46')) +r8.put('/res47/:id', (c) => c.text('m8 r47')) +r8.delete('/res48/:id', (c) => c.text('m8 r48')) +r8.patch('/res49/:id', (c) => c.text('m8 r49')) +r8.get('/res50/:id', (c) => c.text('m8 r50')) +r8.post('/res51/:id', (c) => c.text('m8 r51')) +r8.put('/res52/:id', (c) => c.text('m8 r52')) +r8.delete('/res53/:id', (c) => c.text('m8 r53')) +r8.patch('/res54/:id', (c) => c.text('m8 r54')) +r8.get('/res55/:id', (c) => c.text('m8 r55')) +r8.post('/res56/:id', (c) => c.text('m8 r56')) +r8.put('/res57/:id', (c) => c.text('m8 r57')) +r8.delete('/res58/:id', (c) => c.text('m8 r58')) +r8.patch('/res59/:id', (c) => c.text('m8 r59')) +r8.get('/res60/:id', (c) => c.text('m8 r60')) +r8.post('/res61/:id', (c) => c.text('m8 r61')) +r8.put('/res62/:id', (c) => c.text('m8 r62')) +r8.delete('/res63/:id', (c) => c.text('m8 r63')) +r8.patch('/res64/:id', (c) => c.text('m8 r64')) +r8.get('/res65/:id', (c) => c.text('m8 r65')) +r8.post('/res66/:id', (c) => c.text('m8 r66')) +r8.put('/res67/:id', (c) => c.text('m8 r67')) +r8.delete('/res68/:id', (c) => c.text('m8 r68')) +r8.patch('/res69/:id', (c) => c.text('m8 r69')) +r8.get('/res70/:id', (c) => c.text('m8 r70')) +r8.post('/res71/:id', (c) => c.text('m8 r71')) +r8.put('/res72/:id', (c) => c.text('m8 r72')) +r8.delete('/res73/:id', (c) => c.text('m8 r73')) +r8.patch('/res74/:id', (c) => c.text('m8 r74')) +r8.get('/res75/:id', (c) => c.text('m8 r75')) +r8.post('/res76/:id', (c) => c.text('m8 r76')) +r8.put('/res77/:id', (c) => c.text('m8 r77')) +r8.delete('/res78/:id', (c) => c.text('m8 r78')) +r8.patch('/res79/:id', (c) => c.text('m8 r79')) +r8.get('/res80/:id', (c) => c.text('m8 r80')) +r8.post('/res81/:id', (c) => c.text('m8 r81')) +r8.put('/res82/:id', (c) => c.text('m8 r82')) +r8.delete('/res83/:id', (c) => c.text('m8 r83')) +r8.patch('/res84/:id', (c) => c.text('m8 r84')) +r8.get('/res85/:id', (c) => c.text('m8 r85')) +r8.post('/res86/:id', (c) => c.text('m8 r86')) +r8.put('/res87/:id', (c) => c.text('m8 r87')) +r8.delete('/res88/:id', (c) => c.text('m8 r88')) +r8.patch('/res89/:id', (c) => c.text('m8 r89')) +r8.get('/res90/:id', (c) => c.text('m8 r90')) +r8.post('/res91/:id', (c) => c.text('m8 r91')) +r8.put('/res92/:id', (c) => c.text('m8 r92')) +r8.delete('/res93/:id', (c) => c.text('m8 r93')) +r8.patch('/res94/:id', (c) => c.text('m8 r94')) +r8.get('/res95/:id', (c) => c.text('m8 r95')) +r8.post('/res96/:id', (c) => c.text('m8 r96')) +r8.put('/res97/:id', (c) => c.text('m8 r97')) +r8.delete('/res98/:id', (c) => c.text('m8 r98')) +r8.patch('/res99/:id', (c) => c.text('m8 r99')) diff --git a/graph/test/typescript/hono/cases/scale/routes-2k/src/mod9.ts b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod9.ts new file mode 100644 index 000000000..3dfcf492f --- /dev/null +++ b/graph/test/typescript/hono/cases/scale/routes-2k/src/mod9.ts @@ -0,0 +1,103 @@ +import { Hono } from 'hono' + +export const r9 = new Hono() +r9.get('/res0/:id', (c) => c.text('m9 r0')) +r9.post('/res1/:id', (c) => c.text('m9 r1')) +r9.put('/res2/:id', (c) => c.text('m9 r2')) +r9.delete('/res3/:id', (c) => c.text('m9 r3')) +r9.patch('/res4/:id', (c) => c.text('m9 r4')) +r9.get('/res5/:id', (c) => c.text('m9 r5')) +r9.post('/res6/:id', (c) => c.text('m9 r6')) +r9.put('/res7/:id', (c) => c.text('m9 r7')) +r9.delete('/res8/:id', (c) => c.text('m9 r8')) +r9.patch('/res9/:id', (c) => c.text('m9 r9')) +r9.get('/res10/:id', (c) => c.text('m9 r10')) +r9.post('/res11/:id', (c) => c.text('m9 r11')) +r9.put('/res12/:id', (c) => c.text('m9 r12')) +r9.delete('/res13/:id', (c) => c.text('m9 r13')) +r9.patch('/res14/:id', (c) => c.text('m9 r14')) +r9.get('/res15/:id', (c) => c.text('m9 r15')) +r9.post('/res16/:id', (c) => c.text('m9 r16')) +r9.put('/res17/:id', (c) => c.text('m9 r17')) +r9.delete('/res18/:id', (c) => c.text('m9 r18')) +r9.patch('/res19/:id', (c) => c.text('m9 r19')) +r9.get('/res20/:id', (c) => c.text('m9 r20')) +r9.post('/res21/:id', (c) => c.text('m9 r21')) +r9.put('/res22/:id', (c) => c.text('m9 r22')) +r9.delete('/res23/:id', (c) => c.text('m9 r23')) +r9.patch('/res24/:id', (c) => c.text('m9 r24')) +r9.get('/res25/:id', (c) => c.text('m9 r25')) +r9.post('/res26/:id', (c) => c.text('m9 r26')) +r9.put('/res27/:id', (c) => c.text('m9 r27')) +r9.delete('/res28/:id', (c) => c.text('m9 r28')) +r9.patch('/res29/:id', (c) => c.text('m9 r29')) +r9.get('/res30/:id', (c) => c.text('m9 r30')) +r9.post('/res31/:id', (c) => c.text('m9 r31')) +r9.put('/res32/:id', (c) => c.text('m9 r32')) +r9.delete('/res33/:id', (c) => c.text('m9 r33')) +r9.patch('/res34/:id', (c) => c.text('m9 r34')) +r9.get('/res35/:id', (c) => c.text('m9 r35')) +r9.post('/res36/:id', (c) => c.text('m9 r36')) +r9.put('/res37/:id', (c) => c.text('m9 r37')) +r9.delete('/res38/:id', (c) => c.text('m9 r38')) +r9.patch('/res39/:id', (c) => c.text('m9 r39')) +r9.get('/res40/:id', (c) => c.text('m9 r40')) +r9.post('/res41/:id', (c) => c.text('m9 r41')) +r9.put('/res42/:id', (c) => c.text('m9 r42')) +r9.delete('/res43/:id', (c) => c.text('m9 r43')) +r9.patch('/res44/:id', (c) => c.text('m9 r44')) +r9.get('/res45/:id', (c) => c.text('m9 r45')) +r9.post('/res46/:id', (c) => c.text('m9 r46')) +r9.put('/res47/:id', (c) => c.text('m9 r47')) +r9.delete('/res48/:id', (c) => c.text('m9 r48')) +r9.patch('/res49/:id', (c) => c.text('m9 r49')) +r9.get('/res50/:id', (c) => c.text('m9 r50')) +r9.post('/res51/:id', (c) => c.text('m9 r51')) +r9.put('/res52/:id', (c) => c.text('m9 r52')) +r9.delete('/res53/:id', (c) => c.text('m9 r53')) +r9.patch('/res54/:id', (c) => c.text('m9 r54')) +r9.get('/res55/:id', (c) => c.text('m9 r55')) +r9.post('/res56/:id', (c) => c.text('m9 r56')) +r9.put('/res57/:id', (c) => c.text('m9 r57')) +r9.delete('/res58/:id', (c) => c.text('m9 r58')) +r9.patch('/res59/:id', (c) => c.text('m9 r59')) +r9.get('/res60/:id', (c) => c.text('m9 r60')) +r9.post('/res61/:id', (c) => c.text('m9 r61')) +r9.put('/res62/:id', (c) => c.text('m9 r62')) +r9.delete('/res63/:id', (c) => c.text('m9 r63')) +r9.patch('/res64/:id', (c) => c.text('m9 r64')) +r9.get('/res65/:id', (c) => c.text('m9 r65')) +r9.post('/res66/:id', (c) => c.text('m9 r66')) +r9.put('/res67/:id', (c) => c.text('m9 r67')) +r9.delete('/res68/:id', (c) => c.text('m9 r68')) +r9.patch('/res69/:id', (c) => c.text('m9 r69')) +r9.get('/res70/:id', (c) => c.text('m9 r70')) +r9.post('/res71/:id', (c) => c.text('m9 r71')) +r9.put('/res72/:id', (c) => c.text('m9 r72')) +r9.delete('/res73/:id', (c) => c.text('m9 r73')) +r9.patch('/res74/:id', (c) => c.text('m9 r74')) +r9.get('/res75/:id', (c) => c.text('m9 r75')) +r9.post('/res76/:id', (c) => c.text('m9 r76')) +r9.put('/res77/:id', (c) => c.text('m9 r77')) +r9.delete('/res78/:id', (c) => c.text('m9 r78')) +r9.patch('/res79/:id', (c) => c.text('m9 r79')) +r9.get('/res80/:id', (c) => c.text('m9 r80')) +r9.post('/res81/:id', (c) => c.text('m9 r81')) +r9.put('/res82/:id', (c) => c.text('m9 r82')) +r9.delete('/res83/:id', (c) => c.text('m9 r83')) +r9.patch('/res84/:id', (c) => c.text('m9 r84')) +r9.get('/res85/:id', (c) => c.text('m9 r85')) +r9.post('/res86/:id', (c) => c.text('m9 r86')) +r9.put('/res87/:id', (c) => c.text('m9 r87')) +r9.delete('/res88/:id', (c) => c.text('m9 r88')) +r9.patch('/res89/:id', (c) => c.text('m9 r89')) +r9.get('/res90/:id', (c) => c.text('m9 r90')) +r9.post('/res91/:id', (c) => c.text('m9 r91')) +r9.put('/res92/:id', (c) => c.text('m9 r92')) +r9.delete('/res93/:id', (c) => c.text('m9 r93')) +r9.patch('/res94/:id', (c) => c.text('m9 r94')) +r9.get('/res95/:id', (c) => c.text('m9 r95')) +r9.post('/res96/:id', (c) => c.text('m9 r96')) +r9.put('/res97/:id', (c) => c.text('m9 r97')) +r9.delete('/res98/:id', (c) => c.text('m9 r98')) +r9.patch('/res99/:id', (c) => c.text('m9 r99')) diff --git a/graph/test/typescript/hono/cases/zod/composition/src/index.ts b/graph/test/typescript/hono/cases/zod/composition/src/index.ts new file mode 100644 index 000000000..ea3722945 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/composition/src/index.ts @@ -0,0 +1,27 @@ +// census: zvalidator (SPEC 3.9 composition) +// A route validating a DERIVED schema is reached from its BASE: extend, merge, pick, omit, partial, +// z.array(Base), and .openapi('Name') metadata (still the same schema). +import { Hono } from 'hono' +import { zValidator } from '@hono/zod-validator' +import { z } from '@hono/zod-openapi' + +const Base = z.object({ id: z.string(), name: z.string(), age: z.number() }) +const Extra = z.object({ tag: z.string() }) +const Extended = Base.extend({ email: z.string() }) +const Merged = Base.merge(Extra) +const Picked = Base.pick({ id: true }) +const Omitted = Base.omit({ age: true }) +const Partial = Base.partial() +const Many = z.array(Base) +const Named = Base.openapi('Person') + +const app = new Hono() +app.post('/extended', zValidator('json', Extended), (c) => c.json(c.req.valid('json'))) +app.post('/merged', zValidator('json', Merged), (c) => c.json(c.req.valid('json'))) +app.post('/picked', zValidator('json', Picked), (c) => c.json(c.req.valid('json'))) +app.post('/omitted', zValidator('json', Omitted), (c) => c.json(c.req.valid('json'))) +app.patch('/partial', zValidator('json', Partial), (c) => c.json(c.req.valid('json'))) +app.put('/many', zValidator('json', Many), (c) => c.json(c.req.valid('json'))) +app.post('/named', zValidator('json', Named), (c) => c.json(c.req.valid('json'))) + +export default app diff --git a/graph/test/typescript/hono/cases/zod/decl-forms/src/index.ts b/graph/test/typescript/hono/cases/zod/decl-forms/src/index.ts new file mode 100644 index 000000000..02bc69864 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/decl-forms/src/index.ts @@ -0,0 +1,21 @@ +// census: zvalidator, req_valid (SPEC 3.9 declaration forms) +// The schema DECLARATION is found through inline, local, named, default, namespace and barrel forms. +import { Hono } from 'hono' +import { zValidator } from '@hono/zod-validator' +import { z } from 'zod' +import { User } from './schemas/user' +import Settings from './schemas/user' +import * as q from './schemas/query' +import { BarrelUser } from './schemas' + +const Local = z.object({ id: z.string() }) + +const app = new Hono() +app.post('/inline', zValidator('json', z.object({ x: z.number() })), (c) => c.json(c.req.valid('json'))) +app.post('/local', zValidator('json', Local), (c) => c.json(c.req.valid('json'))) +app.post('/named', zValidator('json', User), (c) => c.json(c.req.valid('json'))) +app.post('/default', zValidator('json', Settings), (c) => c.json(c.req.valid('json'))) +app.get('/namespace', zValidator('query', q.Paging), (c) => c.json(c.req.valid('query'))) +app.post('/barrel', zValidator('json', BarrelUser), (c) => c.json(c.req.valid('json'))) + +export default app diff --git a/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/index.ts b/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/index.ts new file mode 100644 index 000000000..b90b10f83 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/index.ts @@ -0,0 +1 @@ +export { User as BarrelUser } from './user' diff --git a/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/query.ts b/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/query.ts new file mode 100644 index 000000000..44f45e462 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/query.ts @@ -0,0 +1,3 @@ +import { z } from 'zod' + +export const Paging = z.object({ page: z.string() }) diff --git a/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/user.ts b/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/user.ts new file mode 100644 index 000000000..3c20378b4 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/decl-forms/src/schemas/user.ts @@ -0,0 +1,6 @@ +import { z } from 'zod' + +export const User = z.object({ name: z.string() }) + +const Settings = z.object({ theme: z.string() }) +export default Settings diff --git a/graph/test/typescript/hono/cases/zod/no-route/src/forms.ts b/graph/test/typescript/hono/cases/zod/no-route/src/forms.ts new file mode 100644 index 000000000..807ec1bc2 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/no-route/src/forms.ts @@ -0,0 +1,14 @@ +// census: zvalidator (negative partition: zod with no Hono route, SPEC 3.9) +// zod used for plain parsing in a project that has no Hono app: zero route_* rows of any kind. +import { z } from 'zod' + +export const Signup = z.object({ email: z.string(), password: z.string() }) + +export function parseSignup(input: unknown) { + return Signup.parse(input) +} + +export const Profile = Signup.omit({ password: true }).extend({ bio: z.string() }) +export function parseProfile(input: unknown) { + return Profile.safeParse(input) +} diff --git a/graph/test/typescript/hono/cases/zod/specifiers/src/index.ts b/graph/test/typescript/hono/cases/zod/specifiers/src/index.ts new file mode 100644 index 000000000..1b20b1d77 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/specifiers/src/index.ts @@ -0,0 +1,26 @@ +// census: zvalidator, req_valid (SPEC 3.9 import forms: zod, zod/v4, zod/v3, zod/v4-mini, @hono/zod-openapi's z) +// The same validator shape with `z` taken from every specifier the corpus uses. +import { Hono } from 'hono' +import { zValidator } from '@hono/zod-validator' +import { validator } from 'hono/validator' +import { z } from 'zod' +import { z as z4 } from 'zod/v4' +import { z as z3 } from 'zod/v3' +import * as zm from 'zod/v4-mini' +import { z as zo } from '@hono/zod-openapi' + +const FromZod = z.object({ a: z.string() }) +const FromV4 = z4.object({ b: z4.string() }) +const FromV3 = z3.object({ c: z3.string() }) +const FromMini = zm.object({ d: zm.string() }) +const FromOpenapi = zo.object({ e: zo.string() }) + +const app = new Hono() +app.post('/zod', zValidator('json', FromZod), (c) => c.json(c.req.valid('json'))) +app.post('/v4', zValidator('json', FromV4), (c) => c.json(c.req.valid('json'))) +app.post('/v3', zValidator('json', FromV3), (c) => c.json(c.req.valid('json'))) +app.post('/mini', zValidator('json', FromMini), (c) => c.json(c.req.valid('json'))) +app.post('/fn', validator('json', (v) => zm.parse(FromMini, v)), (c) => c.json(c.req.valid('json'))) +app.post('/openapi-z', zValidator('json', FromOpenapi), (c) => c.json(c.req.valid('json'))) + +export default app diff --git a/graph/test/typescript/hono/cases/zod/valid-targets/src/index.ts b/graph/test/typescript/hono/cases/zod/valid-targets/src/index.ts new file mode 100644 index 000000000..dc1f92b82 --- /dev/null +++ b/graph/test/typescript/hono/cases/zod/valid-targets/src/index.ts @@ -0,0 +1,35 @@ +// census: req_valid, zvalidator, validator_builtin (SPEC 3.9 targets) +// c.req.valid(target) for every target links to that target's validator on the same route; a target with +// no validator on the route is declared (valid_without_validator). +import { Hono } from 'hono' +import { zValidator } from '@hono/zod-validator' +import { z } from 'zod' + +const J = z.object({ j: z.string() }) +const Q = z.object({ q: z.string() }) +const P = z.object({ id: z.string() }) +const F = z.object({ f: z.string() }) +const H = z.object({ h: z.string() }) +const K = z.object({ k: z.string() }) + +const app = new Hono() +app.post( + '/all/:id', + zValidator('json', J), + zValidator('query', Q), + zValidator('param', P), + zValidator('form', F), + zValidator('header', H), + zValidator('cookie', K), + (c) => { + const all = [c.req.valid('json'), c.req.valid('query'), c.req.valid('param'), c.req.valid('form'), c.req.valid('header'), c.req.valid('cookie')] + return c.json(all) + } +) +app.get('/missing', zValidator('query', Q), (c) => { + // @ts-expect-error -- no json validator on this route: the read is declared, not linked + const body = c.req.valid('json') + return c.json([c.req.valid('query'), body]) +}) + +export default app diff --git a/graph/test/typescript/hono/expected/chains/ctx-partial-route.chains b/graph/test/typescript/hono/expected/chains/ctx-partial-route.chains new file mode 100644 index 000000000..68e2c3327 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-partial-route.chains @@ -0,0 +1,25 @@ +# hand-reviewed 2026-10-28 against the fixture, the compiler call-chain oracle and the runtime trace: R18 on partial routes: the handlers read the service out of the context typed by the sub-app Env (destructured c.get, const x = c.var.k then a member call); service -> repository -> db. The provider -> handler hop is the partial route decidable chain (mwp). At run time API_BASE is unset, so the chains are requested at the un-rebased path +# census: ctx_di on a rebased root (SPEC R18 on a PARTIAL route: http_route_partial, dynamic_mount_prefix) +fn app.ts:10:16 +fn app.ts:14:19 +fn app.ts:18:22 +fn app.ts:27:3 +fn app.ts:30:3 +fn users.ts:10:3 +fn users.ts:17:3 +fn users.ts:20:3 +fn users.ts:23:3 +fn users.ts:30:3 +fn users.ts:33:3 +fn users.ts:36:3 +fn users.ts:7:3 +edge app.ts:10:16 users.ts:17:3 +edge app.ts:10:16 users.ts:30:3 +edge app.ts:14:19 users.ts:33:3 +edge app.ts:18:22 users.ts:36:3 +edge users.ts:20:3 users.ts:7:3 +edge users.ts:23:3 users.ts:10:3 +edge users.ts:33:3 users.ts:20:3 +edge users.ts:36:3 users.ts:23:3 +chain user-find GET /users/x1 app.ts:10:16 app.ts:14:19 users.ts:33:3 users.ts:20:3 users.ts:7:3 +chain user-remove DELETE /users/x1 app.ts:10:16 app.ts:18:22 users.ts:36:3 users.ts:23:3 users.ts:10:3 diff --git a/graph/test/typescript/hono/expected/chains/ctx-partial-route.entries b/graph/test/typescript/hono/expected/chains/ctx-partial-route.entries new file mode 100644 index 000000000..f36caac83 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-partial-route.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: chains fixture (R18 on PARTIAL routes): the served root is rebased by a run-time prefix in a server holder, so both sub-app routes are partial dynamic_mount_prefix with their decidable chain (the provider at 0) +# census: ctx_di on a rebased root (SPEC R18 on a PARTIAL route: http_route_partial, dynamic_mount_prefix) +entry app.ts:10:16 http +entry app.ts:14:19 http +entry app.ts:18:22 http diff --git a/graph/test/typescript/hono/expected/chains/ctx-partial-route.tsv b/graph/test/typescript/hono/expected/chains/ctx-partial-route.tsv new file mode 100644 index 000000000..eaad55342 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-partial-route.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: chains fixture (R18 on PARTIAL routes): the served root is rebased by a run-time prefix in a server holder, so both sub-app routes are partial dynamic_mount_prefix with their decidable chain (the provider at 0) +# census: ctx_di on a rebased root (SPEC R18 on a PARTIAL route: http_route_partial, dynamic_mount_prefix) +# R23 (2026-10-29): re-derived; the provider is in both decided chains, so its services key flows to both handlers (2 ctx rows added); every other row unchanged +ctx app.ts:10:16 app.ts:14:19 services +ctx app.ts:10:16 app.ts:18:22 services +partial app.ts:14:19 GET dynamic_mount_prefix +partial app.ts:18:22 DELETE dynamic_mount_prefix +mwp app.ts:10:16 app.ts:14:19 GET 0 +mwp app.ts:10:16 app.ts:18:22 DELETE 0 +unknown app.ts:40:1 dynamic_mount_prefix app.ts:14:19 +unknown app.ts:40:1 dynamic_mount_prefix app.ts:18:22 diff --git a/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.chains b/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.chains new file mode 100644 index 000000000..82a87e138 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.chains @@ -0,0 +1,20 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: R23 + R18 setter-type form on partial routes: with no Env, c.get(k) / c.var.k take the type of the decided-chain setter value (OrderService); the compiler types them any and the run-time trace observes handler -> service (rt); service -> repository is static. The root scoped middleware ran at run time (the unset variable gives /api/orders) but is no chain hop: statically it only may apply. At run time ORDERS_PREFIX is unset, so the chains are requested under the default +# census: ctx_di on a rebased root, untyped (SPEC R23 with R18 setter-type form, on PARTIAL routes) +fn app.ts:12:21 +fn app.ts:16:22 +fn app.ts:21:19 +fn app.ts:8:17 +fn orders.ts:10:3 +fn orders.ts:13:3 +fn orders.ts:16:3 +fn orders.ts:23:3 +fn orders.ts:26:3 +fn orders.ts:29:3 +edge app.ts:8:17 orders.ts:10:3 +edge app.ts:8:17 orders.ts:23:3 +edge orders.ts:26:3 orders.ts:13:3 +edge orders.ts:29:3 orders.ts:16:3 +edge app.ts:12:21 orders.ts:26:3 rt +edge app.ts:16:22 orders.ts:29:3 rt +chain orders-list GET /api/orders/list app.ts:8:17 app.ts:12:21 orders.ts:26:3 orders.ts:13:3 +chain orders-total GET /api/orders/total app.ts:8:17 app.ts:16:22 orders.ts:29:3 orders.ts:16:3 diff --git a/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.entries b/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.entries new file mode 100644 index 000000000..83f95fd0b --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R23: the sub-app provider is in both partial routes decided chain (mwp 0) and its orders key flows to both handlers; the root scoped use only may apply (partial_route_scope), so its tenant key gives no flow and the /list reader is no_setter_on_chain +# census: ctx_di on a rebased root, untyped (SPEC R23 with R18 setter-type form, on PARTIAL routes) +entry app.ts:12:21 http +entry app.ts:16:22 http +entry app.ts:21:19 http +entry app.ts:8:17 http diff --git a/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.tsv b/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.tsv new file mode 100644 index 000000000..1198f4cd2 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-partial-untyped.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R23: the sub-app provider is in both partial routes decided chain (mwp 0) and its orders key flows to both handlers; the root scoped use only may apply (partial_route_scope), so its tenant key gives no flow and the /list reader is no_setter_on_chain +# census: ctx_di on a rebased root, untyped (SPEC R23 with R18 setter-type form, on PARTIAL routes) +ctx app.ts:8:17 app.ts:12:21 orders +ctx app.ts:8:17 app.ts:16:22 orders +partial app.ts:12:21 GET dynamic_mount_prefix +partial app.ts:16:22 GET dynamic_mount_prefix +mwp app.ts:8:17 app.ts:12:21 GET 0 +mwp app.ts:8:17 app.ts:16:22 GET 0 +unknown app.ts:12:21 no_setter_on_chain app.ts:12:21 +unknown app.ts:26:1 dynamic_mount_prefix app.ts:12:21 +unknown app.ts:26:1 dynamic_mount_prefix app.ts:16:22 +unknown app.ts:26:1 partial_route_scope app.ts:21:19 diff --git a/graph/test/typescript/hono/expected/chains/ctx-services-typed.chains b/graph/test/typescript/hono/expected/chains/ctx-services-typed.chains new file mode 100644 index 000000000..a12ef825d --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-services-typed.chains @@ -0,0 +1,38 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: R18: services read from the context (c.get destructured, c.var.k, const x = c.var.k, c.get(k).m()) through every Env form reach service -> repository -> db +# census: ctx_di (SPEC R18; call-chain break class 1) +fn app.ts:16:23 +fn app.ts:21:51 +fn app.ts:26:15 +fn db.ts:7:3 +fn handlers.ts:11:1 +fn handlers.ts:5:1 +fn repos.ts:15:3 +fn repos.ts:18:3 +fn repos.ts:5:3 +fn repos.ts:8:3 +fn services.ts:15:3 +fn services.ts:18:3 +fn services.ts:24:3 +fn services.ts:5:3 +fn services.ts:8:3 +fn wire.ts:12:48 +fn wire.ts:19:52 +edge app.ts:16:23 services.ts:8:3 +edge app.ts:21:51 services.ts:8:3 +edge app.ts:26:15 repos.ts:5:3 +edge app.ts:26:15 services.ts:5:3 +edge handlers.ts:11:1 services.ts:8:3 +edge handlers.ts:5:1 services.ts:18:3 +edge repos.ts:18:3 db.ts:7:3 +edge repos.ts:8:3 db.ts:7:3 +edge services.ts:18:3 repos.ts:18:3 +edge services.ts:8:3 repos.ts:8:3 +edge wire.ts:12:48 repos.ts:15:3 +edge wire.ts:12:48 repos.ts:5:3 +edge wire.ts:12:48 services.ts:15:3 +edge wire.ts:12:48 services.ts:5:3 +edge wire.ts:19:52 services.ts:24:3 +chain keys-verify GET /keys/abc wire.ts:12:48 wire.ts:19:52 handlers.ts:5:1 services.ts:18:3 repos.ts:18:3 db.ts:7:3 +chain users-inline-get GET /users/u1 wire.ts:12:48 app.ts:16:23 services.ts:8:3 repos.ts:8:3 db.ts:7:3 +chain factory-handlers-var GET /f/whoami/u1 wire.ts:12:48 app.ts:21:51 services.ts:8:3 repos.ts:8:3 db.ts:7:3 +chain interface-env-const-var GET /i/u/u1 wire.ts:12:48 app.ts:26:15 handlers.ts:11:1 services.ts:8:3 repos.ts:8:3 db.ts:7:3 diff --git a/graph/test/typescript/hono/expected/chains/ctx-services-typed.entries b/graph/test/typescript/hono/expected/chains/ctx-services-typed.entries new file mode 100644 index 000000000..fe25753a8 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-services-typed.entries @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R18 chains fixture: routes, middleware chains, ctx flows +# census: ctx_di (SPEC R18) +entry app.ts:16:23 http +entry app.ts:21:51 http +entry app.ts:26:15 http +entry handlers.ts:11:1 http +entry handlers.ts:5:1 http +entry wire.ts:12:48 http +entry wire.ts:19:52 http diff --git a/graph/test/typescript/hono/expected/chains/ctx-services-typed.tsv b/graph/test/typescript/hono/expected/chains/ctx-services-typed.tsv new file mode 100644 index 000000000..ee92c4051 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-services-typed.tsv @@ -0,0 +1,24 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R18 chains fixture: routes, middleware chains, ctx flows +# census: ctx_di (SPEC R18) +route GET /keys/:key handlers.ts:5:1 app.ts:10:13 2 +route GET /users/:id app.ts:16:23 app.ts:10:13 3 +route GET /f/whoami/:id app.ts:21:51 app.ts:10:13 5 +route GET /i/u/:id handlers.ts:11:1 app.ts:10:13 7 +mw wire.ts:12:48 handlers.ts:5:1 GET /keys/:key 0 app.ts:10:13 +mw wire.ts:19:52 handlers.ts:5:1 GET /keys/:key 1 app.ts:10:13 +mw wire.ts:12:48 app.ts:16:23 GET /users/:id 0 app.ts:10:13 +mw wire.ts:12:48 app.ts:21:51 GET /f/whoami/:id 0 app.ts:10:13 +mw wire.ts:12:48 app.ts:21:51 GET /f/whoami/:id 1 app.ts:10:13 +mw wire.ts:12:48 handlers.ts:11:1 GET /i/u/:id 0 app.ts:10:13 +mw app.ts:26:15 handlers.ts:11:1 GET /i/u/:id 1 app.ts:10:13 +ctx app.ts:26:15 handlers.ts:11:1 users +ctx wire.ts:12:48 app.ts:16:23 services +ctx wire.ts:12:48 app.ts:21:51 services +ctx wire.ts:12:48 handlers.ts:5:1 services +ctx wire.ts:12:48 wire.ts:19:52 audit +submount /f app.ts:22:5 +submount /i app.ts:31:5 +regby app.ts:1:1 app.ts:16:23 GET /users/:id app.ts:10:13 +regby app.ts:1:1 app.ts:21:51 GET /f/whoami/:id app.ts:10:13 +regby app.ts:1:1 handlers.ts:11:1 GET /i/u/:id app.ts:10:13 +regby app.ts:1:1 handlers.ts:5:1 GET /keys/:key app.ts:10:13 diff --git a/graph/test/typescript/hono/expected/chains/ctx-set-untyped.chains b/graph/test/typescript/hono/expected/chains/ctx-set-untyped.chains new file mode 100644 index 000000000..93e87e877 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-set-untyped.chains @@ -0,0 +1,22 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: R18 untyped form: with no Env type (c: any, Hono), c.get(k) / c.var.k take the c.set value's type; the calls are observed at run time (rt), the compiler types them any +# census: ctx_di (SPEC R18 untyped; call-chain break class 1) +fn app.ts:10:25 +fn app.ts:17:18 +fn app.ts:21:23 +fn app.ts:6:22 +fn orders.ts:11:3 +fn orders.ts:14:3 +fn orders.ts:21:3 +fn orders.ts:24:3 +fn orders.ts:27:3 +fn orders.ts:8:3 +edge app.ts:17:18 orders.ts:21:3 +edge app.ts:17:18 orders.ts:8:3 +edge app.ts:6:22 orders.ts:21:3 +edge app.ts:6:22 orders.ts:8:3 +edge orders.ts:24:3 orders.ts:11:3 +edge orders.ts:27:3 orders.ts:14:3 +edge app.ts:10:25 orders.ts:24:3 rt +edge app.ts:21:23 orders.ts:27:3 rt +chain orders-list GET /orders/list app.ts:6:22 app.ts:10:25 orders.ts:24:3 orders.ts:11:3 +chain reports-total GET /reports/total app.ts:17:18 app.ts:21:23 orders.ts:27:3 orders.ts:14:3 diff --git a/graph/test/typescript/hono/expected/chains/ctx-set-untyped.entries b/graph/test/typescript/hono/expected/chains/ctx-set-untyped.entries new file mode 100644 index 000000000..02eb7f7d7 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-set-untyped.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (ctx_di (SPEC R18 untyped; call-chain break class 1)): routes, middleware chains, ctx flows +# census: ctx_di (SPEC R18 untyped; call-chain break class 1) +entry app.ts:10:25 http +entry app.ts:17:18 http +entry app.ts:21:23 http +entry app.ts:6:22 http diff --git a/graph/test/typescript/hono/expected/chains/ctx-set-untyped.tsv b/graph/test/typescript/hono/expected/chains/ctx-set-untyped.tsv new file mode 100644 index 000000000..73fcc9308 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/ctx-set-untyped.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (ctx_di (SPEC R18 untyped; call-chain break class 1)): routes, middleware chains, ctx flows +# census: ctx_di (SPEC R18 untyped; call-chain break class 1) +route GET /orders/list app.ts:10:25 app.ts:5:13 1 +route GET /reports/total app.ts:21:23 app.ts:5:13 3 +mw app.ts:6:22 app.ts:10:25 GET /orders/list 0 app.ts:5:13 +mw app.ts:17:18 app.ts:21:23 GET /reports/total 0 app.ts:5:13 +ctx app.ts:17:18 app.ts:21:23 orders +ctx app.ts:6:22 app.ts:10:25 orders +submount /reports app.ts:22:5 +regby app.ts:1:1 app.ts:10:25 GET /orders/list app.ts:5:13 +regby app.ts:1:1 app.ts:21:23 GET /reports/total app.ts:5:13 diff --git a/graph/test/typescript/hono/expected/chains/function-values.chains b/graph/test/typescript/hono/expected/chains/function-values.chains new file mode 100644 index 000000000..bc80bbbce --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/function-values.chains @@ -0,0 +1,42 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: R21: callbacks, handler tables (literal and const keys), returned functions, options-object functions, array elements and bound methods reach their targets (rt where the compiler sees only a signature); a table read with an undecided key is a declared unknown +# census: fn_value (SPEC R21; call-chain break class 2) +fn app.ts:10:23 +fn app.ts:12:23 +fn app.ts:14:21 +fn app.ts:16:26 +fn app.ts:18:22 +fn app.ts:23:25 +fn app.ts:8:23 +fn app.ts:8:50 +fn ops.ts:12:1 +fn ops.ts:18:1 +fn ops.ts:24:1 +fn ops.ts:25:10 +fn ops.ts:28:1 +fn ops.ts:32:1 +fn ops.ts:40:3 +fn ops.ts:43:3 +fn ops.ts:6:1 +fn ops.ts:9:1 +edge app.ts:10:23 ops.ts:6:1 +edge app.ts:10:23 ops.ts:9:1 +edge app.ts:12:23 ops.ts:12:1 +edge app.ts:12:23 ops.ts:24:1 +edge app.ts:12:23 ops.ts:25:10 +edge app.ts:14:21 ops.ts:28:1 +edge app.ts:18:22 ops.ts:40:3 +edge app.ts:18:22 ops.ts:43:3 +edge app.ts:8:23 app.ts:8:50 +edge app.ts:8:23 ops.ts:18:1 +edge app.ts:8:50 ops.ts:6:1 +edge app.ts:16:26 ops.ts:9:1 rt +edge ops.ts:18:1 app.ts:8:50 rt +edge ops.ts:25:10 ops.ts:12:1 rt +edge ops.ts:28:1 ops.ts:32:1 rt +chain retry-callback GET /retry/x1 app.ts:8:23 ops.ts:18:1 app.ts:8:50 ops.ts:6:1 +chain table-const-key GET /table/x1 app.ts:10:23 ops.ts:9:1 +chain tryit-returned GET /tryit/x1 app.ts:12:23 ops.ts:25:10 ops.ts:12:1 +chain options-fn GET /options app.ts:14:21 ops.ts:28:1 ops.ts:32:1 +chain array-element GET /pipeline/x1 app.ts:16:26 ops.ts:9:1 +chain bound-method GET /mail/x1 app.ts:18:22 ops.ts:43:3 +ccunknown app.ts:23:25 diff --git a/graph/test/typescript/hono/expected/chains/function-values.entries b/graph/test/typescript/hono/expected/chains/function-values.entries new file mode 100644 index 000000000..b3ed9145c --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/function-values.entries @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (fn_value (SPEC R21; call-chain break class 2)): routes, middleware chains, ctx flows +# census: fn_value (SPEC R21; call-chain break class 2) +entry app.ts:10:23 http +entry app.ts:12:23 http +entry app.ts:14:21 http +entry app.ts:16:26 http +entry app.ts:18:22 http +entry app.ts:23:25 http +entry app.ts:8:23 http diff --git a/graph/test/typescript/hono/expected/chains/function-values.tsv b/graph/test/typescript/hono/expected/chains/function-values.tsv new file mode 100644 index 000000000..5d28c8011 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/function-values.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (fn_value (SPEC R21; call-chain break class 2)): routes, middleware chains, ctx flows +# census: fn_value (SPEC R21; call-chain break class 2) +route GET /retry/:id app.ts:8:23 app.ts:4:13 0 +route GET /table/:id app.ts:10:23 app.ts:4:13 1 +route GET /tryit/:id app.ts:12:23 app.ts:4:13 2 +route GET /options app.ts:14:21 app.ts:4:13 3 +route GET /pipeline/:id app.ts:16:26 app.ts:4:13 4 +route GET /mail/:to app.ts:18:22 app.ts:4:13 5 +route GET /act/:op/:id app.ts:23:25 app.ts:4:13 6 +regby app.ts:1:1 app.ts:10:23 GET /table/:id app.ts:4:13 +regby app.ts:1:1 app.ts:12:23 GET /tryit/:id app.ts:4:13 +regby app.ts:1:1 app.ts:14:21 GET /options app.ts:4:13 +regby app.ts:1:1 app.ts:16:26 GET /pipeline/:id app.ts:4:13 +regby app.ts:1:1 app.ts:18:22 GET /mail/:to app.ts:4:13 +regby app.ts:1:1 app.ts:23:25 GET /act/:op/:id app.ts:4:13 +regby app.ts:1:1 app.ts:8:23 GET /retry/:id app.ts:4:13 diff --git a/graph/test/typescript/hono/expected/chains/library-generic-params.chains b/graph/test/typescript/hono/expected/chains/library-generic-params.chains new file mode 100644 index 000000000..6538e0e68 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/library-generic-params.chains @@ -0,0 +1,58 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: R19: callback parameters typed only by Array.map/reduce, Promise.then, Map.forEach, tuple elements from shift()/Object.entries, and a validator's output reach the project methods +# census: callback_generic (SPEC R19; call-chain break class 3) +fn app.ts:10:18 +fn app.ts:11:20 +fn app.ts:12:23 +fn app.ts:13:19 +fn app.ts:18:21 +fn app.ts:19:3 +fn app.ts:9:19 +fn model.ts:10:3 +fn model.ts:13:3 +fn model.ts:20:3 +fn model.ts:23:3 +fn model.ts:30:3 +fn model.ts:33:3 +fn model.ts:36:3 +fn model.ts:7:3 +fn report.ts:11:1 +fn report.ts:12:31 +fn report.ts:15:1 +fn report.ts:22:1 +fn report.ts:24:17 +fn report.ts:30:1 +fn report.ts:34:1 +fn report.ts:3:1 +fn report.ts:4:29 +fn report.ts:7:1 +fn report.ts:8:32 +edge app.ts:10:18 report.ts:7:1 +edge app.ts:11:20 report.ts:11:1 +edge app.ts:12:23 report.ts:15:1 +edge app.ts:12:23 report.ts:30:1 +edge app.ts:13:19 report.ts:22:1 +edge app.ts:13:19 report.ts:34:1 +edge app.ts:18:21 model.ts:7:3 +edge app.ts:19:3 model.ts:10:3 +edge app.ts:9:19 report.ts:3:1 +edge model.ts:30:3 model.ts:7:3 +edge report.ts:11:1 model.ts:36:3 +edge report.ts:11:1 report.ts:12:31 +edge report.ts:12:31 model.ts:10:3 +edge report.ts:15:1 model.ts:23:3 +edge report.ts:22:1 report.ts:24:17 +edge report.ts:24:17 model.ts:13:3 +edge report.ts:30:1 model.ts:20:3 +edge report.ts:34:1 model.ts:7:3 +edge report.ts:3:1 model.ts:33:3 +edge report.ts:3:1 report.ts:4:29 +edge report.ts:4:29 model.ts:10:3 +edge report.ts:7:1 model.ts:33:3 +edge report.ts:7:1 report.ts:8:32 +edge report.ts:8:32 model.ts:13:3 +chain roles-map GET /roles app.ts:9:19 report.ts:3:1 report.ts:4:29 model.ts:10:3 +chain rank-reduce GET /rank app.ts:10:18 report.ts:7:1 report.ts:8:32 model.ts:13:3 +chain latest-then GET /latest app.ts:11:20 report.ts:11:1 report.ts:12:31 model.ts:10:3 +chain providers-tuple GET /providers app.ts:12:23 report.ts:15:1 model.ts:23:3 +chain names-map-foreach GET /names app.ts:13:19 report.ts:22:1 report.ts:24:17 model.ts:13:3 +chain validator-output - - app.ts:19:3 model.ts:10:3 diff --git a/graph/test/typescript/hono/expected/chains/library-generic-params.entries b/graph/test/typescript/hono/expected/chains/library-generic-params.entries new file mode 100644 index 000000000..eed3f910e --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/library-generic-params.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (callback_generic (SPEC R19; call-chain break class 3)): routes, middleware chains, ctx flows +# census: callback_generic (SPEC R19; call-chain break class 3) +entry app.ts:10:18 http +entry app.ts:11:20 http +entry app.ts:12:23 http +entry app.ts:13:19 http +entry app.ts:19:3 http +entry app.ts:9:19 http diff --git a/graph/test/typescript/hono/expected/chains/library-generic-params.tsv b/graph/test/typescript/hono/expected/chains/library-generic-params.tsv new file mode 100644 index 000000000..3058b6d78 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/library-generic-params.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (callback_generic (SPEC R19; call-chain break class 3)): routes, middleware chains, ctx flows +# census: callback_generic (SPEC R19; call-chain break class 3) +route GET /roles app.ts:9:19 app.ts:6:13 0 +route GET /rank app.ts:10:18 app.ts:6:13 1 +route GET /latest app.ts:11:20 app.ts:6:13 2 +route GET /providers app.ts:12:23 app.ts:6:13 3 +route GET /names app.ts:13:19 app.ts:6:13 4 +route POST /roles app.ts:19:3 app.ts:6:13 6 +mw lib:hono/validator.validator@app.ts:18:3 app.ts:19:3 POST /roles 0 app.ts:6:13 +regby app.ts:1:1 app.ts:10:18 GET /rank app.ts:6:13 +regby app.ts:1:1 app.ts:11:20 GET /latest app.ts:6:13 +regby app.ts:1:1 app.ts:12:23 GET /providers app.ts:6:13 +regby app.ts:1:1 app.ts:13:19 GET /names app.ts:6:13 +regby app.ts:1:1 app.ts:19:3 POST /roles app.ts:6:13 +regby app.ts:1:1 app.ts:9:19 GET /roles app.ts:6:13 diff --git a/graph/test/typescript/hono/expected/chains/post-validator-chain.chains b/graph/test/typescript/hono/expected/chains/post-validator-chain.chains new file mode 100644 index 000000000..cc6b1094f --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/post-validator-chain.chains @@ -0,0 +1,25 @@ +# hand-reviewed 2026-10-28 against the fixture, the compiler call-chain oracle and the runtime trace: R18 on POST routes: the provider middleware, then the library json validator (zValidator; the built-in validator with a hand-written check), then the handler, which reads the validated body and calls the service it reads out of the context; service -> repository -> db. The body rows are the JSON each request carries: without them the validator answers 400 and no handler runs (checked). The middleware -> handler hop runs through the validator, which awaits the body before it calls next, so it is observed as both functions running in a one-request run, the handler entered from library code +# census: ctx_di + zvalidator + req_valid (SPEC R18 with SPEC 3.9; call-chain break class 1 on a POST route) +fn app.ts:12:41 +fn app.ts:21:54 +fn app.ts:30:21 +fn app.ts:34:3 +fn orders.ts:14:3 +fn orders.ts:17:3 +fn orders.ts:20:3 +fn orders.ts:27:3 +fn orders.ts:30:3 +fn orders.ts:33:3 +fn orders.ts:7:3 +edge app.ts:12:41 orders.ts:14:3 +edge app.ts:12:41 orders.ts:27:3 +edge app.ts:21:54 orders.ts:30:3 +edge app.ts:34:3 orders.ts:33:3 +edge orders.ts:17:3 orders.ts:7:3 +edge orders.ts:20:3 orders.ts:7:3 +edge orders.ts:30:3 orders.ts:17:3 +edge orders.ts:33:3 orders.ts:20:3 +body POST /orders {"sku":"a1","qty":2} +body POST /orders/x1/items {"sku":"a1"} +chain create-order POST /orders app.ts:12:41 app.ts:21:54 orders.ts:30:3 orders.ts:17:3 orders.ts:7:3 +chain add-item POST /orders/x1/items app.ts:12:41 app.ts:34:3 orders.ts:33:3 orders.ts:20:3 orders.ts:7:3 diff --git a/graph/test/typescript/hono/expected/chains/post-validator-chain.entries b/graph/test/typescript/hono/expected/chains/post-validator-chain.entries new file mode 100644 index 000000000..3756299be --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/post-validator-chain.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: chains fixture (POST routes behind a json validator, zValidator and the built-in validator): routes, middleware chains with the library validator at position 1, ctx flows, schema and the validated read +# census: ctx_di + zvalidator + req_valid (SPEC R18 with SPEC 3.9; call-chain break class 1 on a POST route) +entry app.ts:12:41 http +entry app.ts:21:54 http +entry app.ts:34:3 http diff --git a/graph/test/typescript/hono/expected/chains/post-validator-chain.tsv b/graph/test/typescript/hono/expected/chains/post-validator-chain.tsv new file mode 100644 index 000000000..9703dff0d --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/post-validator-chain.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: chains fixture (POST routes behind a json validator, zValidator and the built-in validator): routes, middleware chains with the library validator at position 1, ctx flows, schema and the validated read +# census: ctx_di + zvalidator + req_valid (SPEC R18 with SPEC 3.9; call-chain break class 1 on a POST route) +route POST /orders app.ts:21:54 app.ts:17:13 2 +route POST /orders/:id/items app.ts:34:3 app.ts:17:13 4 +mw app.ts:12:41 app.ts:21:54 POST /orders 0 app.ts:17:13 +mw lib:@hono/zod-validator.zValidator@app.ts:21:21 app.ts:21:54 POST /orders 1 app.ts:17:13 +mw app.ts:12:41 app.ts:34:3 POST /orders/:id/items 0 app.ts:17:13 +mw lib:hono/validator.validator@app.ts:30:3 app.ts:34:3 POST /orders/:id/items 1 app.ts:17:13 +ctx app.ts:12:41 app.ts:21:54 services +ctx app.ts:12:41 app.ts:34:3 services +schema app.ts:21:54 json app.ts:10:7 +validread app.ts:22:17 app.ts:21:54 json app.ts:10:7 +regby app.ts:1:1 app.ts:21:54 POST /orders app.ts:17:13 +regby app.ts:1:1 app.ts:34:3 POST /orders/:id/items app.ts:17:13 diff --git a/graph/test/typescript/hono/expected/chains/same-name-unrelated.chains b/graph/test/typescript/hono/expected/chains/same-name-unrelated.chains new file mode 100644 index 000000000..ecedebdc5 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/same-name-unrelated.chains @@ -0,0 +1,23 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: negative controls: a typed receiver, a typed context read and an untyped c.set value reach UserStore.save only, never the unrelated AuditLog.save (an edge to it is EXTRA); an interface call reaches both +# census: ctx_di, negative (SPEC R18-R21 negative controls) +fn app.ts:10:21 +fn app.ts:15:25 +fn app.ts:17:24 +fn app.ts:21:16 +fn app.ts:26:21 +fn app.ts:30:18 +fn stores.ts:10:3 +fn stores.ts:16:3 +fn stores.ts:21:1 +fn stores.ts:22:21 +edge app.ts:15:25 stores.ts:10:3 +edge app.ts:17:24 stores.ts:10:3 +edge app.ts:30:18 stores.ts:21:1 +edge stores.ts:21:1 stores.ts:22:21 +edge stores.ts:22:21 stores.ts:10:3 +edge stores.ts:22:21 stores.ts:16:3 +edge app.ts:26:21 stores.ts:10:3 rt +chain typed-receiver POST /typed/save app.ts:10:21 app.ts:15:25 stores.ts:10:3 +chain typed-ctx POST /typed/ctx app.ts:10:21 app.ts:17:24 stores.ts:10:3 +chain untyped-set POST /loose/save app.ts:21:16 app.ts:26:21 stores.ts:10:3 +chain interface-both POST /all app.ts:30:18 stores.ts:21:1 stores.ts:22:21 stores.ts:16:3 diff --git a/graph/test/typescript/hono/expected/chains/same-name-unrelated.entries b/graph/test/typescript/hono/expected/chains/same-name-unrelated.entries new file mode 100644 index 000000000..525bfa509 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/same-name-unrelated.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (ctx_di, negative (SPEC R18-R21 negative controls)): routes, middleware chains, ctx flows +# census: ctx_di, negative (SPEC R18-R21 negative controls) +entry app.ts:10:21 http +entry app.ts:15:25 http +entry app.ts:17:24 http +entry app.ts:21:16 http +entry app.ts:26:21 http +entry app.ts:30:18 http diff --git a/graph/test/typescript/hono/expected/chains/same-name-unrelated.tsv b/graph/test/typescript/hono/expected/chains/same-name-unrelated.tsv new file mode 100644 index 000000000..f76a74091 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/same-name-unrelated.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (ctx_di, negative (SPEC R18-R21 negative controls)): routes, middleware chains, ctx flows +# census: ctx_di, negative (SPEC R18-R21 negative controls) +route POST /typed/save app.ts:15:25 app.ts:9:13 1 +route POST /typed/ctx app.ts:17:24 app.ts:9:13 2 +route POST /loose/save app.ts:26:21 app.ts:9:13 4 +route POST /all app.ts:30:18 app.ts:9:13 5 +mw app.ts:10:21 app.ts:15:25 POST /typed/save 0 app.ts:9:13 +mw app.ts:10:21 app.ts:17:24 POST /typed/ctx 0 app.ts:9:13 +mw app.ts:21:16 app.ts:26:21 POST /loose/save 0 app.ts:9:13 +ctx app.ts:10:21 app.ts:17:24 users +ctx app.ts:21:16 app.ts:26:21 store +submount /loose app.ts:27:5 +regby app.ts:1:1 app.ts:15:25 POST /typed/save app.ts:9:13 +regby app.ts:1:1 app.ts:17:24 POST /typed/ctx app.ts:9:13 +regby app.ts:1:1 app.ts:26:21 POST /loose/save app.ts:9:13 +regby app.ts:1:1 app.ts:30:18 POST /all app.ts:9:13 diff --git a/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.chains b/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.chains new file mode 100644 index 000000000..8046ea89a --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.chains @@ -0,0 +1,53 @@ +# hand-reviewed 2026-10-29 against the fixture, the compiler call-chain oracle and the runtime trace: R20: this in arrows nested 1, 2 and 3 deep in a method, in a stored arrow, and in an arrow inside a static method reaches the class's own members +# census: this_arrow (SPEC R20; call-chain break class 4) +fn app.ts:10:18 +fn app.ts:6:20 +fn app.ts:7:19 +fn app.ts:8:21 +fn app.ts:9:19 +fn resp.ts:15:3 +fn resp.ts:18:3 +fn resp.ts:21:3 +fn resp.ts:24:3 +fn resp.ts:28:3 +fn resp.ts:29:27 +fn resp.ts:32:3 +fn resp.ts:33:27 +fn resp.ts:33:42 +fn resp.ts:36:3 +fn resp.ts:37:27 +fn resp.ts:37:42 +fn resp.ts:37:57 +fn resp.ts:40:3 +fn resp.ts:41:17 +fn resp.ts:42:21 +fn resp.ts:5:3 +fn resp.ts:8:3 +fn resp.ts:9:23 +edge app.ts:10:18 resp.ts:8:3 +edge app.ts:6:20 resp.ts:28:3 +edge app.ts:7:19 resp.ts:32:3 +edge app.ts:8:21 resp.ts:36:3 +edge app.ts:9:19 resp.ts:40:3 +edge resp.ts:28:3 resp.ts:29:27 +edge resp.ts:29:27 resp.ts:18:3 +edge resp.ts:32:3 resp.ts:33:27 +edge resp.ts:33:27 resp.ts:33:42 +edge resp.ts:33:42 resp.ts:18:3 +edge resp.ts:33:42 resp.ts:21:3 +edge resp.ts:36:3 resp.ts:37:27 +edge resp.ts:37:27 resp.ts:37:42 +edge resp.ts:37:42 resp.ts:37:57 +edge resp.ts:37:57 resp.ts:18:3 +edge resp.ts:37:57 resp.ts:21:3 +edge resp.ts:37:57 resp.ts:24:3 +edge resp.ts:40:3 resp.ts:41:17 +edge resp.ts:41:17 resp.ts:42:21 +edge resp.ts:42:21 resp.ts:18:3 +edge resp.ts:8:3 resp.ts:9:23 +edge resp.ts:9:23 resp.ts:5:3 +chain prices-depth1 GET /prices app.ts:6:20 resp.ts:28:3 resp.ts:29:27 resp.ts:18:3 +chain taxes-depth2 GET /taxes app.ts:7:19 resp.ts:32:3 resp.ts:33:27 resp.ts:33:42 resp.ts:21:3 +chain rounded-depth3 GET /rounded app.ts:8:21 resp.ts:36:3 resp.ts:37:27 resp.ts:37:42 resp.ts:37:57 resp.ts:24:3 +chain later-stored-arrow GET /later app.ts:9:19 resp.ts:40:3 resp.ts:41:17 resp.ts:42:21 resp.ts:18:3 +chain fail-static-this GET /fail app.ts:10:18 resp.ts:8:3 resp.ts:9:23 resp.ts:5:3 diff --git a/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.entries b/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.entries new file mode 100644 index 000000000..360d58824 --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (this_arrow (SPEC R20; call-chain break class 4)): routes, middleware chains, ctx flows +# census: this_arrow (SPEC R20; call-chain break class 4) +entry app.ts:10:18 http +entry app.ts:6:20 http +entry app.ts:7:19 http +entry app.ts:8:21 http +entry app.ts:9:19 http diff --git a/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.tsv b/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.tsv new file mode 100644 index 000000000..22de5206b --- /dev/null +++ b/graph/test/typescript/hono/expected/chains/this-in-nested-arrows.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: chains fixture (this_arrow (SPEC R20; call-chain break class 4)): routes, middleware chains, ctx flows +# census: this_arrow (SPEC R20; call-chain break class 4) +route GET /prices app.ts:6:20 app.ts:4:13 0 +route GET /taxes app.ts:7:19 app.ts:4:13 1 +route GET /rounded app.ts:8:21 app.ts:4:13 2 +route GET /later app.ts:9:19 app.ts:4:13 3 +route GET /fail app.ts:10:18 app.ts:4:13 4 +regby app.ts:1:1 app.ts:10:18 GET /fail app.ts:4:13 +regby app.ts:1:1 app.ts:6:20 GET /prices app.ts:4:13 +regby app.ts:1:1 app.ts:7:19 GET /taxes app.ts:4:13 +regby app.ts:1:1 app.ts:8:21 GET /rounded app.ts:4:13 +regby app.ts:1:1 app.ts:9:19 GET /later app.ts:4:13 diff --git a/graph/test/typescript/hono/expected/compose/abstract-strategy-mount.entries b/graph/test/typescript/hono/expected/compose/abstract-strategy-mount.entries new file mode 100644 index 000000000..3022b48b6 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/abstract-strategy-mount.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-2-01, re-derived: the map's instances are known, so each override mounts exactly under its key (runtime agrees); never a root +# census: route_mount_nonliteral (violation hono-2-01) +entry index.ts:13:24 http +entry index.ts:20:22 http diff --git a/graph/test/typescript/hono/expected/compose/abstract-strategy-mount.tsv b/graph/test/typescript/hono/expected/compose/abstract-strategy-mount.tsv new file mode 100644 index 000000000..34b44050e --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/abstract-strategy-mount.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-2-01, re-derived: the map's instances are known, so each override mounts exactly under its key (runtime agrees); never a root +# census: route_mount_nonliteral (violation hono-2-01) +route GET /oauth/callback index.ts:13:24 index.ts:26:13 0 +route POST /password/login index.ts:20:22 index.ts:26:13 1 +submount /oauth index.ts:28:7 +submount /password index.ts:28:7 +regby index.ts:11:3 index.ts:13:24 GET /oauth/callback index.ts:26:13 +regby index.ts:18:3 index.ts:20:22 POST /password/login index.ts:26:13 diff --git a/graph/test/typescript/hono/expected/compose/aliased-reexport-mount.entries b/graph/test/typescript/hono/expected/compose/aliased-reexport-mount.entries new file mode 100644 index 000000000..0b2333159 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/aliased-reexport-mount.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m30/hono-4-06: an export { local as alias } of an imported default mounts exactly at /api/search +# census: route_mount_literal (stress-4 mutation m30 shape; violation hono-4-06) +entry search/routes/api.ts:4:21 http +entry search/routes/api.ts:5:27 http diff --git a/graph/test/typescript/hono/expected/compose/aliased-reexport-mount.tsv b/graph/test/typescript/hono/expected/compose/aliased-reexport-mount.tsv new file mode 100644 index 000000000..ccd55775c --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/aliased-reexport-mount.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m30/hono-4-06: an export { local as alias } of an imported default mounts exactly at /api/search +# census: route_mount_literal (stress-4 mutation m30 shape; violation hono-4-06) +route POST /api/search search/routes/api.ts:4:21 index.ts:7:13 0 +route GET /api/search/suggest search/routes/api.ts:5:27 index.ts:7:13 1 +submount /api/search index.ts:8:5 +regby search/routes/api.ts:1:1 search/routes/api.ts:4:21 POST /api/search index.ts:7:13 +regby search/routes/api.ts:1:1 search/routes/api.ts:5:27 GET /api/search/suggest index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/compose/async-wrapper-mount.entries b/graph/test/typescript/hono/expected/compose/async-wrapper-mount.entries new file mode 100644 index 000000000..292249306 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/async-wrapper-mount.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m38/hono-5-06: the awaited async wrapper serves the inner route behind its use(*) +# census: bun_serve (stress-5 mutation m38 shape; violation hono-5-06) +entry main.ts:10:21 http +entry wrap.ts:5:20 http diff --git a/graph/test/typescript/hono/expected/compose/async-wrapper-mount.tsv b/graph/test/typescript/hono/expected/compose/async-wrapper-mount.tsv new file mode 100644 index 000000000..0a335d657 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/async-wrapper-mount.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m38/hono-5-06: the awaited async wrapper serves the inner route behind its use(*) +# census: bun_serve (stress-5 mutation m38 shape; violation hono-5-06) +route GET /hello main.ts:10:21 wrap.ts:4:19 1 +mw wrap.ts:5:20 main.ts:10:21 GET /hello 0 wrap.ts:4:19 +submount / wrap.ts:9:11 +regby main.ts:1:1 main.ts:10:21 GET /hello wrap.ts:4:19 diff --git a/graph/test/typescript/hono/expected/compose/basepath-group.entries b/graph/test/typescript/hono/expected/compose/basepath-group.entries new file mode 100644 index 000000000..3e57427ba --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/basepath-group.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: basePath clones share one route list; the original app's own route has no prefix +# census: basepath +entry index.ts:10:20 http +entry index.ts:11:19 http +entry index.ts:9:14 http diff --git a/graph/test/typescript/hono/expected/compose/basepath-group.tsv b/graph/test/typescript/hono/expected/compose/basepath-group.tsv new file mode 100644 index 000000000..e676163c8 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/basepath-group.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: basePath clones share one route list; the original app's own route has no prefix +# census: basepath +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.ts:9:14 index.ts:5:13 0 +route GET /api/status index.ts:10:20 index.ts:5:13 1 +route GET /api/v2/status index.ts:11:19 index.ts:5:13 2 +regby index.ts:1:1 index.ts:10:20 GET /api/status index.ts:5:13 +regby index.ts:1:1 index.ts:11:19 GET /api/v2/status index.ts:5:13 +regby index.ts:1:1 index.ts:9:14 GET / index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/compose/basepath-sub-mounted.entries b/graph/test/typescript/hono/expected/compose/basepath-sub-mounted.entries new file mode 100644 index 000000000..d8e4a99d5 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/basepath-sub-mounted.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: mount prefix then the sub-app's basePath then the local path +# census: basepath, route_mount_literal +entry index.ts:6:17 http diff --git a/graph/test/typescript/hono/expected/compose/basepath-sub-mounted.tsv b/graph/test/typescript/hono/expected/compose/basepath-sub-mounted.tsv new file mode 100644 index 000000000..527282721 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/basepath-sub-mounted.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: mount prefix then the sub-app's basePath then the local path +# census: basepath, route_mount_literal +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /svc/v1/ping index.ts:6:17 index.ts:8:13 0 +submount /svc index.ts:9:5 +regby index.ts:1:1 index.ts:6:17 GET /svc/v1/ping index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/compose/builder-called-twice.entries b/graph/test/typescript/hono/expected/compose/builder-called-twice.entries new file mode 100644 index 000000000..6dcab8fe6 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/builder-called-twice.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-02/R6: the helper makes two apps; /logo.png on the root, POST /import partial dynamic_mount_prefix under the sub-app +# census: app_factory_fn (violation hono-2-02, SPEC R6; oracle gap O9) +entry main.ts:10:22 http +entry users.ts:9:33 http diff --git a/graph/test/typescript/hono/expected/compose/builder-called-twice.tsv b/graph/test/typescript/hono/expected/compose/builder-called-twice.tsv new file mode 100644 index 000000000..e6f570815 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/builder-called-twice.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-02/R6: the helper makes two apps; /logo.png on the root, POST /import partial dynamic_mount_prefix under the sub-app +# census: app_factory_fn (violation hono-2-02, SPEC R6; oracle gap O9) +route GET /logo.png main.ts:10:22 routes.ts:4:13 0 +partial users.ts:9:33 POST dynamic_mount_prefix +regby main.ts:1:1 main.ts:10:22 GET /logo.png routes.ts:4:13 +unknown main.ts:12:3 dynamic_mount_prefix users.ts:9:33 diff --git a/graph/test/typescript/hono/expected/compose/declarative-routes-const.entries b/graph/test/typescript/hono/expected/compose/declarative-routes-const.entries new file mode 100644 index 000000000..69753dfc9 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/declarative-routes-const.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R13: a const { path, handler } array mounted in a loop gives exact routes; the { path, label } menu gives nothing +# census: route_mount_literal (SPEC R13: a const array of { path, handler } mounted in a loop) +entry index.ts:6:37 http +entry index.ts:7:38 http diff --git a/graph/test/typescript/hono/expected/compose/declarative-routes-const.tsv b/graph/test/typescript/hono/expected/compose/declarative-routes-const.tsv new file mode 100644 index 000000000..8c0db38c8 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/declarative-routes-const.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R13: a const { path, handler } array mounted in a loop gives exact routes; the { path, label } menu gives nothing +# census: route_mount_literal (SPEC R13: a const array of { path, handler } mounted in a loop) +route GET /tickets index.ts:6:37 index.ts:19:13 0 +route GET /tags/:tag index.ts:7:38 index.ts:19:13 1 +submount /tickets index.ts:21:7 +submount /tags index.ts:21:7 +regby index.ts:1:1 index.ts:6:37 GET /tickets index.ts:19:13 +regby index.ts:1:1 index.ts:7:38 GET /tags/:tag index.ts:19:13 diff --git a/graph/test/typescript/hono/expected/compose/declarative-routes-derived.entries b/graph/test/typescript/hono/expected/compose/declarative-routes-derived.entries new file mode 100644 index 000000000..598e2f96d --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/declarative-routes-derived.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R13b re-derived: sorted lists mount exact at element paths; the settings-filtered list adds conditional_registration; never roots at /; menu silent +# census: app_request_test (SPEC R13 / R13b; violation hono-4-09 and its silent menu-list control) +entry app.ts:8:14 http +entry mount.test.ts:12:14 http +entry mount.test.ts:28:95 http +entry plugins/inbox.ts:4:38 http diff --git a/graph/test/typescript/hono/expected/compose/declarative-routes-derived.tsv b/graph/test/typescript/hono/expected/compose/declarative-routes-derived.tsv new file mode 100644 index 000000000..678b8ea26 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/declarative-routes-derived.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R13b re-derived: sorted lists mount exact at element paths; the settings-filtered list adds conditional_registration; never roots at /; menu silent +# census: app_request_test (SPEC R13 / R13b; violation hono-4-09 and its silent menu-list control) +route GET / app.ts:8:14 app.ts:7:13 0 +route GET /api/inbox plugins/inbox.ts:4:38 app.ts:7:13 1 +route GET /solo mount.test.ts:12:14 mount.test.ts:17:15 0 +route GET /inline mount.test.ts:28:95 mount.test.ts:27:15 0 +submount /api/inbox mount.ts:25:9 +submount /solo mount.ts:25:9 +submount /inline mount.ts:25:9 +regby app.ts:1:1 app.ts:8:14 GET / app.ts:7:13 +regby mount.test.ts:10:1 mount.test.ts:12:14 GET /solo mount.test.ts:17:15 +regby mount.test.ts:26:32 mount.test.ts:28:95 GET /inline mount.test.ts:27:15 +regby plugins/inbox.ts:1:1 plugins/inbox.ts:4:38 GET /api/inbox app.ts:7:13 +unknown mount.ts:25:5 conditional_registration plugins/inbox.ts:4:38 diff --git a/graph/test/typescript/hono/expected/compose/discarded-basepath.entries b/graph/test/typescript/hono/expected/compose/discarded-basepath.entries new file mode 100644 index 000000000..34762ef53 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/discarded-basepath.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a statement basePath() changes nothing: GET /items, not /v2/items +# census: basepath (SPEC 2 [iter2]: a helper that discards basePath()'s result) +entry index.ts:11:19 http diff --git a/graph/test/typescript/hono/expected/compose/discarded-basepath.tsv b/graph/test/typescript/hono/expected/compose/discarded-basepath.tsv new file mode 100644 index 000000000..b9759bf34 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/discarded-basepath.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a statement basePath() changes nothing: GET /items, not /v2/items +# census: basepath (SPEC 2 [iter2]: a helper that discards basePath()'s result) +route GET /items index.ts:11:19 index.ts:10:25 0 +regby index.ts:1:1 index.ts:11:19 GET /items index.ts:10:25 diff --git a/graph/test/typescript/hono/expected/compose/dynamic-prefix.entries b/graph/test/typescript/hono/expected/compose/dynamic-prefix.entries new file mode 100644 index 000000000..09ad792ab --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/dynamic-prefix.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: the mounted route is partial with dynamic_mount_prefix, attributed to its handler +# census: route_mount_nonliteral +entry index.ts:11:20 http +entry index.ts:6:27 http diff --git a/graph/test/typescript/hono/expected/compose/dynamic-prefix.tsv b/graph/test/typescript/hono/expected/compose/dynamic-prefix.tsv new file mode 100644 index 000000000..c4e14d8d0 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/dynamic-prefix.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: the mounted route is partial with dynamic_mount_prefix, attributed to its handler +# census: route_mount_nonliteral +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /static index.ts:11:20 index.ts:9:13 0 +partial index.ts:6:27 GET dynamic_mount_prefix +regby index.ts:1:1 index.ts:11:20 GET /static index.ts:9:13 +unknown index.ts:10:1 dynamic_mount_prefix index.ts:6:27 diff --git a/graph/test/typescript/hono/expected/compose/factory-basepath.entries b/graph/test/typescript/hono/expected/compose/factory-basepath.entries new file mode 100644 index 000000000..3bef534eb --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/factory-basepath.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-02: only GET /v1/ping; no base-less /ping +# census: app_factory_fn, basepath (violation hono-1-02) +entry index.ts:10:18 http diff --git a/graph/test/typescript/hono/expected/compose/factory-basepath.tsv b/graph/test/typescript/hono/expected/compose/factory-basepath.tsv new file mode 100644 index 000000000..8ffc37df3 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/factory-basepath.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-02: only GET /v1/ping; no base-less /ping +# census: app_factory_fn, basepath (violation hono-1-02) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /v1/ping index.ts:10:18 index.ts:6:10 0 +regby index.ts:1:1 index.ts:10:18 GET /v1/ping index.ts:6:10 diff --git a/graph/test/typescript/hono/expected/compose/factory-fn.entries b/graph/test/typescript/hono/expected/compose/factory-fn.entries new file mode 100644 index 000000000..e68509ad1 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/factory-fn.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: factory results are distinct apps; /items mounted on the factory-made app +# census: app_factory_fn +entry app.ts:9:21 http +entry index.ts:7:16 http diff --git a/graph/test/typescript/hono/expected/compose/factory-fn.tsv b/graph/test/typescript/hono/expected/compose/factory-fn.tsv new file mode 100644 index 000000000..69316dced --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/factory-fn.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: factory results are distinct apps; /items mounted on the factory-made app +# census: app_factory_fn +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /ready app.ts:9:21 app.ts:4:10 0 +route GET /items index.ts:7:16 app.ts:4:10 1 +submount /items index.ts:8:5 +regby app.ts:7:1 app.ts:9:21 GET /ready app.ts:4:10 +regby index.ts:1:1 index.ts:7:16 GET /items app.ts:4:10 diff --git a/graph/test/typescript/hono/expected/compose/field-app-class.entries b/graph/test/typescript/hono/expected/compose/field-app-class.entries new file mode 100644 index 000000000..8a519cd5f --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/field-app-class.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: SPEC 2 field flow: this.app (createApp() basePath /v1) gets both mounts from setupRoutes() called in the constructor; the users mount argument comes from a method; this.extra (field initializer) is its own served app +# census: route_mount_literal, app_factory_fn (SPEC 2 [iter2] flow through fields; a class whose +entry routes/health.ts:3:43 http +entry routes/users.ts:6:19 http +entry server.ts:23:30 http diff --git a/graph/test/typescript/hono/expected/compose/field-app-class.tsv b/graph/test/typescript/hono/expected/compose/field-app-class.tsv new file mode 100644 index 000000000..508d3dd40 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/field-app-class.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: SPEC 2 field flow: this.app (createApp() basePath /v1) gets both mounts from setupRoutes() called in the constructor; the users mount argument comes from a method; this.extra (field initializer) is its own served app +# census: route_mount_literal, app_factory_fn (SPEC 2 [iter2] flow through fields; a class whose +route GET /extra server.ts:23:30 server.ts:13:25 0 +route GET /v1/health routes/health.ts:3:43 server.ts:8:10 0 +route GET /v1/users/:id routes/users.ts:6:19 server.ts:8:10 1 +submount /v1/health server.ts:21:14 +submount /v1/users server.ts:22:14 +regby routes/health.ts:1:1 routes/health.ts:3:43 GET /v1/health server.ts:8:10 +regby routes/users.ts:4:3 routes/users.ts:6:19 GET /v1/users/:id server.ts:8:10 +regby server.ts:20:3 server.ts:23:30 GET /extra server.ts:13:25 diff --git a/graph/test/typescript/hono/expected/compose/filtered-instance-loop.entries b/graph/test/typescript/hono/expected/compose/filtered-instance-loop.entries new file mode 100644 index 000000000..b7d9ec4d5 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/filtered-instance-loop.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m36/hono-5-01 under R13b: exact /accounts and /invoices, each with conditional_registration +# census: route_mount_root (stress-5 mutation m36 shape; violation hono-5-01, SPEC R13b) +entry index.ts:11:24 http +entry index.ts:18:24 http +entry index.ts:27:14 http diff --git a/graph/test/typescript/hono/expected/compose/filtered-instance-loop.tsv b/graph/test/typescript/hono/expected/compose/filtered-instance-loop.tsv new file mode 100644 index 000000000..2fc142d87 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/filtered-instance-loop.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m36/hono-5-01 under R13b: exact /accounts and /invoices, each with conditional_registration +# census: route_mount_root (stress-5 mutation m36 shape; violation hono-5-01, SPEC R13b) +# iteration 8: repeated rows removed (O29: the oracle prints each row once); the row set is unchanged +route GET / index.ts:27:14 index.ts:26:13 0 +route GET /accounts index.ts:11:24 index.ts:26:13 1 +route GET /invoices index.ts:18:24 index.ts:26:13 2 +submount / index.ts:29:7 +regby index.ts:16:3 index.ts:18:24 GET /invoices index.ts:26:13 +regby index.ts:1:1 index.ts:27:14 GET / index.ts:26:13 +regby index.ts:9:3 index.ts:11:24 GET /accounts index.ts:26:13 +unknown index.ts:29:3 conditional_registration index.ts:11:24 +unknown index.ts:29:3 conditional_registration index.ts:18:24 diff --git a/graph/test/typescript/hono/expected/compose/foreign-mount.entries b/graph/test/typescript/hono/expected/compose/foreign-mount.entries new file mode 100644 index 000000000..d727f45c7 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/foreign-mount.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: mount: ANY /legacy/* served by the foreign function, which is an http entry +# census: mount_foreign +entry index.ts:11:17 http +entry index.ts:5:1 http diff --git a/graph/test/typescript/hono/expected/compose/foreign-mount.tsv b/graph/test/typescript/hono/expected/compose/foreign-mount.tsv new file mode 100644 index 000000000..784bd3e17 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/foreign-mount.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: mount: ANY /legacy/* served by the foreign function, which is an http entry +# census: mount_foreign +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +# iteration 3: the mount is a store entry with a chain (O8); its route row and regby row re-derived +route ANY /legacy/* index.ts:5:1 index.ts:9:13 0 +route GET /new index.ts:11:17 index.ts:9:13 1 +regby index.ts:1:1 index.ts:11:17 GET /new index.ts:9:13 +regby index.ts:1:1 index.ts:5:1 ANY /legacy/* index.ts:9:13 diff --git a/graph/test/typescript/hono/expected/compose/getter-prefix-typed-holder.entries b/graph/test/typescript/hono/expected/compose/getter-prefix-typed-holder.entries new file mode 100644 index 000000000..29702fd97 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/getter-prefix-typed-holder.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m25: controller routes mounted on a typed holder at a getter-read prefix: one partial unresolved_app_value per route +# census: prop_receiver_route (stress-4 mutation m25 shape; SPEC R2, hono-2-04 residue) +entry index.ts:21:33 http +entry index.ts:22:30 http diff --git a/graph/test/typescript/hono/expected/compose/getter-prefix-typed-holder.tsv b/graph/test/typescript/hono/expected/compose/getter-prefix-typed-holder.tsv new file mode 100644 index 000000000..60d6f4fdf --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/getter-prefix-typed-holder.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m25: controller routes mounted on a typed holder at a getter-read prefix: one partial unresolved_app_value per route +# census: prop_receiver_route (stress-4 mutation m25 shape; SPEC R2, hono-2-04 residue) +partial index.ts:21:33 DELETE unresolved_app_value +partial index.ts:22:30 GET unresolved_app_value +unknown index.ts:42:5 unresolved_app_value index.ts:21:33 +unknown index.ts:42:5 unresolved_app_value index.ts:22:30 diff --git a/graph/test/typescript/hono/expected/compose/glob-brace-alternatives.entries b/graph/test/typescript/hono/expected/compose/glob-brace-alternatives.entries new file mode 100644 index 000000000..b30403949 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/glob-brace-alternatives.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: O28: {memory,*-store} matches memory, disk-store, remote-store (mounted under /stores); legacy stays its own exported app +# census: route_mount_root (SPEC R12.1; oracle note O28: a brace alternative holding a `*` crashed the oracle) +entry stores/disk-store/routes.ts:4:20 http +entry stores/legacy/routes.ts:4:22 http +entry stores/memory/routes.ts:4:22 http +entry stores/remote-store/routes.ts:4:22 http diff --git a/graph/test/typescript/hono/expected/compose/glob-brace-alternatives.tsv b/graph/test/typescript/hono/expected/compose/glob-brace-alternatives.tsv new file mode 100644 index 000000000..90232fbb6 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/glob-brace-alternatives.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: O28: {memory,*-store} matches memory, disk-store, remote-store (mounted under /stores); legacy stays its own exported app +# census: route_mount_root (SPEC R12.1; oracle note O28: a brace alternative holding a `*` crashed the oracle) +route GET /stores/disk stores/disk-store/routes.ts:4:20 index.ts:8:13 0 +route GET /stores/memory stores/memory/routes.ts:4:22 index.ts:8:13 1 +route GET /stores/remote stores/remote-store/routes.ts:4:22 index.ts:8:13 2 +route GET /legacy stores/legacy/routes.ts:4:22 stores/legacy/routes.ts:3:15 0 +submount /stores index.ts:10:7 +regby stores/disk-store/routes.ts:1:1 stores/disk-store/routes.ts:4:20 GET /stores/disk index.ts:8:13 +regby stores/legacy/routes.ts:1:1 stores/legacy/routes.ts:4:22 GET /legacy stores/legacy/routes.ts:3:15 +regby stores/memory/routes.ts:1:1 stores/memory/routes.ts:4:22 GET /stores/memory index.ts:8:13 +regby stores/remote-store/routes.ts:1:1 stores/remote-store/routes.ts:4:22 GET /stores/remote index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/compose/glob-module-list.entries b/graph/test/typescript/hono/expected/compose/glob-module-list.entries new file mode 100644 index 000000000..513595dc9 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/glob-module-list.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R12.1: literal import.meta.glob (eager and lazy) mounts each matched default-exported app; an unmatched module stays a root +# census: route_mount_root (SPEC R12.1; QD16 shape: a tier app mounting `mod.default` over a literal glob) +entry lazy/reports.page.ts:4:23 http +entry routes/orders/helpers.ts:5:25 http +entry routes/orders/orders.index.ts:4:24 http +entry routes/users/users.index.ts:4:21 http +entry routes/users/users.index.ts:5:25 http diff --git a/graph/test/typescript/hono/expected/compose/glob-module-list.tsv b/graph/test/typescript/hono/expected/compose/glob-module-list.tsv new file mode 100644 index 000000000..2f0b6b33f --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/glob-module-list.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R12.1: literal import.meta.glob (eager and lazy) mounts each matched default-exported app; an unmatched module stays a root +# census: route_mount_root (SPEC R12.1; QD16 shape: a tier app mounting `mod.default` over a literal glob) +# iteration 8: repeated rows removed (O29: the oracle prints each row once); the row set is unchanged +route POST /api/orders routes/orders/orders.index.ts:4:24 index.ts:21:13 0 +route GET /api/users routes/users/users.index.ts:4:21 index.ts:21:13 1 +route GET /api/users/:id routes/users/users.index.ts:5:25 index.ts:21:13 2 +route GET /pages/daily lazy/reports.page.ts:4:23 index.ts:21:13 3 +route GET /scratch routes/orders/helpers.ts:5:25 routes/orders/helpers.ts:4:17 0 +submount / index.ts:11:7 +submount /api index.ts:22:5 +submount /pages index.ts:17:9 +regby lazy/reports.page.ts:1:1 lazy/reports.page.ts:4:23 GET /pages/daily index.ts:21:13 +regby routes/orders/helpers.ts:1:1 routes/orders/helpers.ts:5:25 GET /scratch routes/orders/helpers.ts:4:17 +regby routes/orders/orders.index.ts:1:1 routes/orders/orders.index.ts:4:24 POST /api/orders index.ts:21:13 +regby routes/users/users.index.ts:1:1 routes/users/users.index.ts:4:21 GET /api/users index.ts:21:13 +regby routes/users/users.index.ts:1:1 routes/users/users.index.ts:5:25 GET /api/users/:id index.ts:21:13 diff --git a/graph/test/typescript/hono/expected/compose/late-sub-registration.entries b/graph/test/typescript/hono/expected/compose/late-sub-registration.entries new file mode 100644 index 000000000..28a91553a --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/late-sub-registration.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: /late is registered after the copy: not a route of the served app, still an entry point +# census: route_mount_literal +entry index.ts:12:18 http +entry index.ts:7:19 http diff --git a/graph/test/typescript/hono/expected/compose/late-sub-registration.tsv b/graph/test/typescript/hono/expected/compose/late-sub-registration.tsv new file mode 100644 index 000000000..67b6cb588 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/late-sub-registration.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: /late is registered after the copy: not a route of the served app, still an entry point +# census: route_mount_literal +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /sub/early index.ts:7:19 index.ts:9:13 0 +submount /sub index.ts:10:5 +regby index.ts:1:1 index.ts:7:19 GET /sub/early index.ts:9:13 diff --git a/graph/test/typescript/hono/expected/compose/let-rebase-conditional.entries b/graph/test/typescript/hono/expected/compose/let-rebase-conditional.entries new file mode 100644 index 000000000..209c5d751 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/let-rebase-conditional.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R8b (O27): routes registered through a module-level app variable after a conditional rebase (run-time base; literal base behind a condition) are partial dynamic_mount_prefix, never exact; /health, registered before the rebase, stays exact +# census: basepath (SPEC R8a/R8b, oracle note O27: a module-level app variable rebased under a condition) +entry index.ts:11:19 http +entry index.ts:14:20 http +entry index.ts:19:21 http +entry index.ts:26:21 http diff --git a/graph/test/typescript/hono/expected/compose/let-rebase-conditional.tsv b/graph/test/typescript/hono/expected/compose/let-rebase-conditional.tsv new file mode 100644 index 000000000..db989cbf5 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/let-rebase-conditional.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R8b (O27): routes registered through a module-level app variable after a conditional rebase (run-time base; literal base behind a condition) are partial dynamic_mount_prefix, never exact; /health, registered before the rebase, stays exact +# census: basepath (SPEC R8a/R8b, oracle note O27: a module-level app variable rebased under a condition) +route GET /health index.ts:14:20 index.ts:13:11 0 +partial index.ts:11:19 GET dynamic_mount_prefix +partial index.ts:19:21 GET dynamic_mount_prefix +partial index.ts:26:21 GET dynamic_mount_prefix +regby index.ts:1:1 index.ts:14:20 GET /health index.ts:13:11 +unknown index.ts:19:1 dynamic_mount_prefix index.ts:19:21 +unknown index.ts:20:1 dynamic_mount_prefix index.ts:11:19 +unknown index.ts:26:1 dynamic_mount_prefix index.ts:26:21 diff --git a/graph/test/typescript/hono/expected/compose/let-rebase-literal.entries b/graph/test/typescript/hono/expected/compose/let-rebase-literal.entries new file mode 100644 index 000000000..b1a2c9558 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/let-rebase-literal.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R8b control: an unconditional literal basePath reassignment is exact under /api for every later registration; /health before it stays at /health +# census: basepath (SPEC R8a/R8b control: an app variable re-pointed at a LITERAL basePath with no condition) +entry index.ts:10:20 http +entry index.ts:12:21 http +entry index.ts:7:19 http diff --git a/graph/test/typescript/hono/expected/compose/let-rebase-literal.tsv b/graph/test/typescript/hono/expected/compose/let-rebase-literal.tsv new file mode 100644 index 000000000..cc27c83bc --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/let-rebase-literal.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: R8b control: an unconditional literal basePath reassignment is exact under /api for every later registration; /health before it stays at /health +# census: basepath (SPEC R8a/R8b control: an app variable re-pointed at a LITERAL basePath with no condition) +route GET /health index.ts:10:20 index.ts:9:11 0 +route GET /api/version index.ts:12:21 index.ts:9:11 1 +route GET /api/users/:id index.ts:7:19 index.ts:9:11 2 +submount /api/users index.ts:13:5 +regby index.ts:1:1 index.ts:10:20 GET /health index.ts:9:11 +regby index.ts:1:1 index.ts:12:21 GET /api/version index.ts:9:11 +regby index.ts:1:1 index.ts:7:19 GET /api/users/:id index.ts:9:11 diff --git a/graph/test/typescript/hono/expected/compose/lib-dirs.entries b/graph/test/typescript/hono/expected/compose/lib-dirs.entries new file mode 100644 index 000000000..1e13bc688 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/lib-dirs.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: project files under lib/ and libs/ are project keys: /from-lib and /users/:id served by the lib/ app +# census: route_mount_literal (project sources under lib/ and libs/, a common monorepo layout) +entry lib/app.ts:4:22 http +entry libs/users/routes.ts:4:19 http diff --git a/graph/test/typescript/hono/expected/compose/lib-dirs.tsv b/graph/test/typescript/hono/expected/compose/lib-dirs.tsv new file mode 100644 index 000000000..cac74a7ad --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/lib-dirs.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: project files under lib/ and libs/ are project keys: /from-lib and /users/:id served by the lib/ app +# census: route_mount_literal (project sources under lib/ and libs/, a common monorepo layout) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /from-lib lib/app.ts:4:22 lib/app.ts:3:20 0 +route GET /users/:id libs/users/routes.ts:4:19 lib/app.ts:3:20 1 +submount /users index.ts:6:5 +regby lib/app.ts:1:1 lib/app.ts:4:22 GET /from-lib lib/app.ts:3:20 +regby libs/users/routes.ts:1:1 libs/users/routes.ts:4:19 GET /users/:id lib/app.ts:3:20 diff --git a/graph/test/typescript/hono/expected/compose/literal-prefix-method.entries b/graph/test/typescript/hono/expected/compose/literal-prefix-method.entries new file mode 100644 index 000000000..08c8cb56d --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/literal-prefix-method.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-05: a zero-argument method returning a literal is the constant /console; a field-built prefix stays partial +# census: mount_dynamic_prefix_call (violation hono-3-05, SPEC 3.2 G8) +entry index.ts:10:28 http +entry index.ts:25:29 http +entry index.ts:9:29 http diff --git a/graph/test/typescript/hono/expected/compose/literal-prefix-method.tsv b/graph/test/typescript/hono/expected/compose/literal-prefix-method.tsv new file mode 100644 index 000000000..736dc6849 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/literal-prefix-method.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-05: a zero-argument method returning a literal is the constant /console; a field-built prefix stays partial +# census: mount_dynamic_prefix_call (violation hono-3-05, SPEC 3.2 G8) +route GET /console/login index.ts:9:29 index.ts:35:13 0 +route GET /console/home index.ts:10:28 index.ts:35:13 1 +submount /console index.ts:37:5 +partial index.ts:25:29 GET dynamic_mount_prefix +regby index.ts:8:3 index.ts:10:28 GET /console/home index.ts:35:13 +regby index.ts:8:3 index.ts:9:29 GET /console/login index.ts:35:13 +unknown index.ts:39:1 dynamic_mount_prefix index.ts:25:29 diff --git a/graph/test/typescript/hono/expected/compose/loop-mount-method-fallback.entries b/graph/test/typescript/hono/expected/compose/loop-mount-method-fallback.entries new file mode 100644 index 000000000..146ae214a --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/loop-mount-method-fallback.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m29/hono-4-05: only the loop element class is partial; /admin/signin exact and not also partial +# census: mount_dynamic_prefix_call (stress-4 mutation m29 shape; violation hono-4-05) +entry index.ts:11:30 http +entry index.ts:24:30 http diff --git a/graph/test/typescript/hono/expected/compose/loop-mount-method-fallback.tsv b/graph/test/typescript/hono/expected/compose/loop-mount-method-fallback.tsv new file mode 100644 index 000000000..20cbf2b27 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/loop-mount-method-fallback.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m29/hono-4-05: only the loop element class is partial; /admin/signin exact and not also partial +# census: mount_dynamic_prefix_call (stress-4 mutation m29 shape; violation hono-4-05) +route GET /admin/signin index.ts:24:30 index.ts:35:13 0 +submount /admin index.ts:41:5 +partial index.ts:11:30 GET dynamic_mount_prefix +regby index.ts:23:3 index.ts:24:30 GET /admin/signin index.ts:35:13 +unknown index.ts:38:3 dynamic_mount_prefix index.ts:11:30 diff --git a/graph/test/typescript/hono/expected/compose/method-prefix-const-list.entries b/graph/test/typescript/hono/expected/compose/method-prefix-const-list.entries new file mode 100644 index 000000000..ac35c43e6 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/method-prefix-const-list.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-5-03: g.prefix(V) with a const V over a const list composes /v2/members exactly +# census: mount_dynamic_prefix_call (violation hono-5-03) +entry index.ts:16:22 http +entry members.ts:10:29 http +entry members.ts:9:33 http diff --git a/graph/test/typescript/hono/expected/compose/method-prefix-const-list.tsv b/graph/test/typescript/hono/expected/compose/method-prefix-const-list.tsv new file mode 100644 index 000000000..e565cdf78 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/method-prefix-const-list.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-5-03: g.prefix(V) with a const V over a const list composes /v2/members exactly +# census: mount_dynamic_prefix_call (violation hono-5-03) +route POST /v2/members/import members.ts:9:33 routes.ts:4:13 0 +route GET /v2/members/:id members.ts:10:29 routes.ts:4:13 1 +route GET /logo.png index.ts:16:22 routes.ts:4:13 2 +submount /v2/members index.ts:14:7 +regby index.ts:1:1 index.ts:16:22 GET /logo.png routes.ts:4:13 +regby members.ts:8:3 members.ts:10:29 GET /v2/members/:id routes.ts:4:13 +regby members.ts:8:3 members.ts:9:33 POST /v2/members/import routes.ts:4:13 diff --git a/graph/test/typescript/hono/expected/compose/mount-arg-never-root.entries b/graph/test/typescript/hono/expected/compose/mount-arg-never-root.entries new file mode 100644 index 000000000..6b177e927 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/mount-arg-never-root.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route() on an unrecognised receiver: the mounted app's /daily is partial unresolved_mount, never a root; a non-app route() argument produces nothing +# census: neg_route_on_nonhono, route_mount_literal (SPEC 2 [iter2]: a mount argument is never a root) +entry index.ts:7:23 http diff --git a/graph/test/typescript/hono/expected/compose/mount-arg-never-root.tsv b/graph/test/typescript/hono/expected/compose/mount-arg-never-root.tsv new file mode 100644 index 000000000..b267ca7c6 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/mount-arg-never-root.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route() on an unrecognised receiver: the mounted app's /daily is partial unresolved_mount, never a root; a non-app route() argument produces nothing +# census: neg_route_on_nonhono, route_mount_literal (SPEC 2 [iter2]: a mount argument is never a root) +partial index.ts:7:23 GET unresolved_mount +unknown index.ts:10:1 unresolved_mount index.ts:7:23 diff --git a/graph/test/typescript/hono/expected/compose/mount-chain.entries b/graph/test/typescript/hono/expected/compose/mount-chain.entries new file mode 100644 index 000000000..b14dd0fe0 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/mount-chain.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O8: the mount route ANY /legacy/* has its chain: cors then legacyAuth +# census: mount_foreign, use_scoped (oracle gap O8) +entry index.ts:7:39 http +entry index.ts:8:1 http diff --git a/graph/test/typescript/hono/expected/compose/mount-chain.tsv b/graph/test/typescript/hono/expected/compose/mount-chain.tsv new file mode 100644 index 000000000..e0449331b --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/mount-chain.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O8: the mount route ANY /legacy/* has its chain: cors then legacyAuth +# census: mount_foreign, use_scoped (oracle gap O8) +route ANY /legacy/* index.ts:8:1 index.ts:12:13 2 +mw lib:hono/cors.cors@index.ts:13:9 index.ts:8:1 ANY /legacy/* 0 index.ts:12:13 +mw index.ts:7:39 index.ts:8:1 ANY /legacy/* 1 index.ts:12:13 +regby index.ts:1:1 index.ts:8:1 ANY /legacy/* index.ts:12:13 diff --git a/graph/test/typescript/hono/expected/compose/nested-three-deep.entries b/graph/test/typescript/hono/expected/compose/nested-three-deep.entries new file mode 100644 index 000000000..c6c98fa86 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/nested-three-deep.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: comments under posts under /api basePath mounted at /: prefixes compose outer to inner +# census: route_mount_literal, basepath +entry comments.ts:5:19 http +entry comments.ts:6:32 http +entry posts.ts:6:23 http diff --git a/graph/test/typescript/hono/expected/compose/nested-three-deep.tsv b/graph/test/typescript/hono/expected/compose/nested-three-deep.tsv new file mode 100644 index 000000000..601907a2d --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/nested-three-deep.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: comments under posts under /api basePath mounted at /: prefixes compose outer to inner (http_mount prefix is the effective one: /api/posts under the basePath) +# census: route_mount_literal, basepath +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/posts/:postId posts.ts:6:23 index.ts:6:13 0 +route GET /api/posts/:postId/comments comments.ts:5:19 index.ts:6:13 1 +route DELETE /api/posts/:postId/comments/:commentId comments.ts:6:32 index.ts:6:13 2 +submount /:postId/comments posts.ts:7:7 +submount /api/posts api.ts:6:5 +submount / index.ts:8:5 +regby comments.ts:1:1 comments.ts:5:19 GET /api/posts/:postId/comments index.ts:6:13 +regby comments.ts:1:1 comments.ts:6:32 DELETE /api/posts/:postId/comments/:commentId index.ts:6:13 +regby posts.ts:1:1 posts.ts:6:23 GET /api/posts/:postId index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/compose/opaque-module-list.entries b/graph/test/typescript/hono/expected/compose/opaque-module-list.entries new file mode 100644 index 000000000..e7c7e4c63 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/opaque-module-list.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R12.2: with an opaque mod.default mount, unimported unserved default-exported apps are partial unresolved_mount; imported, served and entry apps are not +# census: route_mount_root (SPEC R12.2: an opaque run-time module list) +entry routes/billing.ts:4:26 http +entry routes/status.ts:4:23 http +entry shared.ts:5:24 http +entry worker.ts:5:21 http diff --git a/graph/test/typescript/hono/expected/compose/opaque-module-list.tsv b/graph/test/typescript/hono/expected/compose/opaque-module-list.tsv new file mode 100644 index 000000000..88ffa4792 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/opaque-module-list.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R12.2: with an opaque mod.default mount, unimported unserved default-exported apps are partial unresolved_mount; imported, served and entry apps are not +# census: route_mount_root (SPEC R12.2: an opaque run-time module list) +route GET /version shared.ts:5:24 server.ts:10:13 0 +route GET /tick worker.ts:5:21 worker.ts:4:16 0 +submount / server.ts:11:5 +partial routes/billing.ts:4:26 GET unresolved_mount +partial routes/status.ts:4:23 GET unresolved_mount +regby shared.ts:1:1 shared.ts:5:24 GET /version server.ts:10:13 +regby worker.ts:1:1 worker.ts:5:21 GET /tick worker.ts:4:16 +unknown server.ts:16:5 unresolved_mount routes/billing.ts:4:26 +unknown server.ts:16:5 unresolved_mount routes/status.ts:4:23 +unknown server.ts:16:5 unresolved_mount server.ts:13:1 diff --git a/graph/test/typescript/hono/expected/compose/oracle-eval-cycle.entries b/graph/test/typescript/hono/expected/compose/oracle-eval-cycle.entries new file mode 100644 index 000000000..eb926d3f2 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/oracle-eval-cycle.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O15: the oracle terminates on the destructure-and-rebuild cycle and is linear on a 25-link builder chain; the app's route, middleware and ctx flow are unaffected +# census: new_hono_inside_function (oracle gap O15) +entry index.ts:12:23 http +entry index.ts:16:33 http diff --git a/graph/test/typescript/hono/expected/compose/oracle-eval-cycle.tsv b/graph/test/typescript/hono/expected/compose/oracle-eval-cycle.tsv new file mode 100644 index 000000000..cef0baf76 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/oracle-eval-cycle.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O15: the oracle terminates on the destructure-and-rebuild cycle and is linear on a 25-link builder chain; the app's route, middleware and ctx flow are unaffected +# census: new_hono_inside_function (oracle gap O15) +route POST /threads/:id/resume index.ts:16:33 index.ts:11:13 1 +mw index.ts:12:23 index.ts:16:33 POST /threads/:id/resume 0 index.ts:11:13 +ctx index.ts:12:23 index.ts:16:33 saver +regby index.ts:1:1 index.ts:16:33 POST /threads/:id/resume index.ts:11:13 diff --git a/graph/test/typescript/hono/expected/compose/partial-path-mid-hole.entries b/graph/test/typescript/hono/expected/compose/partial-path-mid-hole.entries new file mode 100644 index 000000000..5462e1fc4 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/partial-path-mid-hole.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-05: the template prefix /v1/${group} keeps its known pieces: partial GET /v1/{}/ping and /v1/{}/status/:part (runtime /v1/system/... matches), global use 0 and the sub-app's use 1, the /v1/* use is partial_route_scope +# census: route_mount_nonliteral, use_scoped, use_global (violation hono-7-05: a partial route whose unknown piece +entry main.ts:14:14 http +entry main.ts:17:26 http +entry main.ts:23:20 http +entry system.ts:4:17 http +entry system.ts:8:21 http +entry system.ts:9:29 http diff --git a/graph/test/typescript/hono/expected/compose/partial-path-mid-hole.tsv b/graph/test/typescript/hono/expected/compose/partial-path-mid-hole.tsv new file mode 100644 index 000000000..c176925df --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/partial-path-mid-hole.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-05: the template prefix /v1/${group} keeps its known pieces: partial GET /v1/{}/ping and /v1/{}/status/:part (runtime /v1/system/... matches), global use 0 and the sub-app's use 1, the /v1/* use is partial_route_scope +# census: route_mount_nonliteral, use_scoped, use_global (violation hono-7-05: a partial route whose unknown piece +route GET /health main.ts:23:20 main.ts:13:13 2 +mw main.ts:14:14 main.ts:23:20 GET /health 0 main.ts:13:13 +partial system.ts:8:21 GET dynamic_mount_prefix +partial system.ts:9:29 GET dynamic_mount_prefix +ppath system.ts:8:21 GET /v1/{}/ping +ppath system.ts:9:29 GET /v1/{}/status/:part +mwp main.ts:14:14 system.ts:8:21 GET 0 +mwp main.ts:14:14 system.ts:9:29 GET 0 +mwp system.ts:4:17 system.ts:8:21 GET 1 +mwp system.ts:4:17 system.ts:9:29 GET 1 +regby main.ts:1:1 main.ts:23:20 GET /health main.ts:13:13 +unknown main.ts:22:1 dynamic_mount_prefix system.ts:8:21 +unknown main.ts:22:1 dynamic_mount_prefix system.ts:9:29 +unknown main.ts:22:1 partial_route_scope main.ts:17:26 diff --git a/graph/test/typescript/hono/expected/compose/plugin-helper-list.entries b/graph/test/typescript/hono/expected/compose/plugin-helper-list.entries new file mode 100644 index 000000000..8050cea71 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-helper-list.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O20/R13b: plugin apps reached through a filtered, push-sorted helper list mount at their element paths, exact plus conditional; never roots +# census: app_request_test (oracle gap O20; SPEC R13 / R13b) +entry app.test.ts:13:19 http +entry app.ts:9:16 http +entry plugins/magic-link.ts:5:24 http +entry plugins/magic-link.ts:6:22 http diff --git a/graph/test/typescript/hono/expected/compose/plugin-helper-list.tsv b/graph/test/typescript/hono/expected/compose/plugin-helper-list.tsv new file mode 100644 index 000000000..0803a00d1 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-helper-list.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O20/R13b: plugin apps reached through a filtered, push-sorted helper list mount at their element paths, exact plus conditional; never roots +# census: app_request_test (oracle gap O20; SPEC R13 / R13b) +route GET / app.ts:9:16 app.ts:8:15 0 +route GET /api/custom-test app.test.ts:13:19 app.ts:8:15 1 +route POST /auth/magic-link/request plugins/magic-link.ts:5:24 app.ts:8:15 2 +route GET /auth/magic-link/verify plugins/magic-link.ts:6:22 app.ts:8:15 3 +request app.test.ts:17:30 GET /api/custom-test app.test.ts:13:19 +submount /api/custom-test mount.ts:13:9 +submount /auth/magic-link mount.ts:13:9 +regby app.test.ts:11:1 app.test.ts:13:19 GET /api/custom-test app.ts:8:15 +regby app.ts:7:1 app.ts:9:16 GET / app.ts:8:15 +regby plugins/magic-link.ts:1:1 plugins/magic-link.ts:5:24 POST /auth/magic-link/request app.ts:8:15 +regby plugins/magic-link.ts:1:1 plugins/magic-link.ts:6:22 GET /auth/magic-link/verify app.ts:8:15 +unknown mount.ts:13:5 conditional_registration app.test.ts:13:19 +unknown mount.ts:13:5 conditional_registration plugins/magic-link.ts:5:24 +unknown mount.ts:13:5 conditional_registration plugins/magic-link.ts:6:22 diff --git a/graph/test/typescript/hono/expected/compose/plugin-instance-never-mounted.entries b/graph/test/typescript/hono/expected/compose/plugin-instance-never-mounted.entries new file mode 100644 index 000000000..7a84d3273 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-instance-never-mounted.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O24/R13: a plugin factory's second instance that nothing imports or mounts is no root at its local paths; a never-imported plugin module's handlers are partial unresolved_mount +# census: plugin_list_mount (oracle gap O24; SPEC R13 / R13b) +entry app.ts:12:16 http +entry plugins/legacy-export.ts:8:22 http +entry plugins/magic-link.ts:12:27 http +entry plugins/magic-link.ts:13:25 http diff --git a/graph/test/typescript/hono/expected/compose/plugin-instance-never-mounted.tsv b/graph/test/typescript/hono/expected/compose/plugin-instance-never-mounted.tsv new file mode 100644 index 000000000..b310a7f4f --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-instance-never-mounted.tsv @@ -0,0 +1,13 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O24/R13: a plugin factory's second instance that nothing imports or mounts is no root at its local paths; a never-imported plugin module's handlers are partial unresolved_mount +# census: plugin_list_mount (oracle gap O24; SPEC R13 / R13b) +route GET / app.ts:12:16 app.ts:11:15 0 +route POST /auth/magic-link/request plugins/magic-link.ts:12:27 app.ts:11:15 1 +route GET /auth/magic-link/verify plugins/magic-link.ts:13:25 app.ts:11:15 2 +submount /auth/magic-link app.ts:6:41 +partial plugins/legacy-export.ts:8:22 GET unresolved_mount +regby app.ts:10:1 app.ts:12:16 GET / app.ts:11:15 +regby plugins/magic-link.ts:10:1 plugins/magic-link.ts:12:27 POST /auth/magic-link/request app.ts:11:15 +regby plugins/magic-link.ts:10:1 plugins/magic-link.ts:13:25 GET /auth/magic-link/verify app.ts:11:15 +unknown app.ts:6:37 conditional_registration plugins/magic-link.ts:12:27 +unknown app.ts:6:37 conditional_registration plugins/magic-link.ts:13:25 +unknown plugins/legacy-export.ts:9:79 unresolved_mount plugins/legacy-export.ts:8:22 diff --git a/graph/test/typescript/hono/expected/compose/plugin-register-method.entries b/graph/test/typescript/hono/expected/compose/plugin-register-method.entries new file mode 100644 index 000000000..c4c998c5e --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-register-method.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R13b re-derived: plugin apps mounted by register(app) over a filtered list of known plugins are exact at their prefixes with conditional_registration +# census: route_mount_literal (oracle gap O11 residual; SPEC 2 a mount argument is never a root) +entry index.ts:19:14 http +entry plugins/media.ts:6:16 http +entry plugins/media.ts:7:22 http +entry plugins/variables.ts:5:24 http +entry plugins/variables.ts:8:23 http diff --git a/graph/test/typescript/hono/expected/compose/plugin-register-method.tsv b/graph/test/typescript/hono/expected/compose/plugin-register-method.tsv new file mode 100644 index 000000000..8e23db2c7 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-register-method.tsv @@ -0,0 +1,19 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R13b re-derived: plugin apps mounted by register(app) over a filtered list of known plugins are exact at their prefixes with conditional_registration +# census: route_mount_literal (oracle gap O11 residual; SPEC 2 a mount argument is never a root) +route GET / index.ts:19:14 index.ts:18:13 0 +route GET /api/media plugins/media.ts:6:16 index.ts:18:13 1 +route DELETE /api/media/:id plugins/media.ts:7:22 index.ts:18:13 2 +route GET /api/variables/:key plugins/variables.ts:5:24 index.ts:18:13 3 +route POST /admin/variables plugins/variables.ts:8:23 index.ts:18:13 4 +submount /api/media plugins/media.ts:14:9 +submount /api/variables plugins/variables.ts:13:9 +submount /admin/variables plugins/variables.ts:14:9 +regby index.ts:1:1 index.ts:19:14 GET / index.ts:18:13 +regby plugins/media.ts:4:1 plugins/media.ts:6:16 GET /api/media index.ts:18:13 +regby plugins/media.ts:4:1 plugins/media.ts:7:22 DELETE /api/media/:id index.ts:18:13 +regby plugins/variables.ts:1:1 plugins/variables.ts:5:24 GET /api/variables/:key index.ts:18:13 +regby plugins/variables.ts:1:1 plugins/variables.ts:8:23 POST /admin/variables index.ts:18:13 +unknown plugins/media.ts:14:5 conditional_registration plugins/media.ts:6:16 +unknown plugins/media.ts:14:5 conditional_registration plugins/media.ts:7:22 +unknown plugins/variables.ts:13:5 conditional_registration plugins/variables.ts:5:24 +unknown plugins/variables.ts:14:5 conditional_registration plugins/variables.ts:8:23 diff --git a/graph/test/typescript/hono/expected/compose/plugin-shared-test-and-prod.entries b/graph/test/typescript/hono/expected/compose/plugin-shared-test-and-prod.entries new file mode 100644 index 000000000..2046746e6 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-shared-test-and-prod.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R16 control: a plugin mounted by production AND by a test app is a route of both; a test-only plugin stays on the test app; a test request for a production-only plugin path is unserved on the test app +# census: app_request_test, plugin_list_mount (SPEC R16 control; R6, R13b) +entry plugins/billing.ts:5:26 http +entry plugins/search.ts:5:17 http +entry plugins/search.ts:6:25 http +entry server.ts:7:14 http +entry test/search.test.ts:15:37 http diff --git a/graph/test/typescript/hono/expected/compose/plugin-shared-test-and-prod.tsv b/graph/test/typescript/hono/expected/compose/plugin-shared-test-and-prod.tsv new file mode 100644 index 000000000..220832422 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/plugin-shared-test-and-prod.tsv @@ -0,0 +1,31 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R16 control: a plugin mounted by production AND by a test app is a route of both; a test-only plugin stays on the test app; a test request for a production-only plugin path is unserved on the test app +# census: app_request_test, plugin_list_mount (SPEC R16 control; R6, R13b) +# iteration 8: repeated rows removed (O29: the oracle prints each row once); the row set is unchanged +route GET / server.ts:7:14 server.ts:6:13 0 +route GET /api/search plugins/search.ts:5:17 server.ts:6:13 1 +route POST /api/search/reindex plugins/search.ts:6:25 server.ts:6:13 2 +route GET /api/billing/invoices plugins/billing.ts:5:26 server.ts:6:13 3 +route GET /api/search plugins/search.ts:5:17 test/search.test.ts:8:15 0 +route POST /api/search/reindex plugins/search.ts:6:25 test/search.test.ts:8:15 1 +route GET /api/search plugins/search.ts:5:17 test/search.test.ts:17:15 0 +route POST /api/search/reindex plugins/search.ts:6:25 test/search.test.ts:17:15 1 +route GET /__probe test/search.test.ts:15:37 test/search.test.ts:17:15 2 +request test/search.test.ts:14:43 GET /__probe test/search.test.ts:15:37 +request test/search.test.ts:7:46 GET /api/search plugins/search.ts:5:17 +request test/search.test.ts:7:46 POST /api/search/reindex plugins/search.ts:6:25 +submount /api/search plugins.ts:10:48 +submount /api/billing plugins.ts:10:48 +submount /__probe plugins.ts:10:48 +regby plugins/billing.ts:1:1 plugins/billing.ts:5:26 GET /api/billing/invoices server.ts:6:13 +regby plugins/search.ts:1:1 plugins/search.ts:5:17 GET /api/search server.ts:6:13 +regby plugins/search.ts:1:1 plugins/search.ts:5:17 GET /api/search test/search.test.ts:17:15 +regby plugins/search.ts:1:1 plugins/search.ts:5:17 GET /api/search test/search.test.ts:8:15 +regby plugins/search.ts:1:1 plugins/search.ts:6:25 POST /api/search/reindex server.ts:6:13 +regby plugins/search.ts:1:1 plugins/search.ts:6:25 POST /api/search/reindex test/search.test.ts:17:15 +regby plugins/search.ts:1:1 plugins/search.ts:6:25 POST /api/search/reindex test/search.test.ts:8:15 +regby server.ts:1:1 server.ts:7:14 GET / server.ts:6:13 +regby test/search.test.ts:14:43 test/search.test.ts:15:37 GET /__probe test/search.test.ts:17:15 +unserved test/search.test.ts:14:43 GET /api/billing/invoices +unknown plugins.ts:10:44 conditional_registration plugins/billing.ts:5:26 +unknown plugins.ts:10:44 conditional_registration plugins/search.ts:5:17 +unknown plugins.ts:10:44 conditional_registration plugins/search.ts:6:25 diff --git a/graph/test/typescript/hono/expected/compose/rebased-holder-getter.entries b/graph/test/typescript/hono/expected/compose/rebased-holder-getter.entries new file mode 100644 index 000000000..e945ce087 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-holder-getter.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-01/R8a through a getter: both controller routes partial dynamic_mount_prefix, no exact rows +# census: basepath (violation hono-3-01, SPEC R8a; holder read through a getter) +entry index.ts:29:20 http +entry index.ts:30:22 http diff --git a/graph/test/typescript/hono/expected/compose/rebased-holder-getter.tsv b/graph/test/typescript/hono/expected/compose/rebased-holder-getter.tsv new file mode 100644 index 000000000..295673df5 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-holder-getter.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-01/R8a through a getter: both controller routes partial dynamic_mount_prefix, no exact rows +# census: basepath (violation hono-3-01, SPEC R8a; holder read through a getter) +partial index.ts:29:20 GET dynamic_mount_prefix +partial index.ts:30:22 POST dynamic_mount_prefix +unknown index.ts:34:5 dynamic_mount_prefix index.ts:29:20 +unknown index.ts:34:5 dynamic_mount_prefix index.ts:30:22 diff --git a/graph/test/typescript/hono/expected/compose/rebased-holder-mount.entries b/graph/test/typescript/hono/expected/compose/rebased-holder-mount.entries new file mode 100644 index 000000000..465dd14fe --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-holder-mount.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-01/R8a: a sub-app mounted with route() into a rebasable holder is one partial dynamic_mount_prefix per route, no exact row +# census: basepath (violation hono-3-01, SPEC R8a) +entry index.ts:9:21 http diff --git a/graph/test/typescript/hono/expected/compose/rebased-holder-mount.tsv b/graph/test/typescript/hono/expected/compose/rebased-holder-mount.tsv new file mode 100644 index 000000000..754d5101b --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-holder-mount.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-01/R8a: a sub-app mounted with route() into a rebasable holder is one partial dynamic_mount_prefix per route, no exact row +# census: basepath (violation hono-3-01, SPEC R8a) +partial index.ts:9:21 GET dynamic_mount_prefix +unknown index.ts:24:1 dynamic_mount_prefix index.ts:9:21 diff --git a/graph/test/typescript/hono/expected/compose/rebased-holder-one-partial.entries b/graph/test/typescript/hono/expected/compose/rebased-holder-one-partial.entries new file mode 100644 index 000000000..2427f54ae --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-holder-one-partial.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-2-04 residue/R8: one partial with one reason (dynamic_mount_prefix) per route, mounted through a build context +# census: prop_receiver_route (violation hono-2-04 residue, SPEC R8 / R8a) +entry index.ts:16:16 http +entry index.ts:17:19 http diff --git a/graph/test/typescript/hono/expected/compose/rebased-holder-one-partial.tsv b/graph/test/typescript/hono/expected/compose/rebased-holder-one-partial.tsv new file mode 100644 index 000000000..8ea4fe513 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-holder-one-partial.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-2-04 residue/R8: one partial with one reason (dynamic_mount_prefix) per route, mounted through a build context +# census: prop_receiver_route (violation hono-2-04 residue, SPEC R8 / R8a) +partial index.ts:16:16 GET dynamic_mount_prefix +partial index.ts:17:19 GET dynamic_mount_prefix +unknown index.ts:38:5 dynamic_mount_prefix index.ts:16:16 +unknown index.ts:38:5 dynamic_mount_prefix index.ts:17:19 diff --git a/graph/test/typescript/hono/expected/compose/rebased-two-mounts.entries b/graph/test/typescript/hono/expected/compose/rebased-two-mounts.entries new file mode 100644 index 000000000..162905f8a --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-two-mounts.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m33: both sub-apps on the rebasable holder are one partial each (dynamic_mount_prefix), no exact rows +# census: basepath (stress-4 mutation m33 shape; violations hono-3-01, hono-4-04) +entry index.ts:11:30 http +entry index.ts:9:29 http diff --git a/graph/test/typescript/hono/expected/compose/rebased-two-mounts.tsv b/graph/test/typescript/hono/expected/compose/rebased-two-mounts.tsv new file mode 100644 index 000000000..c934ad7be --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/rebased-two-mounts.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m33: both sub-apps on the rebasable holder are one partial each (dynamic_mount_prefix), no exact rows +# census: basepath (stress-4 mutation m33 shape; violations hono-3-01, hono-4-04) +partial index.ts:11:30 POST dynamic_mount_prefix +partial index.ts:9:29 GET dynamic_mount_prefix +unknown index.ts:29:1 dynamic_mount_prefix index.ts:9:29 +unknown index.ts:30:1 dynamic_mount_prefix index.ts:11:30 diff --git a/graph/test/typescript/hono/expected/compose/reexport-barrel.entries b/graph/test/typescript/hono/expected/compose/reexport-barrel.entries new file mode 100644 index 000000000..e0898650b --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/reexport-barrel.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: sub-app resolved through export { default as } from +# census: reexport_default_as, route_mount_literal +entry routes/books.ts:4:16 http diff --git a/graph/test/typescript/hono/expected/compose/reexport-barrel.tsv b/graph/test/typescript/hono/expected/compose/reexport-barrel.tsv new file mode 100644 index 000000000..768aac219 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/reexport-barrel.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: sub-app resolved through export { default as } from +# census: reexport_default_as, route_mount_literal +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /books routes/books.ts:4:16 index.ts:6:13 0 +submount /books index.ts:7:5 +regby routes/books.ts:1:1 routes/books.ts:4:16 GET /books index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/compose/register-fn.entries b/graph/test/typescript/hono/expected/compose/register-fn.entries new file mode 100644 index 000000000..4182914ae --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/register-fn.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: registerUsers' routes spliced at the call (order 1-2); typeof-param registration mounted at /v1 +# census: app_factory_fn +entry index.ts:13:18 http +entry index.ts:9:14 http +entry monitors.ts:6:24 http +entry users.ts:4:21 http +entry users.ts:5:22 http diff --git a/graph/test/typescript/hono/expected/compose/register-fn.tsv b/graph/test/typescript/hono/expected/compose/register-fn.tsv new file mode 100644 index 000000000..9f3317782 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/register-fn.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: registerUsers' routes spliced at the call (order 1-2); typeof-param registration mounted at /v1 +# census: app_factory_fn +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.ts:9:14 index.ts:8:13 0 +route GET /users users.ts:4:21 index.ts:8:13 1 +route POST /users users.ts:5:22 index.ts:8:13 2 +route GET /v1/monitors monitors.ts:6:24 index.ts:8:13 3 +route GET /last index.ts:13:18 index.ts:8:13 4 +submount /v1 index.ts:12:5 +regby index.ts:1:1 index.ts:13:18 GET /last index.ts:8:13 +regby index.ts:1:1 index.ts:9:14 GET / index.ts:8:13 +regby monitors.ts:5:1 monitors.ts:6:24 GET /v1/monitors index.ts:8:13 +regby users.ts:3:1 users.ts:4:21 GET /users index.ts:8:13 +regby users.ts:3:1 users.ts:5:22 POST /users index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/compose/register-loop-plugins.entries b/graph/test/typescript/hono/expected/compose/register-loop-plugins.entries new file mode 100644 index 000000000..17b46a775 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/register-loop-plugins.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O11: plugins mounted in a loop by an uncalled register(app: Hono): partial unresolved_app_value, never roots +# census: route_mount_literal (oracle gap O11; SPEC 2 a mount argument is never a root) +entry plugins.ts:3:45 http +entry plugins.ts:4:41 http diff --git a/graph/test/typescript/hono/expected/compose/register-loop-plugins.tsv b/graph/test/typescript/hono/expected/compose/register-loop-plugins.tsv new file mode 100644 index 000000000..a97d414b4 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/register-loop-plugins.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O11: plugins mounted in a loop by an uncalled register(app: Hono): partial unresolved_app_value, never roots +# census: route_mount_literal (oracle gap O11; SPEC 2 a mount argument is never a root) +partial plugins.ts:3:45 GET unresolved_app_value +partial plugins.ts:4:41 GET unresolved_app_value +unknown register.ts:9:5 unresolved_app_value plugins.ts:3:45 +unknown register.ts:9:5 unresolved_app_value plugins.ts:4:41 diff --git a/graph/test/typescript/hono/expected/compose/registered-by.entries b/graph/test/typescript/hono/expected/compose/registered-by.entries new file mode 100644 index 000000000..d10433862 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/registered-by.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route_registered_by: registerGetMonitor and registerListMonitors for the /v1 routes, the module initializer for / +# census: app_factory_fn (SPEC 4 [iter2] route_registered_by: the method enclosing each registering call) +entry index.ts:11:14 http +entry monitors.ts:4:28 http +entry monitors.ts:7:24 http +entry monitors.ts:8:25 http diff --git a/graph/test/typescript/hono/expected/compose/registered-by.tsv b/graph/test/typescript/hono/expected/compose/registered-by.tsv new file mode 100644 index 000000000..a93b00ee9 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/registered-by.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route_registered_by: registerGetMonitor and registerListMonitors for the /v1 routes, the module initializer for / +# census: app_factory_fn (SPEC 4 [iter2] route_registered_by: the method enclosing each registering call) +route GET / index.ts:11:14 index.ts:10:13 0 +route GET /v1/monitors/:id monitors.ts:4:28 index.ts:10:13 1 +route GET /v1/monitors monitors.ts:7:24 index.ts:10:13 2 +route POST /v1/monitors monitors.ts:8:25 index.ts:10:13 3 +submount /v1 index.ts:12:5 +regby index.ts:1:1 index.ts:11:14 GET / index.ts:10:13 +regby monitors.ts:3:1 monitors.ts:4:28 GET /v1/monitors/:id index.ts:10:13 +regby monitors.ts:6:1 monitors.ts:7:24 GET /v1/monitors index.ts:10:13 +regby monitors.ts:6:1 monitors.ts:8:25 POST /v1/monitors index.ts:10:13 diff --git a/graph/test/typescript/hono/expected/compose/returned-object-destructure.entries b/graph/test/typescript/hono/expected/compose/returned-object-destructure.entries new file mode 100644 index 000000000..72565c301 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/returned-object-destructure.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01/O30: each destructured name (one renamed) takes only its own property: stock, orders, audit under /v1 with their own handlers; no unmounted copies +# census: route_mount_literal, app_factory_fn (violation hono-7-01, P1 false_route: sub-apps read out of an +entry routes/audit.ts:5:24 http +entry routes/orders.ts:5:25 http +entry routes/orders.ts:6:27 http +entry routes/stock.ts:5:18 http +entry routes/stock.ts:6:25 http diff --git a/graph/test/typescript/hono/expected/compose/returned-object-destructure.tsv b/graph/test/typescript/hono/expected/compose/returned-object-destructure.tsv new file mode 100644 index 000000000..e0def1d9f --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/returned-object-destructure.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01/O30: each destructured name (one renamed) takes only its own property: stock, orders, audit under /v1 with their own handlers; no unmounted copies +# census: route_mount_literal, app_factory_fn (violation hono-7-01, P1 false_route: sub-apps read out of an +route GET /v1/stock routes/stock.ts:5:18 index.ts:10:13 0 +route DELETE /v1/stock/:sku routes/stock.ts:6:25 index.ts:10:13 1 +route GET /v1/orders/recent routes/orders.ts:5:25 index.ts:10:13 2 +route PUT /v1/orders/:orderId routes/orders.ts:6:27 index.ts:10:13 3 +route POST /v1/audit/flush routes/audit.ts:5:24 index.ts:10:13 4 +submount /stock index.ts:12:4 +submount /orders index.ts:13:4 +submount /audit index.ts:14:4 +submount /v1 index.ts:15:5 +regby routes/audit.ts:3:1 routes/audit.ts:5:24 POST /v1/audit/flush index.ts:10:13 +regby routes/orders.ts:3:1 routes/orders.ts:5:25 GET /v1/orders/recent index.ts:10:13 +regby routes/orders.ts:3:1 routes/orders.ts:6:27 PUT /v1/orders/:orderId index.ts:10:13 +regby routes/stock.ts:3:1 routes/stock.ts:5:18 GET /v1/stock index.ts:10:13 +regby routes/stock.ts:3:1 routes/stock.ts:6:25 DELETE /v1/stock/:sku index.ts:10:13 diff --git a/graph/test/typescript/hono/expected/compose/returned-object-member.entries b/graph/test/typescript/hono/expected/compose/returned-object-member.entries new file mode 100644 index 000000000..49066f03e --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/returned-object-member.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01: each rt.p read takes only its own property: stock, orders, audit under /v1 with their own handlers +# census: route_mount_literal, prop_receiver_route, app_factory_fn (violation hono-7-01, P1 false_route: sub-apps +entry routes/audit.ts:5:24 http +entry routes/orders.ts:5:25 http +entry routes/orders.ts:6:27 http +entry routes/stock.ts:5:18 http +entry routes/stock.ts:6:25 http diff --git a/graph/test/typescript/hono/expected/compose/returned-object-member.tsv b/graph/test/typescript/hono/expected/compose/returned-object-member.tsv new file mode 100644 index 000000000..c7e9dab7f --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/returned-object-member.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-01: each rt.p read takes only its own property: stock, orders, audit under /v1 with their own handlers +# census: route_mount_literal, prop_receiver_route, app_factory_fn (violation hono-7-01, P1 false_route: sub-apps +route GET /v1/stock routes/stock.ts:5:18 index.ts:10:13 0 +route DELETE /v1/stock/:sku routes/stock.ts:6:25 index.ts:10:13 1 +route GET /v1/orders/recent routes/orders.ts:5:25 index.ts:10:13 2 +route PUT /v1/orders/:orderId routes/orders.ts:6:27 index.ts:10:13 3 +route POST /v1/audit/flush routes/audit.ts:5:24 index.ts:10:13 4 +submount /stock index.ts:12:4 +submount /orders index.ts:13:4 +submount /audit index.ts:14:4 +submount /v1 index.ts:15:5 +regby routes/audit.ts:3:1 routes/audit.ts:5:24 POST /v1/audit/flush index.ts:10:13 +regby routes/orders.ts:3:1 routes/orders.ts:5:25 GET /v1/orders/recent index.ts:10:13 +regby routes/orders.ts:3:1 routes/orders.ts:6:27 PUT /v1/orders/:orderId index.ts:10:13 +regby routes/stock.ts:3:1 routes/stock.ts:5:18 GET /v1/stock index.ts:10:13 +regby routes/stock.ts:3:1 routes/stock.ts:6:25 DELETE /v1/stock/:sku index.ts:10:13 diff --git a/graph/test/typescript/hono/expected/compose/route-and-partial.entries b/graph/test/typescript/hono/expected/compose/route-and-partial.entries new file mode 100644 index 000000000..f9a2b0768 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/route-and-partial.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O12: /memory is a route; the same handler under ctx.server is not also partial +# census: app_factory_fn (oracle gap O12) +entry index.ts:9:22 http diff --git a/graph/test/typescript/hono/expected/compose/route-and-partial.tsv b/graph/test/typescript/hono/expected/compose/route-and-partial.tsv new file mode 100644 index 000000000..f8c0427ad --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/route-and-partial.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O12: /memory is a route; the same handler under ctx.server is not also partial +# census: app_factory_fn (oracle gap O12) +route GET /memory index.ts:9:22 index.ts:12:13 0 +regby index.ts:8:1 index.ts:9:22 GET /memory index.ts:12:13 diff --git a/graph/test/typescript/hono/expected/compose/route-cross-module.entries b/graph/test/typescript/hono/expected/compose/route-cross-module.entries new file mode 100644 index 000000000..5fe97f441 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/route-cross-module.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: default-exported sub-app's three routes under /users; / local maps to /users +# census: route_mount_literal, export_default_app +entry index.ts:8:14 http +entry users.ts:5:16 http +entry users.ts:6:19 http +entry users.ts:7:17 http diff --git a/graph/test/typescript/hono/expected/compose/route-cross-module.tsv b/graph/test/typescript/hono/expected/compose/route-cross-module.tsv new file mode 100644 index 000000000..4c86cea9e --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/route-cross-module.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: default-exported sub-app's three routes under /users; / local maps to /users +# census: route_mount_literal, export_default_app +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.ts:8:14 index.ts:6:13 0 +route GET /users users.ts:5:16 index.ts:6:13 1 +route GET /users/:id users.ts:6:19 index.ts:6:13 2 +route POST /users users.ts:7:17 index.ts:6:13 3 +submount /users index.ts:9:5 +regby index.ts:1:1 index.ts:8:14 GET / index.ts:6:13 +regby users.ts:1:1 users.ts:5:16 GET /users index.ts:6:13 +regby users.ts:1:1 users.ts:6:19 GET /users/:id index.ts:6:13 +regby users.ts:1:1 users.ts:7:17 POST /users index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/compose/route-root.entries b/graph/test/typescript/hono/expected/compose/route-root.entries new file mode 100644 index 000000000..80ebefa61 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/route-root.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route('/') merges unprefixed, chained +# census: route_mount_root +entry index.ts:10:20 http +entry index.ts:6:21 http +entry index.ts:7:22 http diff --git a/graph/test/typescript/hono/expected/compose/route-root.tsv b/graph/test/typescript/hono/expected/compose/route-root.tsv new file mode 100644 index 000000000..42249d8d0 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/route-root.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route('/') merges unprefixed, chained +# census: route_mount_root +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /login index.ts:6:21 index.ts:12:13 0 +route POST /logout index.ts:7:22 index.ts:12:13 1 +route GET /about index.ts:10:20 index.ts:12:13 2 +submount / index.ts:13:20 +submount / index.ts:13:37 +regby index.ts:1:1 index.ts:10:20 GET /about index.ts:12:13 +regby index.ts:1:1 index.ts:6:21 POST /login index.ts:12:13 +regby index.ts:1:1 index.ts:7:22 POST /logout index.ts:12:13 diff --git a/graph/test/typescript/hono/expected/compose/same-sub-twice.entries b/graph/test/typescript/hono/expected/compose/same-sub-twice.entries new file mode 100644 index 000000000..d73a13e61 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/same-sub-twice.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: one handler, two routes +# census: route_mount_literal +entry index.ts:6:23 http diff --git a/graph/test/typescript/hono/expected/compose/same-sub-twice.tsv b/graph/test/typescript/hono/expected/compose/same-sub-twice.tsv new file mode 100644 index 000000000..e154ffa45 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/same-sub-twice.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: one handler, two routes +# census: route_mount_literal +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /a/health index.ts:6:23 index.ts:8:13 0 +route GET /b/health index.ts:6:23 index.ts:8:13 1 +submount /a index.ts:9:5 +submount /b index.ts:10:5 +regby index.ts:1:1 index.ts:6:23 GET /a/health index.ts:8:13 +regby index.ts:1:1 index.ts:6:23 GET /b/health index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/compose/self-basepath-field.entries b/graph/test/typescript/hono/expected/compose/self-basepath-field.entries new file mode 100644 index 000000000..5d634c2c3 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/self-basepath-field.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-04/R8: one partial for /x (dynamic_mount_prefix), not one row per path +# census: basepath (violation hono-2-04, SPEC R8) +entry index.ts:20:20 http diff --git a/graph/test/typescript/hono/expected/compose/self-basepath-field.tsv b/graph/test/typescript/hono/expected/compose/self-basepath-field.tsv new file mode 100644 index 000000000..95a84632f --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/self-basepath-field.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-04/R8: one partial for /x (dynamic_mount_prefix), not one row per path +# census: basepath (violation hono-2-04, SPEC R8) +partial index.ts:20:20 GET dynamic_mount_prefix +unknown index.ts:20:1 dynamic_mount_prefix index.ts:20:20 diff --git a/graph/test/typescript/hono/expected/compose/shared-factory-filtered-loop.entries b/graph/test/typescript/hono/expected/compose/shared-factory-filtered-loop.entries new file mode 100644 index 000000000..8ed00f3be --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/shared-factory-filtered-loop.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m35b/hono-5-02: per-call apps; /reports guard 0; /exports guard 0 (from reports), guard 1, quota 2, declared dynamic_middleware_list; exact plus conditional +# census: route_mount_root (stress-5 mutation m35b shape; violation hono-5-02, SPEC R6 and R13b) +entry index.ts:12:21 http +entry index.ts:30:23 http +entry index.ts:37:23 http +entry index.ts:9:21 http diff --git a/graph/test/typescript/hono/expected/compose/shared-factory-filtered-loop.tsv b/graph/test/typescript/hono/expected/compose/shared-factory-filtered-loop.tsv new file mode 100644 index 000000000..52a1da034 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/shared-factory-filtered-loop.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m35b/hono-5-02: per-call apps; /reports guard 0; /exports guard 0 (from reports), guard 1, quota 2, declared dynamic_middleware_list; exact plus conditional +# census: route_mount_root (stress-5 mutation m35b shape; violation hono-5-02, SPEC R6 and R13b) +# iteration 8: repeated rows removed (O29: the oracle prints each row once); the row set is unchanged +route GET /reports index.ts:30:23 index.ts:44:13 1 +route GET /exports index.ts:37:23 index.ts:44:13 4 +mw index.ts:9:21 index.ts:30:23 GET /reports 0 index.ts:44:13 +mw index.ts:9:21 index.ts:37:23 GET /exports 0 index.ts:44:13 +mw index.ts:9:21 index.ts:37:23 GET /exports 1 index.ts:44:13 +mw index.ts:12:21 index.ts:37:23 GET /exports 2 index.ts:44:13 +submount / index.ts:46:27 +regby index.ts:28:3 index.ts:30:23 GET /reports index.ts:44:13 +regby index.ts:35:3 index.ts:37:23 GET /exports index.ts:44:13 +unknown index.ts:37:5 dynamic_middleware_list index.ts:37:23 +unknown index.ts:46:23 conditional_registration index.ts:30:23 +unknown index.ts:46:23 conditional_registration index.ts:37:23 diff --git a/graph/test/typescript/hono/expected/compose/sync-wrapper-mount.entries b/graph/test/typescript/hono/expected/compose/sync-wrapper-mount.entries new file mode 100644 index 000000000..ed91e70bc --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/sync-wrapper-mount.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m38b/hono-5-06: the sync wrapper serves both inner routes behind its use(*) +# census: bun_serve (stress-5 mutation m38b shape; violation hono-5-06) +entry main.ts:10:21 http +entry main.ts:9:21 http +entry wrap.ts:5:20 http diff --git a/graph/test/typescript/hono/expected/compose/sync-wrapper-mount.tsv b/graph/test/typescript/hono/expected/compose/sync-wrapper-mount.tsv new file mode 100644 index 000000000..2894ad635 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/sync-wrapper-mount.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m38b/hono-5-06: the sync wrapper serves both inner routes behind its use(*) +# census: bun_serve (stress-5 mutation m38b shape; violation hono-5-06) +route GET /hello main.ts:9:21 wrap.ts:4:19 1 +route POST /echo main.ts:10:21 wrap.ts:4:19 2 +mw wrap.ts:5:20 main.ts:9:21 GET /hello 0 wrap.ts:4:19 +mw wrap.ts:5:20 main.ts:10:21 POST /echo 0 wrap.ts:4:19 +submount / wrap.ts:9:11 +regby main.ts:1:1 main.ts:10:21 POST /echo wrap.ts:4:19 +regby main.ts:1:1 main.ts:9:21 GET /hello wrap.ts:4:19 diff --git a/graph/test/typescript/hono/expected/compose/test-plugin-own-app.entries b/graph/test/typescript/hono/expected/compose/test-plugin-own-app.entries new file mode 100644 index 000000000..89d9ef383 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/test-plugin-own-app.entries @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R16/hono-6-02: test-built plugins (declarative definePlugin routes, register(app), direct mountPlugin) are routes ONLY of the test app that mounted them; production serves only its core plugins; a request inside an assertion argument reaches its own app (O26); a register-only plugin's absent routes mount nothing (no unresolved_mount) +# census: app_request_test, plugin_list_mount (SPEC R16; R6, R13b; violation hono-6-02; oracle gap O26) +entry __tests__/define-plugin.test.ts:10:37 http +entry __tests__/define-plugin.test.ts:22:47 http +entry __tests__/mount.test.ts:8:14 http +entry app.ts:10:22 http +entry plugins/audit.ts:5:16 http +entry plugins/audit.ts:6:19 http +entry plugins/tenants.ts:6:14 http diff --git a/graph/test/typescript/hono/expected/compose/test-plugin-own-app.tsv b/graph/test/typescript/hono/expected/compose/test-plugin-own-app.tsv new file mode 100644 index 000000000..014a66998 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/test-plugin-own-app.tsv @@ -0,0 +1,38 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R16/hono-6-02: test-built plugins (declarative definePlugin routes, register(app), direct mountPlugin) are routes ONLY of the test app that mounted them; production serves only its core plugins; a request inside an assertion argument reaches its own app (O26); a register-only plugin's absent routes mount nothing (no unresolved_mount) +# census: app_request_test, plugin_list_mount (SPEC R16; R6, R13b; violation hono-6-02; oracle gap O26) +route GET /api/defined __tests__/define-plugin.test.ts:10:37 __tests__/define-plugin.test.ts:12:17 0 +route GET /imp __tests__/define-plugin.test.ts:22:47 __tests__/define-plugin.test.ts:25:17 0 +route GET /alpha __tests__/mount.test.ts:8:14 __tests__/mount.test.ts:13:15 0 +route GET /beta __tests__/mount.test.ts:8:14 __tests__/mount.test.ts:20:15 0 +route GET /gamma __tests__/mount.test.ts:8:14 __tests__/mount.test.ts:27:15 0 +route GET /health app.ts:10:22 app.ts:9:15 0 +route GET /admin/audit plugins/audit.ts:5:16 app.ts:9:15 1 +route GET /admin/audit/:id plugins/audit.ts:6:19 app.ts:9:15 2 +route GET /admin/tenants plugins/tenants.ts:6:14 app.ts:9:15 3 +request __tests__/define-plugin.test.ts:18:37 GET /imp __tests__/define-plugin.test.ts:22:47 +request __tests__/define-plugin.test.ts:9:63 GET /api/defined __tests__/define-plugin.test.ts:10:37 +request __tests__/mount.test.ts:12:25 GET /alpha __tests__/mount.test.ts:8:14 +request __tests__/mount.test.ts:19:31 GET /beta __tests__/mount.test.ts:8:14 +request __tests__/mount.test.ts:26:30 GET /gamma __tests__/mount.test.ts:8:14 +submount /api/defined sdk.ts:34:11 +submount /imp __tests__/define-plugin.test.ts:22:13 +submount /alpha sdk.ts:34:11 +submount /beta sdk.ts:34:11 +submount /gamma sdk.ts:34:11 +submount /admin/audit sdk.ts:34:11 +submount /admin/tenants plugins/tenants.ts:13:9 +regby __tests__/define-plugin.test.ts:21:7 __tests__/define-plugin.test.ts:22:47 GET /imp __tests__/define-plugin.test.ts:25:17 +regby __tests__/define-plugin.test.ts:9:63 __tests__/define-plugin.test.ts:10:37 GET /api/defined __tests__/define-plugin.test.ts:12:17 +regby __tests__/mount.test.ts:6:1 __tests__/mount.test.ts:8:14 GET /alpha __tests__/mount.test.ts:13:15 +regby __tests__/mount.test.ts:6:1 __tests__/mount.test.ts:8:14 GET /beta __tests__/mount.test.ts:20:15 +regby __tests__/mount.test.ts:6:1 __tests__/mount.test.ts:8:14 GET /gamma __tests__/mount.test.ts:27:15 +regby app.ts:8:1 app.ts:10:22 GET /health app.ts:9:15 +regby plugins/audit.ts:1:1 plugins/audit.ts:5:16 GET /admin/audit app.ts:9:15 +regby plugins/audit.ts:1:1 plugins/audit.ts:6:19 GET /admin/audit/:id app.ts:9:15 +regby plugins/tenants.ts:4:1 plugins/tenants.ts:6:14 GET /admin/tenants app.ts:9:15 +unknown __tests__/define-plugin.test.ts:22:9 conditional_registration __tests__/define-plugin.test.ts:22:47 +unknown plugins/tenants.ts:13:5 conditional_registration plugins/tenants.ts:6:14 +unknown sdk.ts:34:7 conditional_registration __tests__/define-plugin.test.ts:10:37 +unknown sdk.ts:34:7 conditional_registration __tests__/mount.test.ts:8:14 +unknown sdk.ts:34:7 conditional_registration plugins/audit.ts:5:16 +unknown sdk.ts:34:7 conditional_registration plugins/audit.ts:6:19 diff --git a/graph/test/typescript/hono/expected/compose/typed-property-receiver.entries b/graph/test/typescript/hono/expected/compose/typed-property-receiver.entries new file mode 100644 index 000000000..b0edd6dfa --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/typed-property-receiver.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-01/R2: route() on ctx.server (declared Hono, value unseen): /raw is partial unresolved_app_value, never a root route +# census: route_mount_literal (violation hono-1-01; SPEC R2) +entry index.ts:13:19 http diff --git a/graph/test/typescript/hono/expected/compose/typed-property-receiver.tsv b/graph/test/typescript/hono/expected/compose/typed-property-receiver.tsv new file mode 100644 index 000000000..90aef2497 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/typed-property-receiver.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-01/R2: route() on ctx.server (declared Hono, value unseen): /raw is partial unresolved_app_value, never a root route +# census: route_mount_literal (violation hono-1-01; SPEC R2) +partial index.ts:13:19 GET unresolved_app_value +unknown index.ts:19:3 unresolved_app_value index.ts:13:19 diff --git a/graph/test/typescript/hono/expected/compose/uncalled-start-server.entries b/graph/test/typescript/hono/expected/compose/uncalled-start-server.entries new file mode 100644 index 000000000..c65060e2c --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/uncalled-start-server.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O2: startServer is never called in the program yet its body runs: /api/status is mounted under /api, the sub-app is not served bare +# census: app_factory_fn (oracle gap O2) +entry api.ts:4:20 http diff --git a/graph/test/typescript/hono/expected/compose/uncalled-start-server.tsv b/graph/test/typescript/hono/expected/compose/uncalled-start-server.tsv new file mode 100644 index 000000000..4e8063e79 --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/uncalled-start-server.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O2: startServer is never called in the program yet its body runs: /api/status is mounted under /api, the sub-app is not served bare +# census: app_factory_fn (oracle gap O2) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/status api.ts:4:20 server.ts:8:15 0 +submount /api server.ts:9:7 +regby api.ts:1:1 api.ts:4:20 GET /api/status server.ts:8:15 diff --git a/graph/test/typescript/hono/expected/compose/workspace-unlisted-subpath-bundler.entries b/graph/test/typescript/hono/expected/compose/workspace-unlisted-subpath-bundler.entries new file mode 100644 index 000000000..ad53e117e --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/workspace-unlisted-subpath-bundler.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and tsc --traceResolution on a real workspace link (not resolved under bundler): R22a: the unlisted subpath import is unbound, so app.route(/adapters) is unresolved_mount and nothing is served under /adapters; the never-mounted adapters app keeps its own root row (/list), as every never-mounted exported app does +# census: workspace_subpath (SPEC R22a; violation hono-5-06 shape) +entry apps/api/src/index.ts:11:20 http +entry packages/core/adapters/index.ts:5:23 http diff --git a/graph/test/typescript/hono/expected/compose/workspace-unlisted-subpath-bundler.tsv b/graph/test/typescript/hono/expected/compose/workspace-unlisted-subpath-bundler.tsv new file mode 100644 index 000000000..c07ea2f9e --- /dev/null +++ b/graph/test/typescript/hono/expected/compose/workspace-unlisted-subpath-bundler.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and tsc --traceResolution on a real workspace link (not resolved under bundler): R22a: the unlisted subpath import is unbound, so app.route(/adapters) is unresolved_mount and nothing is served under /adapters; the never-mounted adapters app keeps its own root row (/list), as every never-mounted exported app does +# census: workspace_subpath (SPEC R22a; violation hono-5-06 shape) +route GET /health apps/api/src/index.ts:11:20 apps/api/src/index.ts:10:13 0 +route GET /list packages/core/adapters/index.ts:5:23 packages/core/adapters/index.ts:4:25 0 +regby apps/api/src/index.ts:1:1 apps/api/src/index.ts:11:20 GET /health apps/api/src/index.ts:10:13 +regby packages/core/adapters/index.ts:1:1 packages/core/adapters/index.ts:5:23 GET /list packages/core/adapters/index.ts:4:25 +unknown apps/api/src/index.ts:12:1 unresolved_mount apps/api/src/index.ts:1:1 diff --git a/graph/test/typescript/hono/expected/context/chain-of-setters.entries b/graph/test/typescript/hono/expected/context/chain-of-setters.entries new file mode 100644 index 000000000..2b8f6f217 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/chain-of-setters.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: lang flows to greet and the handler; greeting flows to the handler +# census: ctx_set, ctx_get, verb_multi_handler +entry index.ts:12:39 http +entry index.ts:18:38 http +entry index.ts:8:44 http diff --git a/graph/test/typescript/hono/expected/context/chain-of-setters.tsv b/graph/test/typescript/hono/expected/context/chain-of-setters.tsv new file mode 100644 index 000000000..b9acc950a --- /dev/null +++ b/graph/test/typescript/hono/expected/context/chain-of-setters.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: lang flows to greet and the handler; greeting flows to the handler +# census: ctx_set, ctx_get, verb_multi_handler +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /hello index.ts:18:38 index.ts:17:13 2 +mw index.ts:8:44 index.ts:18:38 GET /hello 0 index.ts:17:13 +mw index.ts:12:39 index.ts:18:38 GET /hello 1 index.ts:17:13 +ctx index.ts:12:39 index.ts:18:38 greeting +ctx index.ts:8:44 index.ts:12:39 lang +ctx index.ts:8:44 index.ts:18:38 lang +regby index.ts:1:1 index.ts:18:38 GET /hello index.ts:17:13 diff --git a/graph/test/typescript/hono/expected/context/closure-access.entries b/graph/test/typescript/hono/expected/context/closure-access.entries new file mode 100644 index 000000000..f64b92a4d --- /dev/null +++ b/graph/test/typescript/hono/expected/context/closure-access.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user is set, and both keys are read, in callbacks nested in the middleware and the handler; they run during the request, so both keys reach the handler +# census: ctx_set_in_callback, ctx_get_in_callback +entry index.ts:14:14 http +entry index.ts:9:9 http diff --git a/graph/test/typescript/hono/expected/context/closure-access.tsv b/graph/test/typescript/hono/expected/context/closure-access.tsv new file mode 100644 index 000000000..f9929bc42 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/closure-access.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user is set, and both keys are read, in callbacks nested in the middleware and the handler; they run during the request, so both keys reach the handler +# census: ctx_set_in_callback, ctx_get_in_callback +route GET / index.ts:14:14 index.ts:7:13 1 +mw index.ts:9:9 index.ts:14:14 GET / 0 index.ts:7:13 +ctx index.ts:9:9 index.ts:14:14 role +ctx index.ts:9:9 index.ts:14:14 user +regby index.ts:1:1 index.ts:14:14 GET / index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/context/cross-module.entries b/graph/test/typescript/hono/expected/context/cross-module.entries new file mode 100644 index 000000000..870caf078 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/cross-module.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: session flows from auth.ts to both mounted handlers; DELETE reads before it sets, so no self flow +# census: ctx_set, ctx_get, route_mount_literal +entry auth.ts:5:50 http +entry routes.ts:6:18 http +entry routes.ts:7:21 http diff --git a/graph/test/typescript/hono/expected/context/cross-module.tsv b/graph/test/typescript/hono/expected/context/cross-module.tsv new file mode 100644 index 000000000..314abab65 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/cross-module.tsv @@ -0,0 +1,13 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: session flows from auth.ts to both mounted handlers; DELETE reads before it sets, so no self flow +# census: ctx_set, ctx_get, route_mount_literal +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /account routes.ts:6:18 index.ts:8:13 1 +route DELETE /account routes.ts:7:21 index.ts:8:13 2 +mw auth.ts:5:50 routes.ts:6:18 GET /account 0 index.ts:8:13 +mw auth.ts:5:50 routes.ts:7:21 DELETE /account 0 index.ts:8:13 +ctx auth.ts:5:50 routes.ts:6:18 session +ctx auth.ts:5:50 routes.ts:7:21 session +submount /account index.ts:10:5 +regby routes.ts:1:1 routes.ts:6:18 GET /account index.ts:8:13 +regby routes.ts:1:1 routes.ts:7:21 DELETE /account index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/context/destructured-var.entries b/graph/test/typescript/hono/expected/context/destructured-var.entries new file mode 100644 index 000000000..32ba362af --- /dev/null +++ b/graph/test/typescript/hono/expected/context/destructured-var.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: db and origin flow to /both through a destructured c.var, origin to /one by name +entry index.ts:10:13 http +entry index.ts:19:18 http +entry index.ts:23:17 http diff --git a/graph/test/typescript/hono/expected/context/destructured-var.tsv b/graph/test/typescript/hono/expected/context/destructured-var.tsv new file mode 100644 index 000000000..4ef165c30 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/destructured-var.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: db and origin flow to /both through a destructured c.var, origin to /one by name +route GET /both index.ts:19:18 index.ts:18:13 1 +route GET /one index.ts:23:17 index.ts:18:13 2 +mw index.ts:10:13 index.ts:19:18 GET /both 0 index.ts:18:13 +mw index.ts:10:13 index.ts:23:17 GET /one 0 index.ts:18:13 +ctx index.ts:10:13 index.ts:19:18 db +ctx index.ts:10:13 index.ts:19:18 origin +ctx index.ts:10:13 index.ts:23:17 origin +regby index.ts:1:1 index.ts:19:18 GET /both index.ts:18:13 +regby index.ts:1:1 index.ts:23:17 GET /one index.ts:18:13 diff --git a/graph/test/typescript/hono/expected/context/early-return-next.entries b/graph/test/typescript/hono/expected/context/early-return-next.entries new file mode 100644 index 000000000..5d9103391 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/early-return-next.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user and role are set before the next() that runs on their path (the early next() is in a branch), so both reach the handler +# census: ctx_set, ctx_get, ctx_next_in_branch +entry index.ts:14:9 http +entry index.ts:22:14 http +entry index.ts:9:9 http diff --git a/graph/test/typescript/hono/expected/context/early-return-next.tsv b/graph/test/typescript/hono/expected/context/early-return-next.tsv new file mode 100644 index 000000000..88c18baf9 --- /dev/null +++ b/graph/test/typescript/hono/expected/context/early-return-next.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: user and role are set before the next() that runs on their path (the early next() is in a branch), so both reach the handler +# census: ctx_set, ctx_get, ctx_next_in_branch +route GET / index.ts:22:14 index.ts:7:13 2 +mw index.ts:9:9 index.ts:22:14 GET / 0 index.ts:7:13 +mw index.ts:14:9 index.ts:22:14 GET / 1 index.ts:7:13 +ctx index.ts:14:9 index.ts:22:14 role +ctx index.ts:9:9 index.ts:22:14 user +regby index.ts:1:1 index.ts:22:14 GET / index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/context/set-after-next.entries b/graph/test/typescript/hono/expected/context/set-after-next.entries new file mode 100644 index 000000000..a95fce9ad --- /dev/null +++ b/graph/test/typescript/hono/expected/context/set-after-next.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: started flows to the handler; finished is set after next() and is read back only by the middleware itself +entry index.ts:10:9 http +entry index.ts:16:14 http diff --git a/graph/test/typescript/hono/expected/context/set-after-next.tsv b/graph/test/typescript/hono/expected/context/set-after-next.tsv new file mode 100644 index 000000000..e38eca2eb --- /dev/null +++ b/graph/test/typescript/hono/expected/context/set-after-next.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-29 against the fixture, the oracle and a run of the pinned hono: started flows to the handler; finished is set after next() and is read back only by the middleware itself +route GET / index.ts:16:14 index.ts:8:13 1 +mw index.ts:10:9 index.ts:16:14 GET / 0 index.ts:8:13 +ctx index.ts:10:9 index.ts:10:9 finished +ctx index.ts:10:9 index.ts:10:9 started +ctx index.ts:10:9 index.ts:16:14 started +regby index.ts:1:1 index.ts:16:14 GET / index.ts:8:13 +unknown index.ts:16:14 no_setter_on_chain index.ts:16:14 diff --git a/graph/test/typescript/hono/expected/context/set-get.entries b/graph/test/typescript/hono/expected/context/set-get.entries new file mode 100644 index 000000000..b419b4a1c --- /dev/null +++ b/graph/test/typescript/hono/expected/context/set-get.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: user/tenant flow from loadUser to /me and /tenant; /before (registered before the use) and traceId have no setter +# census: ctx_set, ctx_get, ctx_var, variables_type +entry index.ts:16:20 http +entry index.ts:18:16 http +entry index.ts:19:20 http +entry index.ts:20:19 http +entry index.ts:9:40 http diff --git a/graph/test/typescript/hono/expected/context/set-get.tsv b/graph/test/typescript/hono/expected/context/set-get.tsv new file mode 100644 index 000000000..be14ea3de --- /dev/null +++ b/graph/test/typescript/hono/expected/context/set-get.tsv @@ -0,0 +1,19 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: user/tenant flow from loadUser to /me and /tenant; /before (registered before the use) and traceId have no setter +# census: ctx_set, ctx_get, ctx_var, variables_type +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /before index.ts:16:20 index.ts:15:13 0 +route GET /me index.ts:18:16 index.ts:15:13 2 +route GET /tenant index.ts:19:20 index.ts:15:13 3 +route GET /trace index.ts:20:19 index.ts:15:13 4 +mw index.ts:9:40 index.ts:18:16 GET /me 0 index.ts:15:13 +mw index.ts:9:40 index.ts:19:20 GET /tenant 0 index.ts:15:13 +mw index.ts:9:40 index.ts:20:19 GET /trace 0 index.ts:15:13 +ctx index.ts:9:40 index.ts:18:16 user +ctx index.ts:9:40 index.ts:19:20 tenant +regby index.ts:1:1 index.ts:16:20 GET /before index.ts:15:13 +regby index.ts:1:1 index.ts:18:16 GET /me index.ts:15:13 +regby index.ts:1:1 index.ts:19:20 GET /tenant index.ts:15:13 +regby index.ts:1:1 index.ts:20:19 GET /trace index.ts:15:13 +unknown index.ts:16:20 no_setter_on_chain index.ts:16:20 +unknown index.ts:20:19 no_setter_on_chain index.ts:20:19 diff --git a/graph/test/typescript/hono/expected/deno/denoland-url.entries b/graph/test/typescript/hono/expected/deno/denoland-url.entries new file mode 100644 index 000000000..289dfcc59 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/denoland-url.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: deno.land/x URL mod.ts app, etag from middleware.ts; export default app +# census: none (corpus gap). https://deno.land/x/hono@v3.x/mod.ts and /middleware.ts: shape from Hono's Deno docs (v3 era), corpus gap. +entry main.ts:8:17 http diff --git a/graph/test/typescript/hono/expected/deno/denoland-url.tsv b/graph/test/typescript/hono/expected/deno/denoland-url.tsv new file mode 100644 index 000000000..e0ad2d612 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/denoland-url.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: deno.land/x URL mod.ts app, etag from middleware.ts; export default app +# census: none (corpus gap). https://deno.land/x/hono@v3.x/mod.ts and /middleware.ts: shape from Hono's Deno docs (v3 era), corpus gap. +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /url main.ts:8:17 main.ts:6:13 1 +mw lib:hono/middleware.etag@main.ts:7:9 main.ts:8:17 GET /url 0 main.ts:6:13 +regby main.ts:1:1 main.ts:8:17 GET /url main.ts:6:13 diff --git a/graph/test/typescript/hono/expected/deno/import-map-deno-json.entries b/graph/test/typescript/hono/expected/deno/import-map-deno-json.entries new file mode 100644 index 000000000..b2da2aea0 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/import-map-deno-json.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: deno.json exact and prefix maps; ./routes/users.ts with extension mounted at /users; secureHeaders before both +# census: route_mount_literal, export_default_app; bare 'hono' mapped by deno.json imports (exact and the +entry routes/users.ts:4:16 http +entry routes/users.ts:5:19 http diff --git a/graph/test/typescript/hono/expected/deno/import-map-deno-json.tsv b/graph/test/typescript/hono/expected/deno/import-map-deno-json.tsv new file mode 100644 index 000000000..90b280c3b --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/import-map-deno-json.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: deno.json exact and prefix maps; ./routes/users.ts with extension mounted at /users; secureHeaders before both +# census: route_mount_literal, export_default_app; bare 'hono' mapped by deno.json imports (exact and the +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /users routes/users.ts:4:16 main.ts:8:13 1 +route GET /users/:id routes/users.ts:5:19 main.ts:8:13 2 +mw lib:hono/secure-headers.secureHeaders@main.ts:9:9 routes/users.ts:4:16 GET /users 0 main.ts:8:13 +mw lib:hono/secure-headers.secureHeaders@main.ts:9:9 routes/users.ts:5:19 GET /users/:id 0 main.ts:8:13 +submount /users main.ts:10:5 +regby routes/users.ts:1:1 routes/users.ts:4:16 GET /users main.ts:8:13 +regby routes/users.ts:1:1 routes/users.ts:5:19 GET /users/:id main.ts:8:13 diff --git a/graph/test/typescript/hono/expected/deno/import-map-file.entries b/graph/test/typescript/hono/expected/deno/import-map-file.entries new file mode 100644 index 000000000..3afd66a0d --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/import-map-file.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: import_map.json to npm:hono@4; hono/factory via the prefix map; createMiddleware's arg is the middleware +# census: none (corpus gap). a standalone import_map.json mapping bare hono to npm:hono@4 (prefix map for hono/*): shape from Hono's +entry main.ts:11:20 http +entry main.ts:6:32 http diff --git a/graph/test/typescript/hono/expected/deno/import-map-file.tsv b/graph/test/typescript/hono/expected/deno/import-map-file.tsv new file mode 100644 index 000000000..af1775a11 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/import-map-file.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: import_map.json to npm:hono@4; hono/factory via the prefix map; createMiddleware's arg is the middleware +# census: none (corpus gap). a standalone import_map.json mapping bare hono to npm:hono@4 (prefix map for hono/*): shape from Hono's +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /mapped main.ts:11:20 main.ts:9:13 1 +mw main.ts:6:32 main.ts:11:20 GET /mapped 0 main.ts:9:13 +regby main.ts:1:1 main.ts:11:20 GET /mapped main.ts:9:13 diff --git a/graph/test/typescript/hono/expected/deno/import-map-jsonc.entries b/graph/test/typescript/hono/expected/deno/import-map-jsonc.entries new file mode 100644 index 000000000..f9cae2e1c --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/import-map-jsonc.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: bare @hono/hono through a commented deno.jsonc +# census: none (corpus gap). bare JSR name `@hono/hono` mapped by deno.jsonc (comments stripped): shape from Hono's Deno docs, corpus gap. +entry main.ts:5:19 http diff --git a/graph/test/typescript/hono/expected/deno/import-map-jsonc.tsv b/graph/test/typescript/hono/expected/deno/import-map-jsonc.tsv new file mode 100644 index 000000000..c36b0f6ae --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/import-map-jsonc.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: bare @hono/hono through a commented deno.jsonc +# census: none (corpus gap). bare JSR name `@hono/hono` mapped by deno.jsonc (comments stripped): shape from Hono's Deno docs, corpus gap. +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /jsonc main.ts:5:19 main.ts:4:13 0 +regby main.ts:1:1 main.ts:5:19 GET /jsonc main.ts:4:13 diff --git a/graph/test/typescript/hono/expected/deno/jsr-specifier.entries b/graph/test/typescript/hono/expected/deno/jsr-specifier.entries new file mode 100644 index 000000000..71475aa20 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/jsr-specifier.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: jsr:@hono/hono app with jsr logger: one route, logger before it; served by Deno.serve(app.fetch) +# census: deno_serve. jsr:@hono/hono and jsr:@hono/hono@^4/logger specifiers are a shape from Hono's Deno +entry main.ts:9:17 http diff --git a/graph/test/typescript/hono/expected/deno/jsr-specifier.tsv b/graph/test/typescript/hono/expected/deno/jsr-specifier.tsv new file mode 100644 index 000000000..bf5cdd1b4 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/jsr-specifier.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: jsr:@hono/hono app with jsr logger: one route, logger before it; served by Deno.serve(app.fetch) +# census: deno_serve. jsr:@hono/hono and jsr:@hono/hono@^4/logger specifiers are a shape from Hono's Deno +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /jsr main.ts:9:17 main.ts:7:13 1 +mw lib:hono/logger.logger@main.ts:8:9 main.ts:9:17 GET /jsr 0 main.ts:7:13 +regby main.ts:1:1 main.ts:9:17 GET /jsr main.ts:7:13 diff --git a/graph/test/typescript/hono/expected/deno/jsr-static-method.entries b/graph/test/typescript/hono/expected/deno/jsr-static-method.entries new file mode 100644 index 000000000..0a2ffda35 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/jsr-static-method.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Deno shape: import map below the root to jsr:, app from a static method with basePath /static: GET /static/logo.jpg +# census: deno_serve (shape of a Deno holdout project: a deno.json import map to jsr:, below the repository root, +entry api/main.ts:6:23 http diff --git a/graph/test/typescript/hono/expected/deno/jsr-static-method.tsv b/graph/test/typescript/hono/expected/deno/jsr-static-method.tsv new file mode 100644 index 000000000..cc4e9c65f --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/jsr-static-method.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Deno shape: import map below the root to jsr:, app from a static method with basePath /static: GET /static/logo.jpg +# census: deno_serve (shape of a Deno holdout project: a deno.json import map to jsr:, below the repository root, +route GET /static/logo.jpg api/main.ts:6:23 api/routes.ts:5:12 0 +regby api/main.ts:1:1 api/main.ts:6:23 GET /static/logo.jpg api/routes.ts:5:12 diff --git a/graph/test/typescript/hono/expected/deno/npm-specifier.entries b/graph/test/typescript/hono/expected/deno/npm-specifier.entries new file mode 100644 index 000000000..86b5f3eb1 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/npm-specifier.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: npm:hono@4 app with npm:hono/cors scoped to /api/*; Deno.serve({ port }, app.fetch) +# census: none (corpus gap). npm:hono@4 and npm:hono/cors specifiers: shape from Hono's Deno docs, corpus gap. Oracle maps them to the +entry main.ts:8:21 http diff --git a/graph/test/typescript/hono/expected/deno/npm-specifier.tsv b/graph/test/typescript/hono/expected/deno/npm-specifier.tsv new file mode 100644 index 000000000..8e7f4f3d4 --- /dev/null +++ b/graph/test/typescript/hono/expected/deno/npm-specifier.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: npm:hono@4 app with npm:hono/cors scoped to /api/*; Deno.serve({ port }, app.fetch) +# census: none (corpus gap). npm:hono@4 and npm:hono/cors specifiers: shape from Hono's Deno docs, corpus gap. Oracle maps them to the +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/npm main.ts:8:21 main.ts:6:13 1 +mw lib:hono/cors.cors@main.ts:7:19 main.ts:8:21 GET /api/npm 0 main.ts:6:13 +regby main.ts:1:1 main.ts:8:21 GET /api/npm main.ts:6:13 diff --git a/graph/test/typescript/hono/expected/entry/aliased-app-fetch-wrapper.entries b/graph/test/typescript/hono/expected/entry/aliased-app-fetch-wrapper.entries new file mode 100644 index 000000000..8e7a6ea1b --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/aliased-app-fetch-wrapper.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O4/R4: app from a tsconfig-path alias, served through a custom fetch object; app.fetch(req, env, ctx) forwards and is no request +# census: app_factory_fn, export_default_fetch_obj (oracle gap O4, SPEC R4) +entry index.ts:7:21 http diff --git a/graph/test/typescript/hono/expected/entry/aliased-app-fetch-wrapper.tsv b/graph/test/typescript/hono/expected/entry/aliased-app-fetch-wrapper.tsv new file mode 100644 index 000000000..b659389cf --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/aliased-app-fetch-wrapper.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O4/R4: app from a tsconfig-path alias, served through a custom fetch object; app.fetch(req, env, ctx) forwards and is no request +# census: app_factory_fn, export_default_fetch_obj (oracle gap O4, SPEC R4) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /aliased index.ts:7:21 lib/app.ts:4:10 0 +regby index.ts:1:1 index.ts:7:21 GET /aliased lib/app.ts:4:10 diff --git a/graph/test/typescript/hono/expected/entry/app-request-test.entries b/graph/test/typescript/hono/expected/entry/app-request-test.entries new file mode 100644 index 000000000..602e1a3d9 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/app-request-test.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: four test functions reach their routes (three app.request, one testClient); /nowhere is unserved +# census: app_request_test, test_client +entry app.ts:4:19 http +entry app.ts:5:19 http +entry app.ts:6:22 http diff --git a/graph/test/typescript/hono/expected/entry/app-request-test.tsv b/graph/test/typescript/hono/expected/entry/app-request-test.tsv new file mode 100644 index 000000000..941b7b15c --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/app-request-test.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: four test functions reach their routes (three app.request, one testClient); /nowhere is unserved +# census: app_request_test, test_client +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /health app.ts:4:19 app.ts:3:20 0 +route POST /items app.ts:5:19 app.ts:3:20 1 +route GET /items/:id app.ts:6:22 app.ts:3:20 2 +rpc app.test.ts:21:1 GET /health app.ts:4:19 +request app.test.ts:11:1 POST /items app.ts:5:19 +request app.test.ts:16:1 GET /items/42 app.ts:6:22 +request app.test.ts:6:1 GET /health app.ts:4:19 +regby app.ts:1:1 app.ts:4:19 GET /health app.ts:3:20 +regby app.ts:1:1 app.ts:5:19 POST /items app.ts:3:20 +regby app.ts:1:1 app.ts:6:22 GET /items/:id app.ts:3:20 +unserved app.test.ts:27:1 GET /nowhere diff --git a/graph/test/typescript/hono/expected/entry/deno-bun.entries b/graph/test/typescript/hono/expected/entry/deno-bun.entries new file mode 100644 index 000000000..b798074f8 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/deno-bun.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Deno.serve / Bun.serve inside a start function; the route from the exported app +# census: deno_serve, bun_serve +entry index.ts:9:18 http diff --git a/graph/test/typescript/hono/expected/entry/deno-bun.tsv b/graph/test/typescript/hono/expected/entry/deno-bun.tsv new file mode 100644 index 000000000..5718ac45d --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/deno-bun.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Deno.serve / Bun.serve inside a start function; the route from the exported app +# census: deno_serve, bun_serve +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /deno index.ts:9:18 index.ts:8:20 0 +regby index.ts:1:1 index.ts:9:18 GET /deno index.ts:8:20 diff --git a/graph/test/typescript/hono/expected/entry/dynamic-import-test-app.entries b/graph/test/typescript/hono/expected/entry/dynamic-import-test-app.entries new file mode 100644 index 000000000..86af346ec --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/dynamic-import-test-app.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O16: sub-apps bound by await import are mounted on R1 test roots; every request is served +# census: app_request_test (oracle gap O16; SPEC R1) +entry admin.ts:3:53 http +entry skills.test.ts:11:13 http +entry skills.ts:4:22 http +entry skills.ts:5:23 http diff --git a/graph/test/typescript/hono/expected/entry/dynamic-import-test-app.tsv b/graph/test/typescript/hono/expected/entry/dynamic-import-test-app.tsv new file mode 100644 index 000000000..832c6042d --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/dynamic-import-test-app.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O16: sub-apps bound by await import are mounted on R1 test roots; every request is served +# census: app_request_test (oracle gap O16; SPEC R1) +route GET /:ns/:name skills.ts:4:22 skills.test.ts:10:17 1 +route POST /:ns/:name skills.ts:5:23 skills.test.ts:10:17 2 +route GET /admin/stats admin.ts:3:53 skills.test.ts:27:15 0 +mw skills.test.ts:11:13 skills.ts:4:22 GET /:ns/:name 0 skills.test.ts:10:17 +mw skills.test.ts:11:13 skills.ts:5:23 POST /:ns/:name 0 skills.test.ts:10:17 +request skills.test.ts:17:21 GET /acme/review skills.ts:4:22 +request skills.test.ts:21:25 POST /acme/review skills.ts:5:23 +request skills.test.ts:25:25 GET /admin/stats admin.ts:3:53 +submount / skills.test.ts:15:4 +submount /admin skills.test.ts:27:26 +regby admin.ts:1:1 admin.ts:3:53 GET /admin/stats skills.test.ts:27:15 +regby skills.ts:1:1 skills.ts:4:22 GET /:ns/:name skills.test.ts:10:17 +regby skills.ts:1:1 skills.ts:5:23 POST /:ns/:name skills.test.ts:10:17 diff --git a/graph/test/typescript/hono/expected/entry/fetch-object.entries b/graph/test/typescript/hono/expected/entry/fetch-object.entries new file mode 100644 index 000000000..8fb3a84e5 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/fetch-object.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: fetch-object export: the route handler plus scheduled and queue are http entries +# census: export_default_fetch_obj, app_fetch_ref +entry index.ts:15:3 http +entry index.ts:6:14 http +entry index.ts:8:1 http diff --git a/graph/test/typescript/hono/expected/entry/fetch-object.tsv b/graph/test/typescript/hono/expected/entry/fetch-object.tsv new file mode 100644 index 000000000..32bc0511d --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/fetch-object.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: fetch-object export: the route handler plus scheduled and queue are http entries +# census: export_default_fetch_obj, app_fetch_ref +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.ts:6:14 index.ts:5:13 0 +regby index.ts:1:1 index.ts:6:14 GET / index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/entry/fixture-prop-request.entries b/graph/test/typescript/hono/expected/entry/fixture-prop-request.entries new file mode 100644 index 000000000..eac075f1d --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/fixture-prop-request.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-06: the request on fixture.app reaches GET /api/flow +# census: app_request_test (violation hono-2-06) +entry app.ts:5:24 http diff --git a/graph/test/typescript/hono/expected/entry/fixture-prop-request.tsv b/graph/test/typescript/hono/expected/entry/fixture-prop-request.tsv new file mode 100644 index 000000000..39a9d6352 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/fixture-prop-request.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-06: the request on fixture.app reaches GET /api/flow +# census: app_request_test (violation hono-2-06) +route GET /api/flow app.ts:5:24 app.ts:4:15 0 +request app.test.ts:12:14 GET /api/flow app.ts:5:24 +regby app.ts:3:1 app.ts:5:24 GET /api/flow app.ts:4:15 diff --git a/graph/test/typescript/hono/expected/entry/jsx-render.entries b/graph/test/typescript/hono/expected/entry/jsx-render.entries new file mode 100644 index 000000000..519ac2c52 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/jsx-render.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: two routes and their entries, jsxRenderer as library middleware for /page/*; the components and the renderer callback are in no Hono relation (runtime half skips .tsx) +# census: c_render, jsx_import +entry index.tsx:11:18 http +entry index.tsx:13:24 http diff --git a/graph/test/typescript/hono/expected/entry/jsx-render.tsv b/graph/test/typescript/hono/expected/entry/jsx-render.tsv new file mode 100644 index 000000000..51310ce95 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/jsx-render.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: two routes and their entries, jsxRenderer as library middleware for /page/*; the components and the renderer callback are in no Hono relation (runtime half skips .tsx) +# census: c_render, jsx_import +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /html index.tsx:11:18 index.tsx:10:13 0 +route GET /page/hello index.tsx:13:24 index.tsx:10:13 2 +mw lib:hono/jsx-renderer.jsxRenderer@index.tsx:12:20 index.tsx:13:24 GET /page/hello 0 index.tsx:10:13 +regby index.tsx:1:1 index.tsx:11:18 GET /html index.tsx:10:13 +regby index.tsx:1:1 index.tsx:13:24 GET /page/hello index.tsx:10:13 +absent components.tsx:4:27 +absent components.tsx:10:47 +absent index.tsx:12:32 diff --git a/graph/test/typescript/hono/expected/entry/node-serve.entries b/graph/test/typescript/hono/expected/entry/node-serve.entries new file mode 100644 index 000000000..badb32c78 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/node-serve.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an app only served through serve(): its route still in the table +# census: serve_fetch +entry index.ts:7:20 http diff --git a/graph/test/typescript/hono/expected/entry/node-serve.tsv b/graph/test/typescript/hono/expected/entry/node-serve.tsv new file mode 100644 index 000000000..3f6efcea7 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/node-serve.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an app only served through serve(): its route still in the table +# census: serve_fetch +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /served index.ts:7:20 index.ts:6:13 0 +regby index.ts:1:1 index.ts:7:20 GET /served index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/entry/notfound-onerror.entries b/graph/test/typescript/hono/expected/entry/notfound-onerror.entries new file mode 100644 index 000000000..07ee3f282 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/notfound-onerror.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: notFound and onError are entries, not routes +# census: not_found, on_error +entry index.ts:10:13 http +entry index.ts:6:18 http +entry index.ts:9:14 http diff --git a/graph/test/typescript/hono/expected/entry/notfound-onerror.tsv b/graph/test/typescript/hono/expected/entry/notfound-onerror.tsv new file mode 100644 index 000000000..b29054d97 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/notfound-onerror.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: notFound and onError are entries, not routes +# census: not_found, on_error +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /boom index.ts:6:18 index.ts:5:13 0 +regby index.ts:1:1 index.ts:6:18 GET /boom index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/entry/request-object-and-fetch.entries b/graph/test/typescript/hono/expected/entry/request-object-and-fetch.entries new file mode 100644 index 000000000..51c34d017 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/request-object-and-fetch.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: app.request(new Request(url)), app.fetch(new Request(url, {method}), env) and request with init each reach their route +# census: app_request_test, app_fetch_ref +entry app.ts:4:18 http +entry app.ts:5:23 http diff --git a/graph/test/typescript/hono/expected/entry/request-object-and-fetch.tsv b/graph/test/typescript/hono/expected/entry/request-object-and-fetch.tsv new file mode 100644 index 000000000..8c3e20da0 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/request-object-and-fetch.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: app.request(new Request(url)), app.fetch(new Request(url, {method}), env) and request with init each reach their route +# census: app_request_test, app_fetch_ref +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /ping app.ts:4:18 app.ts:3:20 0 +route PUT /items/:id app.ts:5:23 app.ts:3:20 1 +request app.test.ts:10:1 PUT /items/7 app.ts:5:23 +request app.test.ts:15:1 PUT /items/8 app.ts:5:23 +request app.test.ts:5:1 GET /ping app.ts:4:18 +regby app.ts:1:1 app.ts:4:18 GET /ping app.ts:3:20 +regby app.ts:1:1 app.ts:5:23 PUT /items/:id app.ts:3:20 diff --git a/graph/test/typescript/hono/expected/entry/test-built-app.entries b/graph/test/typescript/hono/expected/entry/test-built-app.entries new file mode 100644 index 000000000..4076fb41d --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/test-built-app.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: R1: the app built inside the it() callback is a served root; its /health route and the request from the callback reach it +# census: app_request_test (SPEC R1: oracle gap O1/O5) +entry app.test.ts:12:24 http diff --git a/graph/test/typescript/hono/expected/entry/test-built-app.tsv b/graph/test/typescript/hono/expected/entry/test-built-app.tsv new file mode 100644 index 000000000..bf0f15413 --- /dev/null +++ b/graph/test/typescript/hono/expected/entry/test-built-app.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: R1: the app built inside the it() callback is a served root; its /health route and the request from the callback reach it +# census: app_request_test (SPEC R1: oracle gap O1/O5) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /health app.test.ts:12:24 app.test.ts:11:17 0 +request app.test.ts:10:17 GET /health app.test.ts:12:24 +regby app.test.ts:10:17 app.test.ts:12:24 GET /health app.test.ts:11:17 diff --git a/graph/test/typescript/hono/expected/middleware/barrel-library-mw.entries b/graph/test/typescript/hono/expected/middleware/barrel-library-mw.entries new file mode 100644 index 000000000..74c21046d --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/barrel-library-mw.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O14: library middleware re-exported by a project barrel (named, renamed, export *) keyed at their calls, positions exact, no dynamic list +# census: use_global (oracle gap O14) +entry index.ts:11:20 http +entry index.ts:12:20 http +entry middleware/audit.ts:3:39 http diff --git a/graph/test/typescript/hono/expected/middleware/barrel-library-mw.tsv b/graph/test/typescript/hono/expected/middleware/barrel-library-mw.tsv new file mode 100644 index 000000000..15168837f --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/barrel-library-mw.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O14: library middleware re-exported by a project barrel (named, renamed, export *) keyed at their calls, positions exact, no dynamic list +# census: use_global (oracle gap O14) +route GET /api/me index.ts:11:20 index.ts:7:13 4 +route GET /health index.ts:12:20 index.ts:7:13 5 +mw lib:hono/logger.logger@index.ts:8:14 index.ts:11:20 GET /api/me 0 index.ts:7:13 +mw lib:hono/cors.cors@index.ts:9:14 index.ts:11:20 GET /api/me 1 index.ts:7:13 +mw lib:hono.secureHeaders@index.ts:10:19 index.ts:11:20 GET /api/me 2 index.ts:7:13 +mw middleware/audit.ts:3:39 index.ts:11:20 GET /api/me 3 index.ts:7:13 +mw lib:hono/logger.logger@index.ts:8:14 index.ts:12:20 GET /health 0 index.ts:7:13 +mw lib:hono/cors.cors@index.ts:9:14 index.ts:12:20 GET /health 1 index.ts:7:13 +regby index.ts:1:1 index.ts:11:20 GET /api/me index.ts:7:13 +regby index.ts:1:1 index.ts:12:20 GET /health index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/middleware/builtin.entries b/graph/test/typescript/hono/expected/middleware/builtin.entries new file mode 100644 index 000000000..8740b3205 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/builtin.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: library middleware keyed by registering call site; order logger, cors, secureHeaders, etag +# census: builtin_mw_import +entry index.ts:13:22 http +entry index.ts:14:14 http diff --git a/graph/test/typescript/hono/expected/middleware/builtin.tsv b/graph/test/typescript/hono/expected/middleware/builtin.tsv new file mode 100644 index 000000000..59ca8d3a5 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/builtin.tsv @@ -0,0 +1,13 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: library middleware keyed by registering call site; order logger, cors, secureHeaders, etag +# census: builtin_mw_import +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/data index.ts:13:22 index.ts:9:13 4 +route GET / index.ts:14:14 index.ts:9:13 5 +mw lib:hono/logger.logger@index.ts:10:9 index.ts:13:22 GET /api/data 0 index.ts:9:13 +mw lib:hono/cors.cors@index.ts:11:19 index.ts:13:22 GET /api/data 1 index.ts:9:13 +mw lib:hono/secure-headers.secureHeaders@index.ts:12:19 index.ts:13:22 GET /api/data 2 index.ts:9:13 +mw lib:hono/etag.etag@index.ts:12:36 index.ts:13:22 GET /api/data 3 index.ts:9:13 +mw lib:hono/logger.logger@index.ts:10:9 index.ts:14:14 GET / 0 index.ts:9:13 +regby index.ts:1:1 index.ts:13:22 GET /api/data index.ts:9:13 +regby index.ts:1:1 index.ts:14:14 GET / index.ts:9:13 diff --git a/graph/test/typescript/hono/expected/middleware/combine.entries b/graph/test/typescript/hono/expected/middleware/combine.entries new file mode 100644 index 000000000..ededc366d --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/combine.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: combinator calls are the middleware; except('/health') skips /health; combined functions are entries +# census: combine_every_some_except +entry index.ts:15:25 http +entry index.ts:16:24 http +entry index.ts:17:20 http +entry index.ts:7:36 http +entry index.ts:8:37 http +entry index.ts:9:36 http diff --git a/graph/test/typescript/hono/expected/middleware/combine.tsv b/graph/test/typescript/hono/expected/middleware/combine.tsv new file mode 100644 index 000000000..046691138 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/combine.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: combinator calls are the middleware; except('/health') skips /health; combined functions are entries +# census: combine_every_some_except +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /admin/panel index.ts:15:25 index.ts:11:13 3 +route GET /ops/status index.ts:16:24 index.ts:11:13 4 +route GET /health index.ts:17:20 index.ts:11:13 5 +mw lib:hono/combine.every@index.ts:12:21 index.ts:15:25 GET /admin/panel 0 index.ts:11:13 +mw lib:hono/combine.except@index.ts:14:14 index.ts:15:25 GET /admin/panel 1 index.ts:11:13 +mw lib:hono/combine.some@index.ts:13:19 index.ts:16:24 GET /ops/status 0 index.ts:11:13 +mw lib:hono/combine.except@index.ts:14:14 index.ts:16:24 GET /ops/status 1 index.ts:11:13 +regby index.ts:1:1 index.ts:15:25 GET /admin/panel index.ts:11:13 +regby index.ts:1:1 index.ts:16:24 GET /ops/status index.ts:11:13 +regby index.ts:1:1 index.ts:17:20 GET /health index.ts:11:13 diff --git a/graph/test/typescript/hono/expected/middleware/conditional-lib-mw.entries b/graph/test/typescript/hono/expected/middleware/conditional-lib-mw.entries new file mode 100644 index 000000000..531ae31d7 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/conditional-lib-mw.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m40/hono-5-04: if/else library middleware are alternatives at position 0, each keyed at its call, each conditional +# census: use_conditional_loop (stress-5 mutation m40 shape; violation hono-5-04) +entry index.ts:15:15 http diff --git a/graph/test/typescript/hono/expected/middleware/conditional-lib-mw.tsv b/graph/test/typescript/hono/expected/middleware/conditional-lib-mw.tsv new file mode 100644 index 000000000..132eeadf3 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/conditional-lib-mw.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m40/hono-5-04: if/else library middleware are alternatives at position 0, each keyed at its call, each conditional +# census: use_conditional_loop (stress-5 mutation m40 shape; violation hono-5-04) +route GET /x index.ts:15:15 index.ts:9:13 2 +mw lib:hono/logger.logger@index.ts:11:16 index.ts:15:15 GET /x 0 index.ts:9:13 +mw lib:hono/logger.logger@index.ts:13:16 index.ts:15:15 GET /x 0 index.ts:9:13 +regby index.ts:1:1 index.ts:15:15 GET /x index.ts:9:13 +unknown index.ts:11:3 conditional_registration index.ts:1:1 +unknown index.ts:13:3 conditional_registration index.ts:1:1 diff --git a/graph/test/typescript/hono/expected/middleware/const-library-mw.entries b/graph/test/typescript/hono/expected/middleware/const-library-mw.entries new file mode 100644 index 000000000..1b339dfe5 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/const-library-mw.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m31/hono-4-07: a const bound to jwt(...) is keyed at the call at module level, in a builder and in a branch +# census: use_scoped (stress-4 mutation m31 shapes; violation hono-4-07, SPEC R10/R11) +entry index.ts:12:19 http +entry index.ts:18:29 http +entry index.ts:28:34 http diff --git a/graph/test/typescript/hono/expected/middleware/const-library-mw.tsv b/graph/test/typescript/hono/expected/middleware/const-library-mw.tsv new file mode 100644 index 000000000..ebd6bf5d0 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/const-library-mw.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m31/hono-4-07: a const bound to jwt(...) is keyed at the call at module level, in a builder and in a branch +# census: use_scoped (stress-4 mutation m31 shapes; violation hono-4-07, SPEC R10/R11) +route GET /v1/me index.ts:12:19 index.ts:9:13 1 +route GET /admin/users index.ts:18:29 index.ts:9:13 3 +route GET /partner/orders index.ts:28:34 index.ts:9:13 5 +mw lib:hono/jwt.jwt@index.ts:10:16 index.ts:12:19 GET /v1/me 0 index.ts:9:13 +mw lib:hono/jwt.jwt@index.ts:16:20 index.ts:18:29 GET /admin/users 0 index.ts:9:13 +mw lib:hono/jwt.jwt@index.ts:25:24 index.ts:28:34 GET /partner/orders 0 index.ts:9:13 +submount / index.ts:32:5 +submount / index.ts:33:5 +regby index.ts:14:1 index.ts:18:29 GET /admin/users index.ts:9:13 +regby index.ts:1:1 index.ts:12:19 GET /v1/me index.ts:9:13 +regby index.ts:22:1 index.ts:28:34 GET /partner/orders index.ts:9:13 +unknown index.ts:26:5 conditional_registration index.ts:22:1 diff --git a/graph/test/typescript/hono/expected/middleware/detached-factory-method.entries b/graph/test/typescript/hono/expected/middleware/detached-factory-method.entries new file mode 100644 index 000000000..b470c1ccb --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/detached-factory-method.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O17: createMiddleware/createHandlers read off a factory into consts are the chain middleware and spread handlers +# census: create_middleware (oracle gap O17) +entry index.ts:13:3 http +entry index.ts:16:3 http +entry index.ts:7:44 http diff --git a/graph/test/typescript/hono/expected/middleware/detached-factory-method.tsv b/graph/test/typescript/hono/expected/middleware/detached-factory-method.tsv new file mode 100644 index 000000000..9b22b520a --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/detached-factory-method.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O17: createMiddleware/createHandlers read off a factory into consts are the chain middleware and spread handlers +# census: create_middleware (oracle gap O17) +route GET /admin/users index.ts:16:3 index.ts:19:13 2 +mw index.ts:7:44 index.ts:16:3 GET /admin/users 0 index.ts:19:13 +mw index.ts:13:3 index.ts:16:3 GET /admin/users 1 index.ts:19:13 +ctx index.ts:7:44 index.ts:16:3 role +regby index.ts:1:1 index.ts:16:3 GET /admin/users index.ts:19:13 diff --git a/graph/test/typescript/hono/expected/middleware/factory-fn.entries b/graph/test/typescript/hono/expected/middleware/factory-fn.entries new file mode 100644 index 000000000..794540cfb --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-fn.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: the inner functions the factories return are the middleware; app-level before per-route +# census: mw_factory_returning_fn, create_middleware +entry index.ts:8:45 http +entry mw.ts:10:65 http +entry mw.ts:4:10 http diff --git a/graph/test/typescript/hono/expected/middleware/factory-fn.tsv b/graph/test/typescript/hono/expected/middleware/factory-fn.tsv new file mode 100644 index 000000000..0ce1bb447 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-fn.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: the inner functions the factories return are the middleware; app-level before per-route +# census: mw_factory_returning_fn, create_middleware +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /limited index.ts:8:45 index.ts:6:13 2 +mw mw.ts:10:65 index.ts:8:45 GET /limited 0 index.ts:6:13 +mw mw.ts:4:10 index.ts:8:45 GET /limited 1 index.ts:6:13 +regby index.ts:1:1 index.ts:8:45 GET /limited index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/middleware/factory-handlers.entries b/graph/test/typescript/hono/expected/middleware/factory-handlers.entries new file mode 100644 index 000000000..fa60dfc20 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-handlers.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: initApp's use first, then check from createHandlers, then the handler; all three entries +# census: create_factory, factory_create_app, create_middleware +entry index.ts:14:40 http +entry index.ts:17:48 http +entry index.ts:8:13 http diff --git a/graph/test/typescript/hono/expected/middleware/factory-handlers.tsv b/graph/test/typescript/hono/expected/middleware/factory-handlers.tsv new file mode 100644 index 000000000..dafdf342f --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-handlers.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: initApp's use first, then check from createHandlers, then the handler; all three entries +# census: create_factory, factory_create_app, create_middleware +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /factory index.ts:17:48 index.ts:19:13 2 +mw index.ts:8:13 index.ts:17:48 GET /factory 0 index.ts:19:13 +mw index.ts:14:40 index.ts:17:48 GET /factory 1 index.ts:19:13 +regby index.ts:1:1 index.ts:17:48 GET /factory index.ts:19:13 diff --git a/graph/test/typescript/hono/expected/middleware/factory-object-member.entries b/graph/test/typescript/hono/expected/middleware/factory-object-member.entries new file mode 100644 index 000000000..3ac48d371 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-object-member.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-04: limiter.middleware is the arrow limiter.ts:6, m.auth checks.ts:5 on /admin/* only, m.audit checks.ts:11 on every route, in use order +# census: use_global, use_scoped, mw_factory_returning_fn (violation hono-7-04: middleware read off the object a +entry checks.ts:11:13 http +entry checks.ts:5:35 http +entry limiter.ts:6:41 http +entry index.ts:15:18 http +entry index.ts:16:25 http diff --git a/graph/test/typescript/hono/expected/middleware/factory-object-member.tsv b/graph/test/typescript/hono/expected/middleware/factory-object-member.tsv new file mode 100644 index 000000000..12cb6f4f7 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-object-member.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-04: limiter.middleware is the arrow limiter.ts:6, m.auth checks.ts:5 on /admin/* only, m.audit checks.ts:11 on every route, in use order +# census: use_global, use_scoped, mw_factory_returning_fn (violation hono-7-04: middleware read off the object a +route GET /ping index.ts:15:18 index.ts:11:13 3 +route GET /admin/users index.ts:16:25 index.ts:11:13 4 +mw limiter.ts:6:41 index.ts:15:18 GET /ping 0 index.ts:11:13 +mw checks.ts:11:13 index.ts:15:18 GET /ping 1 index.ts:11:13 +mw limiter.ts:6:41 index.ts:16:25 GET /admin/users 0 index.ts:11:13 +mw checks.ts:5:35 index.ts:16:25 GET /admin/users 1 index.ts:11:13 +mw checks.ts:11:13 index.ts:16:25 GET /admin/users 2 index.ts:11:13 +regby index.ts:1:1 index.ts:15:18 GET /ping index.ts:11:13 +regby index.ts:1:1 index.ts:16:25 GET /admin/users index.ts:11:13 diff --git a/graph/test/typescript/hono/expected/middleware/factory-two-returns.entries b/graph/test/typescript/hono/expected/middleware/factory-two-returns.entries new file mode 100644 index 000000000..4f2957405 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-two-returns.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-03: both returns of the factory are middleware at position 0 (the arrow and basicAuth at its call); verifyUser is no middleware +# census: use_scoped (violation hono-3-03, SPEC 3.1 "resolve the return; if several, all", R10) +entry index.ts:13:12 http +entry index.ts:22:25 http +entry index.ts:23:20 http diff --git a/graph/test/typescript/hono/expected/middleware/factory-two-returns.tsv b/graph/test/typescript/hono/expected/middleware/factory-two-returns.tsv new file mode 100644 index 000000000..48ea99cdb --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/factory-two-returns.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-03: both returns of the factory are middleware at position 0 (the arrow and basicAuth at its call); verifyUser is no middleware +# census: use_scoped (violation hono-3-03, SPEC 3.1 "resolve the return; if several, all", R10) +route GET /admin/stats index.ts:22:25 index.ts:20:13 2 +route GET /public index.ts:23:20 index.ts:20:13 3 +mw index.ts:13:12 index.ts:22:25 GET /admin/stats 0 index.ts:20:13 +mw lib:hono/basic-auth.basicAuth@index.ts:17:10 index.ts:22:25 GET /admin/stats 0 index.ts:20:13 +regby index.ts:1:1 index.ts:22:25 GET /admin/stats index.ts:20:13 +regby index.ts:1:1 index.ts:23:20 GET /public index.ts:20:13 diff --git a/graph/test/typescript/hono/expected/middleware/helper-app-mounted-thrice.entries b/graph/test/typescript/hono/expected/middleware/helper-app-mounted-thrice.entries new file mode 100644 index 000000000..bda162c13 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/helper-app-mounted-thrice.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m28/hono-4-02/R6: three per-call test apps, each chain use 0, param 1, json 2 +# census: app_request_test (stress-4 mutation m28 shape; violation hono-4-02, SPEC R6) +entry routes.test.ts:12:16 http +entry routes.ts:9:3 http diff --git a/graph/test/typescript/hono/expected/middleware/helper-app-mounted-thrice.tsv b/graph/test/typescript/hono/expected/middleware/helper-app-mounted-thrice.tsv new file mode 100644 index 000000000..22b4ccd2c --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/helper-app-mounted-thrice.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m28/hono-4-02/R6: three per-call test apps, each chain use 0, param 1, json 2 +# census: app_request_test (stress-4 mutation m28 shape; violation hono-4-02, SPEC R6) +# iteration 8: repeated rows removed (O29: the oracle prints each row once); the row set is unchanged +route POST /:id/rename routes.ts:9:3 routes.test.ts:11:15 3 +mw routes.test.ts:12:16 routes.ts:9:3 POST /:id/rename 0 routes.test.ts:11:15 +mw lib:@hono/zod-validator.zValidator@routes.ts:7:3 routes.ts:9:3 POST /:id/rename 1 routes.test.ts:11:15 +mw lib:@hono/zod-validator.zValidator@routes.ts:8:3 routes.ts:9:3 POST /:id/rename 2 routes.test.ts:11:15 +request routes.test.ts:24:19 POST /1/rename routes.ts:9:3 +request routes.test.ts:30:19 POST /2/rename routes.ts:9:3 +request routes.test.ts:36:21 POST /3/rename routes.ts:9:3 +submount / routes.test.ts:20:7 +schema routes.ts:9:3 json expr@routes.ts:8:22 +schema routes.ts:9:3 param expr@routes.ts:7:23 +regby routes.ts:1:1 routes.ts:9:3 POST /:id/rename routes.test.ts:11:15 diff --git a/graph/test/typescript/hono/expected/middleware/if-else-unequal-mw.entries b/graph/test/typescript/hono/expected/middleware/if-else-unequal-mw.entries new file mode 100644 index 000000000..eb53fd55c --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/if-else-unequal-mw.entries @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R15 clause 2: unequal if/else branches start at the same position, each conditional; a later middleware continues after the longer branch and its chain is dynamic_middleware_list; /api/ping (nothing after the branch) and /health are not dynamic +# census: use_conditional_loop, use_scoped (SPEC R15 clause 2) +entry index.ts:12:38 http +entry index.ts:13:40 http +entry index.ts:14:37 http +entry index.ts:15:35 http +entry index.ts:16:34 http +entry index.ts:28:20 http +entry index.ts:29:22 http +entry index.ts:30:27 http diff --git a/graph/test/typescript/hono/expected/middleware/if-else-unequal-mw.tsv b/graph/test/typescript/hono/expected/middleware/if-else-unequal-mw.tsv new file mode 100644 index 000000000..aae2611d6 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/if-else-unequal-mw.tsv @@ -0,0 +1,22 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R15 clause 2: unequal if/else branches start at the same position, each conditional; a later middleware continues after the longer branch and its chain is dynamic_middleware_list; /api/ping (nothing after the branch) and /health are not dynamic +# census: use_conditional_loop, use_scoped (SPEC R15 clause 2) +route GET /health index.ts:28:20 index.ts:18:13 5 +route GET /api/ping index.ts:29:22 index.ts:18:13 6 +route GET /api/items/:id index.ts:30:27 index.ts:18:13 7 +mw index.ts:12:38 index.ts:28:20 GET /health 0 index.ts:18:13 +mw index.ts:12:38 index.ts:29:22 GET /api/ping 0 index.ts:18:13 +mw index.ts:13:40 index.ts:29:22 GET /api/ping 1 index.ts:18:13 +mw index.ts:14:37 index.ts:29:22 GET /api/ping 2 index.ts:18:13 +mw index.ts:15:35 index.ts:29:22 GET /api/ping 1 index.ts:18:13 +mw index.ts:12:38 index.ts:30:27 GET /api/items/:id 0 index.ts:18:13 +mw index.ts:13:40 index.ts:30:27 GET /api/items/:id 1 index.ts:18:13 +mw index.ts:14:37 index.ts:30:27 GET /api/items/:id 2 index.ts:18:13 +mw index.ts:15:35 index.ts:30:27 GET /api/items/:id 1 index.ts:18:13 +mw index.ts:16:34 index.ts:30:27 GET /api/items/:id 3 index.ts:18:13 +regby index.ts:1:1 index.ts:28:20 GET /health index.ts:18:13 +regby index.ts:1:1 index.ts:29:22 GET /api/ping index.ts:18:13 +regby index.ts:1:1 index.ts:30:27 GET /api/items/:id index.ts:18:13 +unknown index.ts:21:3 conditional_registration index.ts:13:40 +unknown index.ts:22:3 conditional_registration index.ts:14:37 +unknown index.ts:24:3 conditional_registration index.ts:15:35 +unknown index.ts:30:1 dynamic_middleware_list index.ts:30:27 diff --git a/graph/test/typescript/hono/expected/middleware/lib-mw-options.entries b/graph/test/typescript/hono/expected/middleware/lib-mw-options.entries new file mode 100644 index 000000000..45d1bf9d6 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/lib-mw-options.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-07/R10: cors(...) and the basicAuth(...) call inside guard are the middleware; their option callbacks are not +# census: builtin_mw_import, mw_factory_returning_fn (violation hono-2-07, SPEC R10) +entry index.ts:16:15 http diff --git a/graph/test/typescript/hono/expected/middleware/lib-mw-options.tsv b/graph/test/typescript/hono/expected/middleware/lib-mw-options.tsv new file mode 100644 index 000000000..cffde1be0 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/lib-mw-options.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-07/R10: cors(...) and the basicAuth(...) call inside guard are the middleware; their option callbacks are not +# census: builtin_mw_import, mw_factory_returning_fn (violation hono-2-07, SPEC R10) +route GET /x index.ts:16:15 index.ts:13:13 2 +mw lib:hono/cors.cors@index.ts:14:14 index.ts:16:15 GET /x 0 index.ts:13:13 +mw lib:hono/basic-auth.basicAuth@index.ts:10:10 index.ts:16:15 GET /x 1 index.ts:13:13 +regby index.ts:1:1 index.ts:16:15 GET /x index.ts:13:13 diff --git a/graph/test/typescript/hono/expected/middleware/loop-use.entries b/graph/test/typescript/hono/expected/middleware/loop-use.entries new file mode 100644 index 000000000..dd35e39e1 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/loop-use.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-06 loop form: the two known middleware at 0 and 1, the chain declared dynamic_middleware_list +# census: use_global, use_multi (violation hono-1-06, LOOP form; SPEC 3.3 dynamic chains) +entry index.ts:17:16 http +entry index.ts:21:17 http +entry index.ts:9:16 http diff --git a/graph/test/typescript/hono/expected/middleware/loop-use.tsv b/graph/test/typescript/hono/expected/middleware/loop-use.tsv new file mode 100644 index 000000000..fd71b67af --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/loop-use.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-06 loop form: the two known middleware at 0 and 1, the chain declared dynamic_middleware_list +# census: use_global, use_multi (violation hono-1-06, LOOP form; SPEC 3.3 dynamic chains) +route GET /x index.ts:21:17 index.ts:8:15 3 +mw index.ts:9:16 index.ts:21:17 GET /x 0 index.ts:8:15 +mw index.ts:17:16 index.ts:21:17 GET /x 1 index.ts:8:15 +regby index.ts:7:1 index.ts:21:17 GET /x index.ts:8:15 +unknown index.ts:21:3 dynamic_middleware_list index.ts:21:17 diff --git a/graph/test/typescript/hono/expected/middleware/mw-from-namespace-field.entries b/graph/test/typescript/hono/expected/middleware/mw-from-namespace-field.entries new file mode 100644 index 000000000..977a7004d --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/mw-from-namespace-field.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m32/hono-4-01: factories via a namespace held in a field, a module destructure and namespace members are the inner project functions +# census: use_global (stress-4 mutation m32 shapes; violation hono-4-01) +entry guards/scope.ts:4:17 http +entry guards/session.ts:4:20 http +entry index.ts:15:23 http +entry index.ts:22:23 http +entry index.ts:25:19 http diff --git a/graph/test/typescript/hono/expected/middleware/mw-from-namespace-field.tsv b/graph/test/typescript/hono/expected/middleware/mw-from-namespace-field.tsv new file mode 100644 index 000000000..3c39c1fad --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/mw-from-namespace-field.tsv @@ -0,0 +1,21 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m32/hono-4-01: factories via a namespace held in a field, a module destructure and namespace members are the inner project functions +# census: use_global (stress-4 mutation m32 shapes; violation hono-4-01) +route GET /api/system/info index.ts:15:23 index.ts:27:13 2 +route GET /api/reports/daily index.ts:22:23 index.ts:27:13 5 +route GET /api/audit/log index.ts:25:19 index.ts:27:13 8 +mw guards/session.ts:4:20 index.ts:15:23 GET /api/system/info 0 index.ts:27:13 +mw guards/scope.ts:4:17 index.ts:15:23 GET /api/system/info 1 index.ts:27:13 +mw guards/session.ts:4:20 index.ts:22:23 GET /api/reports/daily 0 index.ts:27:13 +mw guards/scope.ts:4:17 index.ts:22:23 GET /api/reports/daily 1 index.ts:27:13 +mw guards/session.ts:4:20 index.ts:25:19 GET /api/audit/log 0 index.ts:27:13 +mw guards/scope.ts:4:17 index.ts:25:19 GET /api/audit/log 1 index.ts:27:13 +ctx guards/session.ts:4:20 guards/scope.ts:4:17 user +ctx guards/session.ts:4:20 index.ts:15:23 user +ctx guards/session.ts:4:20 index.ts:22:23 user +ctx guards/session.ts:4:20 index.ts:25:19 user +submount /api/system index.ts:28:5 +submount /api/reports index.ts:29:5 +submount /api/audit index.ts:30:5 +regby index.ts:12:3 index.ts:15:23 GET /api/system/info index.ts:27:13 +regby index.ts:1:1 index.ts:22:23 GET /api/reports/daily index.ts:27:13 +regby index.ts:1:1 index.ts:25:19 GET /api/audit/log index.ts:27:13 diff --git a/graph/test/typescript/hono/expected/middleware/partial-sub-app-chain.entries b/graph/test/typescript/hono/expected/middleware/partial-sub-app-chain.entries new file mode 100644 index 000000000..7df6ee21c --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/partial-sub-app-chain.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m34/hono-4-03/SPEC 3.3: the partial route's chain is holder use(*) 0, controller use 1, per-route 2; the holder's use(*) function is an http entry; the scoped holder use is partial_route_scope +# census: basepath (stress-4 mutation m34 shape; violation hono-4-03, SPEC 3.3 [iter2] partial routes) +entry index.ts:11:21 http +entry index.ts:14:15 http +entry index.ts:17:15 http +entry index.ts:27:36 http diff --git a/graph/test/typescript/hono/expected/middleware/partial-sub-app-chain.tsv b/graph/test/typescript/hono/expected/middleware/partial-sub-app-chain.tsv new file mode 100644 index 000000000..3873ce685 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/partial-sub-app-chain.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m34/hono-4-03/SPEC 3.3: the partial route's chain is holder use(*) 0, controller use 1, per-route 2; the holder's use(*) function is an http entry; the scoped holder use is partial_route_scope +# census: basepath (stress-4 mutation m34 shape; violation hono-4-03, SPEC 3.3 [iter2] partial routes) +partial index.ts:27:36 GET dynamic_mount_prefix +mwp index.ts:11:21 index.ts:27:36 GET 1 +mwp index.ts:14:15 index.ts:27:36 GET 0 +mwp index.ts:17:15 index.ts:27:36 GET 2 +unknown index.ts:53:1 dynamic_mount_prefix index.ts:27:36 +unknown index.ts:53:1 partial_route_scope index.ts:11:21 diff --git a/graph/test/typescript/hono/expected/middleware/runtime-list-except-ternary.entries b/graph/test/typescript/hono/expected/middleware/runtime-list-except-ternary.entries new file mode 100644 index 000000000..90d8c5914 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/runtime-list-except-ternary.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: routes straight on a run-time-based tier app are partial with their decidable chain (the tier's own /* middleware at 0) and dynamic_middleware_list from the run-time middleware list; except(..) with a run-time exclusion is dynamic_except +# census: use_conditional_loop, combine_except (stress-6 oracle note; SPEC 3.3, SPEC 3.1) +entry index.ts:28:17 http +entry index.ts:32:22 http +entry index.ts:40:15 http diff --git a/graph/test/typescript/hono/expected/middleware/runtime-list-except-ternary.tsv b/graph/test/typescript/hono/expected/middleware/runtime-list-except-ternary.tsv new file mode 100644 index 000000000..f8b0a93e3 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/runtime-list-except-ternary.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: routes straight on a run-time-based tier app are partial with their decidable chain (the tier's own /* middleware at 0) and dynamic_middleware_list from the run-time middleware list; except(..) with a run-time exclusion is dynamic_except +# census: use_conditional_loop, combine_except (stress-6 oracle note; SPEC 3.3, SPEC 3.1) +route GET / index.ts:40:15 index.ts:39:14 0 +submount / index.ts:41:32 +partial index.ts:32:22 GET dynamic_mount_prefix +mwp index.ts:28:17 index.ts:32:22 GET 0 +regby index.ts:1:1 index.ts:40:15 GET / index.ts:39:14 +unknown index.ts:30:35 dynamic_except index.ts:26:1 +unknown index.ts:32:3 dynamic_middleware_list index.ts:32:22 +unknown index.ts:32:3 dynamic_mount_prefix index.ts:32:22 diff --git a/graph/test/typescript/hono/expected/middleware/scoped-use.entries b/graph/test/typescript/hono/expected/middleware/scoped-use.entries new file mode 100644 index 000000000..23bb42be0 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/scoped-use.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: /admin/* reaches both admin routes; /orgs/:org/* reaches billing; /public gets nothing +# census: use_scoped, path_wildcard +entry index.ts:17:25 http +entry index.ts:18:29 http +entry index.ts:19:31 http +entry index.ts:20:20 http +entry index.ts:6:38 http +entry index.ts:9:35 http diff --git a/graph/test/typescript/hono/expected/middleware/scoped-use.tsv b/graph/test/typescript/hono/expected/middleware/scoped-use.tsv new file mode 100644 index 000000000..3f349df6d --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/scoped-use.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: /admin/* reaches both admin routes; /orgs/:org/* reaches billing; /public gets nothing +# census: use_scoped, path_wildcard +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /admin/users index.ts:17:25 index.ts:13:13 2 +route GET /admin/users/:id index.ts:18:29 index.ts:13:13 3 +route GET /orgs/:org/billing index.ts:19:31 index.ts:13:13 4 +route GET /public index.ts:20:20 index.ts:13:13 5 +mw index.ts:6:38 index.ts:17:25 GET /admin/users 0 index.ts:13:13 +mw index.ts:6:38 index.ts:18:29 GET /admin/users/:id 0 index.ts:13:13 +mw index.ts:9:35 index.ts:19:31 GET /orgs/:org/billing 0 index.ts:13:13 +regby index.ts:1:1 index.ts:17:25 GET /admin/users index.ts:13:13 +regby index.ts:1:1 index.ts:18:29 GET /admin/users/:id index.ts:13:13 +regby index.ts:1:1 index.ts:19:31 GET /orgs/:org/billing index.ts:13:13 +regby index.ts:1:1 index.ts:20:20 GET /public index.ts:13:13 diff --git a/graph/test/typescript/hono/expected/middleware/spread-after-mount.entries b/graph/test/typescript/hono/expected/middleware/spread-after-mount.entries new file mode 100644 index 000000000..6424cfc57 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/spread-after-mount.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: spread array a then b reaches /after only; the mounted /sub/inside was copied before the use +# census: use_multi, route_mount_literal +entry index.ts:12:20 http +entry index.ts:17:23 http +entry index.ts:7:30 http +entry index.ts:8:30 http diff --git a/graph/test/typescript/hono/expected/middleware/spread-after-mount.tsv b/graph/test/typescript/hono/expected/middleware/spread-after-mount.tsv new file mode 100644 index 000000000..ead5e8aa3 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/spread-after-mount.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: spread array a then b reaches /after only; the mounted /sub/inside was copied before the use +# census: use_multi, route_mount_literal +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /sub/inside index.ts:12:20 index.ts:14:17 0 +route GET /after index.ts:17:23 index.ts:14:17 3 +mw index.ts:7:30 index.ts:17:23 GET /after 0 index.ts:14:17 +mw index.ts:8:30 index.ts:17:23 GET /after 1 index.ts:14:17 +submount /sub index.ts:15:9 +regby index.ts:1:1 index.ts:12:20 GET /sub/inside index.ts:14:17 +regby index.ts:1:1 index.ts:17:23 GET /after index.ts:14:17 diff --git a/graph/test/typescript/hono/expected/middleware/spread-call-result.entries b/graph/test/typescript/hono/expected/middleware/spread-call-result.entries new file mode 100644 index 000000000..0d5a2fdff --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/spread-call-result.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-06: ...createLimits() seen through: limiter's inner fn at 0 and 1, after at 2 +# census: use_multi, mw_factory_returning_fn (violation hono-1-06) +entry index.ts:20:34 http +entry index.ts:27:15 http +entry index.ts:8:10 http diff --git a/graph/test/typescript/hono/expected/middleware/spread-call-result.tsv b/graph/test/typescript/hono/expected/middleware/spread-call-result.tsv new file mode 100644 index 000000000..a86c58522 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/spread-call-result.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-06: ...createLimits() seen through: limiter's inner fn at 0 and 1, after at 2 +# census: use_multi, mw_factory_returning_fn (violation hono-1-06) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /x index.ts:27:15 index.ts:24:13 3 +mw index.ts:8:10 index.ts:27:15 GET /x 0 index.ts:24:13 +mw index.ts:8:10 index.ts:27:15 GET /x 1 index.ts:24:13 +mw index.ts:20:34 index.ts:27:15 GET /x 2 index.ts:24:13 +regby index.ts:1:1 index.ts:27:15 GET /x index.ts:24:13 diff --git a/graph/test/typescript/hono/expected/middleware/sub-app-middleware.entries b/graph/test/typescript/hono/expected/middleware/sub-app-middleware.entries new file mode 100644 index 000000000..5031eaef1 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/sub-app-middleware.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: outer then inner on /users; inner never reaches /other +# census: use_global, route_mount_literal +entry index.ts:11:16 http +entry index.ts:16:19 http +entry index.ts:6:34 http +entry index.ts:7:34 http diff --git a/graph/test/typescript/hono/expected/middleware/sub-app-middleware.tsv b/graph/test/typescript/hono/expected/middleware/sub-app-middleware.tsv new file mode 100644 index 000000000..8ba3eae40 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/sub-app-middleware.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: outer then inner on /users; inner never reaches /other +# census: use_global, route_mount_literal +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /users index.ts:11:16 index.ts:13:13 2 +route GET /other index.ts:16:19 index.ts:13:13 3 +mw index.ts:6:34 index.ts:11:16 GET /users 0 index.ts:13:13 +mw index.ts:7:34 index.ts:11:16 GET /users 1 index.ts:13:13 +mw index.ts:6:34 index.ts:16:19 GET /other 0 index.ts:13:13 +submount /users index.ts:15:5 +regby index.ts:1:1 index.ts:11:16 GET /users index.ts:13:13 +regby index.ts:1:1 index.ts:16:19 GET /other index.ts:13:13 diff --git a/graph/test/typescript/hono/expected/middleware/use-order.entries b/graph/test/typescript/hono/expected/middleware/use-order.entries new file mode 100644 index 000000000..0d2f5e253 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/use-order.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: timing reaches all three; auth registered after /public reaches only the two later routes +# census: use_global, use_scoped, await_next +entry index.ts:15:20 http +entry index.ts:17:21 http +entry index.ts:18:22 http +entry index.ts:6:33 http +entry index.ts:9:31 http diff --git a/graph/test/typescript/hono/expected/middleware/use-order.tsv b/graph/test/typescript/hono/expected/middleware/use-order.tsv new file mode 100644 index 000000000..9a9b4ed51 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/use-order.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: timing reaches all three; auth registered after /public reaches only the two later routes +# census: use_global, use_scoped, await_next +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /public index.ts:15:20 index.ts:13:13 1 +route GET /private index.ts:17:21 index.ts:13:13 3 +route POST /private index.ts:18:22 index.ts:13:13 4 +mw index.ts:6:33 index.ts:15:20 GET /public 0 index.ts:13:13 +mw index.ts:6:33 index.ts:17:21 GET /private 0 index.ts:13:13 +mw index.ts:9:31 index.ts:17:21 GET /private 1 index.ts:13:13 +mw index.ts:6:33 index.ts:18:22 POST /private 0 index.ts:13:13 +mw index.ts:9:31 index.ts:18:22 POST /private 1 index.ts:13:13 +regby index.ts:1:1 index.ts:15:20 GET /public index.ts:13:13 +regby index.ts:1:1 index.ts:17:21 GET /private index.ts:13:13 +regby index.ts:1:1 index.ts:18:22 POST /private index.ts:13:13 diff --git a/graph/test/typescript/hono/expected/middleware/validator.entries b/graph/test/typescript/hono/expected/middleware/validator.entries new file mode 100644 index 000000000..bbaa3a435 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/validator.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: zValidator and validator are per-route middleware before the handler; NewPost is the json schema the handler's valid('json') reads +# census: zvalidator, validator_builtin, req_valid +entry index.ts:11:49 http +entry index.ts:15:3 http diff --git a/graph/test/typescript/hono/expected/middleware/validator.tsv b/graph/test/typescript/hono/expected/middleware/validator.tsv new file mode 100644 index 000000000..c6cc373fd --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/validator.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: zValidator and validator are per-route middleware before the handler; NewPost is the json schema the handler's valid('json') reads +# census: zvalidator, validator_builtin, req_valid +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /posts index.ts:11:49 index.ts:10:13 1 +route GET /search index.ts:15:3 index.ts:10:13 3 +mw lib:@hono/zod-validator.zValidator@index.ts:11:20 index.ts:11:49 POST /posts 0 index.ts:10:13 +mw lib:hono/validator.validator@index.ts:14:3 index.ts:15:3 GET /search 0 index.ts:10:13 +schema index.ts:11:49 json index.ts:8:7 +validread index.ts:11:63 index.ts:11:49 json index.ts:8:7 +regby index.ts:1:1 index.ts:11:49 POST /posts index.ts:10:13 +regby index.ts:1:1 index.ts:15:3 GET /search index.ts:10:13 diff --git a/graph/test/typescript/hono/expected/middleware/verb-next.entries b/graph/test/typescript/hono/expected/middleware/verb-next.entries new file mode 100644 index 000000000..3d9ca3783 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/verb-next.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an all('*') function that calls next is middleware for /x +# census: await_next, verb_literal_path +entry index.ts:6:14 http +entry index.ts:9:15 http diff --git a/graph/test/typescript/hono/expected/middleware/verb-next.tsv b/graph/test/typescript/hono/expected/middleware/verb-next.tsv new file mode 100644 index 000000000..baf1b4482 --- /dev/null +++ b/graph/test/typescript/hono/expected/middleware/verb-next.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an all('*') function that calls next is middleware for /x +# census: await_next, verb_literal_path +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route ANY /* index.ts:6:14 index.ts:5:13 0 +route GET /x index.ts:9:15 index.ts:5:13 1 +mw index.ts:6:14 index.ts:9:15 GET /x 0 index.ts:5:13 +regby index.ts:1:1 index.ts:6:14 ANY /* index.ts:5:13 +regby index.ts:1:1 index.ts:9:15 GET /x index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/negative/context-lookalike.entries b/graph/test/typescript/hono/expected/negative/context-lookalike.entries new file mode 100644 index 000000000..688817887 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/context-lookalike.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Map set/get on a parameter named c: no ctx_key_flow +# census: ctx_get (partition outside Hono contexts) (SPEC N5) +entry index.ts:16:16 http diff --git a/graph/test/typescript/hono/expected/negative/context-lookalike.tsv b/graph/test/typescript/hono/expected/negative/context-lookalike.tsv new file mode 100644 index 000000000..da39cf854 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/context-lookalike.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Map set/get on a parameter named c: no ctx_key_flow +# census: ctx_get (partition outside Hono contexts) (SPEC N5) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /me index.ts:16:16 index.ts:15:13 0 +regby index.ts:1:1 index.ts:16:16 GET /me index.ts:15:13 +absent index.ts:5:1 +absent index.ts:8:1 diff --git a/graph/test/typescript/hono/expected/negative/foreign-fetch.entries b/graph/test/typescript/hono/expected/negative/foreign-fetch.entries new file mode 100644 index 000000000..556591c63 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/foreign-fetch.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-12: fetch to another host's /health is no request to GET /health; ping is in no Hono relation +# census: neg_verb_literal_nonhono (violation hono-2-12) +entry index.ts:14:20 http diff --git a/graph/test/typescript/hono/expected/negative/foreign-fetch.tsv b/graph/test/typescript/hono/expected/negative/foreign-fetch.tsv new file mode 100644 index 000000000..ed627f0a4 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/foreign-fetch.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-12: fetch to another host's /health is no request to GET /health; ping is in no Hono relation +# census: neg_verb_literal_nonhono (violation hono-2-12) +route GET /health index.ts:14:20 index.ts:13:13 0 +regby index.ts:1:1 index.ts:14:20 GET /health index.ts:13:13 +absent index.ts:7:3 diff --git a/graph/test/typescript/hono/expected/negative/http-client.entries b/graph/test/typescript/hono/expected/negative/http-client.entries new file mode 100644 index 000000000..ec622580b --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/http-client.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an HTTP client object with get/post(url, cb): its callbacks and caller are not routes +# census: neg_verb_literal_nonhono (SPEC N2) +entry index.ts:5:18 http diff --git a/graph/test/typescript/hono/expected/negative/http-client.tsv b/graph/test/typescript/hono/expected/negative/http-client.tsv new file mode 100644 index 000000000..8fe18fc77 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/http-client.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an HTTP client object with get/post(url, cb): its callbacks and caller are not routes +# census: neg_verb_literal_nonhono (SPEC N2) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /only index.ts:5:18 index.ts:4:13 0 +regby index.ts:1:1 index.ts:5:18 GET /only index.ts:4:13 +absent client.ts:11:21 +absent client.ts:12:37 +absent client.ts:10:1 diff --git a/graph/test/typescript/hono/expected/negative/local-hono-class.entries b/graph/test/typescript/hono/expected/negative/local-hono-class.entries new file mode 100644 index 000000000..b9cd1a7d1 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/local-hono-class.entries @@ -0,0 +1,2 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a project class named Hono and a workflow .route(): zero Hono rows; the route table must still be exported +# census: neg_route_on_nonhono (SPEC N4) diff --git a/graph/test/typescript/hono/expected/negative/local-hono-class.tsv b/graph/test/typescript/hono/expected/negative/local-hono-class.tsv new file mode 100644 index 000000000..eef279747 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/local-hono-class.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a project class named Hono and a workflow .route(): zero Hono rows; the route table must still be exported +# census: neg_route_on_nonhono (SPEC N4) +absent index.ts:10:10 +absent index.ts:11:19 +absent index.ts:17:29 diff --git a/graph/test/typescript/hono/expected/negative/map-get.entries b/graph/test/typescript/hono/expected/negative/map-get.entries new file mode 100644 index 000000000..8776bacee --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/map-get.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Map/KV/Headers get+use beside a real app: one route; the KV callbacks are absent everywhere +# census: neg_map_get_in_hono_file (SPEC N1) +entry index.ts:20:18 http diff --git a/graph/test/typescript/hono/expected/negative/map-get.tsv b/graph/test/typescript/hono/expected/negative/map-get.tsv new file mode 100644 index 000000000..88099fb0f --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/map-get.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: Map/KV/Headers get+use beside a real app: one route; the KV callbacks are absent everywhere +# census: neg_map_get_in_hono_file (SPEC N1) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /real index.ts:20:18 index.ts:19:13 0 +regby index.ts:1:1 index.ts:20:18 GET /real index.ts:19:13 +absent index.ts:13:19 +absent index.ts:14:8 +absent index.ts:10:3 +absent index.ts:11:3 diff --git a/graph/test/typescript/hono/expected/negative/other-router.entries b/graph/test/typescript/hono/expected/negative/other-router.entries new file mode 100644 index 000000000..60451bfb6 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/other-router.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a non-Hono Router class with get/post/use/route: none of its handlers is a route or middleware +# census: neg_other_router_import (SPEC N3) +entry index.ts:14:18 http diff --git a/graph/test/typescript/hono/expected/negative/other-router.tsv b/graph/test/typescript/hono/expected/negative/other-router.tsv new file mode 100644 index 000000000..39fe10c4b --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/other-router.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a non-Hono Router class with get/post/use/route: none of its handlers is a route or middleware +# census: neg_other_router_import (SPEC N3) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /hono index.ts:14:18 index.ts:13:13 0 +regby index.ts:1:1 index.ts:14:18 GET /hono index.ts:13:13 +absent index.ts:7:12 +absent index.ts:8:29 +absent index.ts:9:30 diff --git a/graph/test/typescript/hono/expected/negative/request-lookalike.entries b/graph/test/typescript/hono/expected/negative/request-lookalike.entries new file mode 100644 index 000000000..2402a6c07 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/request-lookalike.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: agent.request and a local hc: no remote edge from either caller +# census: app_request_test (partition where the receiver is not an app) (SPEC N7, N8) +entry index.ts:6:18 http diff --git a/graph/test/typescript/hono/expected/negative/request-lookalike.tsv b/graph/test/typescript/hono/expected/negative/request-lookalike.tsv new file mode 100644 index 000000000..19407edd2 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/request-lookalike.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: agent.request and a local hc: no remote edge from either caller +# census: app_request_test (partition where the receiver is not an app) (SPEC N7, N8) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /real index.ts:6:18 index.ts:5:13 0 +regby index.ts:1:1 index.ts:6:18 GET /real index.ts:5:13 +absent index.ts:9:1 +absent index.ts:14:1 diff --git a/graph/test/typescript/hono/expected/negative/zod-openapi-meta.entries b/graph/test/typescript/hono/expected/negative/zod-openapi-meta.entries new file mode 100644 index 000000000..3c1cb7e71 --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/zod-openapi-meta.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: only app.openapi registers; .openapi('Name') metadata and typeof createRoute are not routes or RPC roots; Params/User are its schemas +# census: openapi_register, apptype_typeof (SPEC N6, N9) +entry index.ts:18:22 http diff --git a/graph/test/typescript/hono/expected/negative/zod-openapi-meta.tsv b/graph/test/typescript/hono/expected/negative/zod-openapi-meta.tsv new file mode 100644 index 000000000..79b6591ef --- /dev/null +++ b/graph/test/typescript/hono/expected/negative/zod-openapi-meta.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: only app.openapi registers; .openapi('Name') metadata and typeof createRoute are not routes or RPC roots; Params/User are its schemas +# census: openapi_register, apptype_typeof (SPEC N6, N9) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /users/:id index.ts:18:22 index.ts:17:13 0 +schema index.ts:18:22 param index.ts:7:7 +schema index.ts:18:22 response index.ts:6:7 +validread index.ts:18:42 index.ts:18:22 param index.ts:7:7 +regby index.ts:1:1 index.ts:18:22 GET /users/:id index.ts:17:13 diff --git a/graph/test/typescript/hono/expected/openapi/create-route-wrapper.entries b/graph/test/typescript/hono/expected/openapi/create-route-wrapper.entries new file mode 100644 index 000000000..3a004eb48 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/create-route-wrapper.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-03: routes built through the scopedRoute wrapper are routes (DELETE, PATCH) with the wrapper's authorize inner arrow at position 0; GET / from createRoute directly has none +# census: create_route, openapi_register, new_openapihono (violation hono-7-03: routes built through a project +entry items.ts:17:23 http +entry items.ts:18:25 http +entry items.ts:19:25 http +entry openapi.ts:5:10 http diff --git a/graph/test/typescript/hono/expected/openapi/create-route-wrapper.tsv b/graph/test/typescript/hono/expected/openapi/create-route-wrapper.tsv new file mode 100644 index 000000000..38cf4a808 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/create-route-wrapper.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-03: routes built through the scopedRoute wrapper are routes (DELETE, PATCH) with the wrapper's authorize inner arrow at position 0; GET / from createRoute directly has none +# census: create_route, openapi_register, new_openapihono (violation hono-7-03: routes built through a project +route GET /api/items items.ts:17:23 index.ts:8:13 0 +route DELETE /api/items/:id items.ts:18:25 index.ts:8:13 2 +route PATCH /api/items/:id/name items.ts:19:25 index.ts:8:13 4 +mw openapi.ts:5:10 items.ts:18:25 DELETE /api/items/:id 0 index.ts:8:13 +mw openapi.ts:5:10 items.ts:19:25 PATCH /api/items/:id/name 0 index.ts:8:13 +submount /api/items index.ts:9:5 +regby items.ts:1:1 items.ts:17:23 GET /api/items index.ts:8:13 +regby items.ts:1:1 items.ts:18:25 DELETE /api/items/:id index.ts:8:13 +regby items.ts:1:1 items.ts:19:25 PATCH /api/items/:id/name index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/openapi/create-route.entries b/graph/test/typescript/hono/expected/openapi/create-route.entries new file mode 100644 index 000000000..976cfd362 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/create-route.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route objects from routes.ts, {id} as :id, handler is arg 1 not the hook; param and response schemas, Task as a base of z.array(Task) +# census: create_route, openapi_register, new_openapihono +entry index.ts:12:3 http +entry index.ts:9:24 http diff --git a/graph/test/typescript/hono/expected/openapi/create-route.tsv b/graph/test/typescript/hono/expected/openapi/create-route.tsv new file mode 100644 index 000000000..6e2d83daf --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/create-route.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: route objects from routes.ts, {id} as :id, handler is arg 1 not the hook; param and response schemas, Task as a base of z.array(Task) +# census: create_route, openapi_register, new_openapihono +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /tasks index.ts:9:24 index.ts:7:13 0 +route GET /tasks/:id index.ts:12:3 index.ts:7:13 1 +schema index.ts:12:3 param expr@routes.ts:14:22 +schema index.ts:12:3 response routes.ts:3:14 +schema index.ts:9:24 response expr@routes.ts:8:86 +schema index.ts:9:24 response routes.ts:3:14 +validread index.ts:12:23 index.ts:12:3 param expr@routes.ts:14:22 +regby index.ts:1:1 index.ts:12:3 GET /tasks/:id index.ts:7:13 +regby index.ts:1:1 index.ts:9:24 GET /tasks index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/openapi/namespace-handlers.entries b/graph/test/typescript/hono/expected/openapi/namespace-handlers.entries new file mode 100644 index 000000000..1c7953dda --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/namespace-handlers.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-04: handlers.login (namespace member) handles POST /auth/login built from a template over a literal +# census: openapi_register, create_route (violation hono-1-04) +entry auth.handlers.ts:3:22 http diff --git a/graph/test/typescript/hono/expected/openapi/namespace-handlers.tsv b/graph/test/typescript/hono/expected/openapi/namespace-handlers.tsv new file mode 100644 index 000000000..544d7e39b --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/namespace-handlers.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-04: handlers.login (namespace member) handles POST /auth/login built from a template over a literal +# census: openapi_register, create_route (violation hono-1-04) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /auth/login auth.handlers.ts:3:22 index.ts:8:14 0 +regby index.ts:1:1 auth.handlers.ts:3:22 POST /auth/login index.ts:8:14 diff --git a/graph/test/typescript/hono/expected/openapi/response-helper.entries b/graph/test/typescript/hono/expected/openapi/response-helper.entries new file mode 100644 index 000000000..697e5cb89 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/response-helper.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-04: response and body schemas written through helpers name the helper argument (Account, ErrorBody), as inline ones do +# census: create_route (violation hono-3-04, SPEC 3.9) +entry index.ts:38:25 http +entry index.ts:39:27 http +entry index.ts:40:28 http diff --git a/graph/test/typescript/hono/expected/openapi/response-helper.tsv b/graph/test/typescript/hono/expected/openapi/response-helper.tsv new file mode 100644 index 000000000..b7e1fa239 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/response-helper.tsv @@ -0,0 +1,17 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-04: response and body schemas written through helpers name the helper argument (Account, ErrorBody), as inline ones do +# census: create_route (violation hono-3-04, SPEC 3.9) +route GET /accounts/:id index.ts:38:25 index.ts:37:13 0 +route GET /accounts index.ts:39:27 index.ts:37:13 1 +route POST /accounts index.ts:40:28 index.ts:37:13 2 +schema index.ts:38:25 param expr@index.ts:22:22 +schema index.ts:38:25 response index.ts:15:7 +schema index.ts:38:25 response index.ts:16:7 +schema index.ts:39:27 response index.ts:15:7 +schema index.ts:39:27 response index.ts:17:7 +schema index.ts:40:28 json index.ts:15:7 +schema index.ts:40:28 response index.ts:15:7 +validread index.ts:38:45 index.ts:38:25 param expr@index.ts:22:22 +validread index.ts:40:42 index.ts:40:28 json index.ts:15:7 +regby index.ts:1:1 index.ts:38:25 GET /accounts/:id index.ts:37:13 +regby index.ts:1:1 index.ts:39:27 GET /accounts index.ts:37:13 +regby index.ts:1:1 index.ts:40:28 POST /accounts index.ts:37:13 diff --git a/graph/test/typescript/hono/expected/openapi/route-middleware.entries b/graph/test/typescript/hono/expected/openapi/route-middleware.entries new file mode 100644 index 000000000..38e6f0d1e --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/route-middleware.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: audit (app-level) then guard (routeDef.middleware); the inline json body schema +# census: create_route, openapi_register, use_global +entry index.ts:19:21 http +entry index.ts:6:34 http +entry index.ts:7:34 http diff --git a/graph/test/typescript/hono/expected/openapi/route-middleware.tsv b/graph/test/typescript/hono/expected/openapi/route-middleware.tsv new file mode 100644 index 000000000..dbd16e1ed --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/route-middleware.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: audit (app-level) then guard (routeDef.middleware); the inline json body schema +# census: create_route, openapi_register, use_global +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /notes index.ts:19:21 index.ts:17:13 2 +mw index.ts:6:34 index.ts:19:21 POST /notes 0 index.ts:17:13 +mw index.ts:7:34 index.ts:19:21 POST /notes 1 index.ts:17:13 +schema index.ts:19:21 json expr@index.ts:13:63 +regby index.ts:1:1 index.ts:19:21 POST /notes index.ts:17:13 diff --git a/graph/test/typescript/hono/expected/openapi/spread-error-responses.entries b/graph/test/typescript/hono/expected/openapi/spread-error-responses.entries new file mode 100644 index 000000000..558abf03a --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/spread-error-responses.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m27/hono-4-08/O19: spread error responses name each errorBody(...) call once, never the helper declaration +# census: create_route (stress-4 mutation m27 shape; violation hono-4-08, oracle gap O19) +entry index.ts:20:24 http diff --git a/graph/test/typescript/hono/expected/openapi/spread-error-responses.tsv b/graph/test/typescript/hono/expected/openapi/spread-error-responses.tsv new file mode 100644 index 000000000..7d963e4d6 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/spread-error-responses.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m27/hono-4-08/O19: spread error responses name each errorBody(...) call once, never the helper declaration +# census: create_route (stress-4 mutation m27 shape; violation hono-4-08, oracle gap O19) +route GET /secrets/:id index.ts:20:24 index.ts:19:13 0 +schema index.ts:20:24 param expr@index.ts:12:22 +schema index.ts:20:24 response expr@errors.ts:12:46 +schema index.ts:20:24 response expr@errors.ts:8:46 +schema index.ts:20:24 response index.ts:7:7 +validread index.ts:20:44 index.ts:20:24 param expr@index.ts:12:22 +regby index.ts:1:1 index.ts:20:24 GET /secrets/:id index.ts:19:13 diff --git a/graph/test/typescript/hono/expected/openapi/status-key-helpers.entries b/graph/test/typescript/hono/expected/openapi/status-key-helpers.entries new file mode 100644 index 000000000..e14a12350 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/status-key-helpers.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m26/hono-3-04: [Status.X] keys and barrel-re-exported helpers name the helper argument for every response and body slot +# census: create_route (stress-4 mutation m26 shape; violation hono-3-04 reopened) +entry handlers.ts:3:26 http +entry handlers.ts:4:29 http diff --git a/graph/test/typescript/hono/expected/openapi/status-key-helpers.tsv b/graph/test/typescript/hono/expected/openapi/status-key-helpers.tsv new file mode 100644 index 000000000..215399187 --- /dev/null +++ b/graph/test/typescript/hono/expected/openapi/status-key-helpers.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m26/hono-3-04: [Status.X] keys and barrel-re-exported helpers name the helper argument for every response and body slot +# census: create_route (stress-4 mutation m26 shape; violation hono-3-04 reopened) +route GET /tickets/:id handlers.ts:3:26 index.ts:8:13 0 +route POST /tickets handlers.ts:4:29 index.ts:8:13 1 +schema handlers.ts:3:26 param expr@routes.ts:12:22 +schema handlers.ts:3:26 response routes.ts:5:7 +schema handlers.ts:3:26 response routes.ts:6:7 +schema handlers.ts:4:29 json routes.ts:7:7 +schema handlers.ts:4:29 response routes.ts:5:7 +regby index.ts:1:1 handlers.ts:3:26 GET /tickets/:id index.ts:8:13 +regby index.ts:1:1 handlers.ts:4:29 POST /tickets index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/routing/all-and-any.entries b/graph/test/typescript/hono/expected/routing/all-and-any.entries new file mode 100644 index 000000000..00d471519 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/all-and-any.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: all is ANY; a handler that never calls next is not middleware +# census: verb_literal_path, path_wildcard +entry index.ts:7:21 http +entry index.ts:8:26 http diff --git a/graph/test/typescript/hono/expected/routing/all-and-any.tsv b/graph/test/typescript/hono/expected/routing/all-and-any.tsv new file mode 100644 index 000000000..f13115e5c --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/all-and-any.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: all is ANY; a handler that never calls next is not middleware +# census: verb_literal_path, path_wildcard +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route ANY /proxy/* index.ts:7:21 index.ts:5:13 0 +route GET /proxy/health index.ts:8:26 index.ts:5:13 1 +regby index.ts:1:1 index.ts:7:21 ANY /proxy/* index.ts:5:13 +regby index.ts:1:1 index.ts:8:26 GET /proxy/health index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/routing/conditional-loop.entries b/graph/test/typescript/hono/expected/routing/conditional-loop.entries new file mode 100644 index 000000000..157776120 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/conditional-loop.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: both branches and the loop body are emitted, each declared conditional_registration / loop_registration; /always plain +# census: verb_literal_path (registrations behind a condition / in a loop, SPEC 3.1) +entry index.ts:11:20 http +entry index.ts:15:20 http +entry index.ts:18:20 http +entry index.ts:9:21 http diff --git a/graph/test/typescript/hono/expected/routing/conditional-loop.tsv b/graph/test/typescript/hono/expected/routing/conditional-loop.tsv new file mode 100644 index 000000000..1529f7685 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/conditional-loop.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: both branches and the loop body are emitted, each declared conditional_registration / loop_registration; /always plain +# census: verb_literal_path (registrations behind a condition / in a loop, SPEC 3.1) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +# iteration 3: the loop over a known list runs per element (O11 loop binding): /loop is registered twice, same route row +route GET /debug index.ts:9:21 index.ts:5:13 0 +route GET /prod index.ts:11:20 index.ts:5:13 1 +route GET /loop index.ts:15:20 index.ts:5:13 2 +route GET /loop index.ts:15:20 index.ts:5:13 3 +route GET /always index.ts:18:20 index.ts:5:13 4 +regby index.ts:1:1 index.ts:11:20 GET /prod index.ts:5:13 +regby index.ts:1:1 index.ts:15:20 GET /loop index.ts:5:13 +regby index.ts:1:1 index.ts:18:20 GET /always index.ts:5:13 +regby index.ts:1:1 index.ts:9:21 GET /debug index.ts:5:13 +unknown index.ts:11:3 conditional_registration index.ts:11:20 +unknown index.ts:15:3 loop_registration index.ts:15:20 +unknown index.ts:9:3 conditional_registration index.ts:9:21 diff --git a/graph/test/typescript/hono/expected/routing/const-paths.entries b/graph/test/typescript/hono/expected/routing/const-paths.entries new file mode 100644 index 000000000..54884662f --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/const-paths.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: imported const, const-object member, template and + over consts all decidable +# census: verb_const_path, verb_template_path +entry index.ts:10:27 http +entry index.ts:11:23 http +entry index.ts:12:33 http +entry index.ts:9:16 http diff --git a/graph/test/typescript/hono/expected/routing/const-paths.tsv b/graph/test/typescript/hono/expected/routing/const-paths.tsv new file mode 100644 index 000000000..9c4a66ca0 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/const-paths.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: imported const, const-object member, template and + over consts all decidable +# census: verb_const_path, verb_template_path +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /users index.ts:9:16 index.ts:7:13 0 +route GET /users/:id index.ts:10:27 index.ts:7:13 1 +route GET /health index.ts:11:23 index.ts:7:13 2 +route GET /api/version index.ts:12:33 index.ts:7:13 3 +regby index.ts:1:1 index.ts:10:27 GET /users/:id index.ts:7:13 +regby index.ts:1:1 index.ts:11:23 GET /health index.ts:7:13 +regby index.ts:1:1 index.ts:12:33 GET /api/version index.ts:7:13 +regby index.ts:1:1 index.ts:9:16 GET /users index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/routing/dynamic-path.entries b/graph/test/typescript/hono/expected/routing/dynamic-path.entries new file mode 100644 index 000000000..1507989e5 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/dynamic-path.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: run-time path: partial + dynamic_route_path, the literal sibling still a route (the partly-known /v${version}/status handler is still an http entry: orchestrator ruling, it is registered on a recognised app) +# census: verb_template_path (non-decidable partition) +entry index.ts:8:32 http +entry index.ts:9:19 http diff --git a/graph/test/typescript/hono/expected/routing/dynamic-path.tsv b/graph/test/typescript/hono/expected/routing/dynamic-path.tsv new file mode 100644 index 000000000..4e881b665 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/dynamic-path.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: run-time path: partial + dynamic_route_path, the literal sibling still a route +# census: verb_template_path (non-decidable partition) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /fixed index.ts:9:19 index.ts:5:13 0 +partial index.ts:8:32 GET dynamic_route_path +regby index.ts:1:1 index.ts:9:19 GET /fixed index.ts:5:13 +unknown index.ts:8:1 dynamic_route_path index.ts:8:32 diff --git a/graph/test/typescript/hono/expected/routing/every-verb.entries b/graph/test/typescript/hono/expected/routing/every-verb.entries new file mode 100644 index 000000000..680a6a75a --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/every-verb.entries @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ten routes, PURGE via on, path-less post continues /chain; all is ANY +# census: verb_literal_path, verb_chained, on_method, export_default_app +entry index.ts:10:26 http +entry index.ts:11:25 http +entry index.ts:12:23 http +entry index.ts:13:20 http +entry index.ts:14:27 http +entry index.ts:17:18 http +entry index.ts:18:9 http +entry index.ts:7:19 http +entry index.ts:8:20 http +entry index.ts:9:23 http diff --git a/graph/test/typescript/hono/expected/routing/every-verb.tsv b/graph/test/typescript/hono/expected/routing/every-verb.tsv new file mode 100644 index 000000000..1d96dd495 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/every-verb.tsv @@ -0,0 +1,23 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ten routes, PURGE via on, path-less post continues /chain; all is ANY +# census: verb_literal_path, verb_chained, on_method, export_default_app +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /items index.ts:7:19 index.ts:5:13 0 +route POST /items index.ts:8:20 index.ts:5:13 1 +route PUT /items/:id index.ts:9:23 index.ts:5:13 2 +route DELETE /items/:id index.ts:10:26 index.ts:5:13 3 +route PATCH /items/:id index.ts:11:25 index.ts:5:13 4 +route OPTIONS /items index.ts:12:23 index.ts:5:13 5 +route ANY /health index.ts:13:20 index.ts:5:13 6 +route PURGE /cache index.ts:14:27 index.ts:5:13 7 +route GET /chain index.ts:17:18 index.ts:5:13 8 +route POST /chain index.ts:18:9 index.ts:5:13 9 +regby index.ts:1:1 index.ts:10:26 DELETE /items/:id index.ts:5:13 +regby index.ts:1:1 index.ts:11:25 PATCH /items/:id index.ts:5:13 +regby index.ts:1:1 index.ts:12:23 OPTIONS /items index.ts:5:13 +regby index.ts:1:1 index.ts:13:20 ANY /health index.ts:5:13 +regby index.ts:1:1 index.ts:14:27 PURGE /cache index.ts:5:13 +regby index.ts:1:1 index.ts:17:18 GET /chain index.ts:5:13 +regby index.ts:1:1 index.ts:18:9 POST /chain index.ts:5:13 +regby index.ts:1:1 index.ts:7:19 GET /items index.ts:5:13 +regby index.ts:1:1 index.ts:8:20 POST /items index.ts:5:13 +regby index.ts:1:1 index.ts:9:23 PUT /items/:id index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/routing/library-handler.entries b/graph/test/typescript/hono/expected/routing/library-handler.entries new file mode 100644 index 000000000..70efe7228 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/library-handler.entries @@ -0,0 +1,2 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-03/R5: routes whose handler is a library call are keyed at the call (serveStatic x2); no project entry +# census: verb_literal_path (violation hono-1-03; SPEC R5) diff --git a/graph/test/typescript/hono/expected/routing/library-handler.tsv b/graph/test/typescript/hono/expected/routing/library-handler.tsv new file mode 100644 index 000000000..76ccb5ece --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/library-handler.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-03/R5: routes whose handler is a library call are keyed at the call (serveStatic x2); no project entry +# census: verb_literal_path (violation hono-1-03; SPEC R5) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /favicon.ico lib:@hono/node-server/serve-static.serveStatic@index.ts:8:25 index.ts:7:13 0 +route ANY /assets/* lib:hono/serve-static.serveStatic@index.ts:11:3 index.ts:7:13 1 +regby index.ts:1:1 lib:@hono/node-server/serve-static.serveStatic@index.ts:8:25 GET /favicon.ico index.ts:7:13 +regby index.ts:1:1 lib:hono/serve-static.serveStatic@index.ts:11:3 ANY /assets/* index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/routing/mts-source.entries b/graph/test/typescript/hono/expected/routing/mts-source.entries new file mode 100644 index 000000000..5ee7c489a --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/mts-source.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an .mts module is parsed like .ts +# census: new_hono, verb_literal_path (an .mts module) +entry server.mts:6:17 http +entry server.mts:7:18 http diff --git a/graph/test/typescript/hono/expected/routing/mts-source.tsv b/graph/test/typescript/hono/expected/routing/mts-source.tsv new file mode 100644 index 000000000..67abf2915 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/mts-source.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: an .mts module is parsed like .ts +# census: new_hono, verb_literal_path (an .mts module) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /mts server.mts:6:17 server.mts:4:20 0 +route POST /mts server.mts:7:18 server.mts:4:20 1 +regby server.mts:1:1 server.mts:6:17 GET /mts server.mts:4:20 +regby server.mts:1:1 server.mts:7:18 POST /mts server.mts:4:20 diff --git a/graph/test/typescript/hono/expected/routing/multi-handler.entries b/graph/test/typescript/hono/expected/routing/multi-handler.entries new file mode 100644 index 000000000..10dbca62e --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/multi-handler.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: non-last args are per-route middleware in argument order; handler is the last +# census: verb_multi_handler, await_next +entry index.ts:13:1 http +entry index.ts:20:27 http +entry index.ts:21:19 http +entry index.ts:6:40 http +entry index.ts:9:34 http diff --git a/graph/test/typescript/hono/expected/routing/multi-handler.tsv b/graph/test/typescript/hono/expected/routing/multi-handler.tsv new file mode 100644 index 000000000..8fe260334 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/multi-handler.tsv @@ -0,0 +1,13 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: non-last args are per-route middleware in argument order; handler is the last +# census: verb_multi_handler, await_next +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /orders index.ts:13:1 index.ts:17:13 2 +route GET /orders index.ts:20:27 index.ts:17:13 4 +route GET /plain index.ts:21:19 index.ts:17:13 5 +mw index.ts:6:40 index.ts:13:1 POST /orders 0 index.ts:17:13 +mw index.ts:9:34 index.ts:13:1 POST /orders 1 index.ts:17:13 +mw index.ts:9:34 index.ts:20:27 GET /orders 0 index.ts:17:13 +regby index.ts:1:1 index.ts:13:1 POST /orders index.ts:17:13 +regby index.ts:1:1 index.ts:20:27 GET /orders index.ts:17:13 +regby index.ts:1:1 index.ts:21:19 GET /plain index.ts:17:13 diff --git a/graph/test/typescript/hono/expected/routing/named-handlers.entries b/graph/test/typescript/hono/expected/routing/named-handlers.entries new file mode 100644 index 000000000..761bf3311 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/named-handlers.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: handler is the declaration in handlers.ts, not the reference +# census: verb_literal_path, export_default_app +entry handlers.ts:3:1 http +entry handlers.ts:7:27 http +entry handlers.ts:9:1 http diff --git a/graph/test/typescript/hono/expected/routing/named-handlers.tsv b/graph/test/typescript/hono/expected/routing/named-handlers.tsv new file mode 100644 index 000000000..138a0f599 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/named-handlers.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: handler is the declaration in handlers.ts, not the reference +# census: verb_literal_path, export_default_app +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /projects handlers.ts:3:1 index.ts:6:13 0 +route GET /projects/:id handlers.ts:7:27 index.ts:6:13 1 +route DELETE /projects/:id handlers.ts:9:1 index.ts:6:13 2 +regby index.ts:1:1 handlers.ts:3:1 GET /projects index.ts:6:13 +regby index.ts:1:1 handlers.ts:7:27 GET /projects/:id index.ts:6:13 +regby index.ts:1:1 handlers.ts:9:1 DELETE /projects/:id index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/routing/on-arrays.entries b/graph/test/typescript/hono/expected/routing/on-arrays.entries new file mode 100644 index 000000000..7b5bf6e2d --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/on-arrays.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: verbs x paths cross product, one handler four routes; lower-case verb upper-cased +# census: on_method_array, on_method +entry index.ts:7:52 http +entry index.ts:8:32 http +entry index.ts:9:27 http diff --git a/graph/test/typescript/hono/expected/routing/on-arrays.tsv b/graph/test/typescript/hono/expected/routing/on-arrays.tsv new file mode 100644 index 000000000..9938da957 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/on-arrays.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: verbs x paths cross product, one handler four routes; lower-case verb upper-cased +# census: on_method_array, on_method +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /form index.ts:7:52 index.ts:5:13 0 +route POST /form index.ts:7:52 index.ts:5:13 1 +route GET /form/legacy index.ts:7:52 index.ts:5:13 2 +route POST /form/legacy index.ts:7:52 index.ts:5:13 3 +route PURGE /cache/:key index.ts:8:32 index.ts:5:13 4 +route PUT /lower index.ts:9:27 index.ts:5:13 5 +regby index.ts:1:1 index.ts:7:52 GET /form index.ts:5:13 +regby index.ts:1:1 index.ts:7:52 GET /form/legacy index.ts:5:13 +regby index.ts:1:1 index.ts:7:52 POST /form index.ts:5:13 +regby index.ts:1:1 index.ts:7:52 POST /form/legacy index.ts:5:13 +regby index.ts:1:1 index.ts:8:32 PURGE /cache/:key index.ts:5:13 +regby index.ts:1:1 index.ts:9:27 PUT /lower index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/routing/partial-route-scope.entries b/graph/test/typescript/hono/expected/routing/partial-route-scope.entries new file mode 100644 index 000000000..8ef8b5b19 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/partial-route-scope.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: the /list route under an unknown prefix is partial; the /v1/* use against it is partial_route_scope +# census: use_scoped, route_mount_nonliteral (SPEC 3.3 [iter2] partial_route_scope) +entry index.ts:6:38 http +entry index.ts:9:20 http diff --git a/graph/test/typescript/hono/expected/routing/partial-route-scope.tsv b/graph/test/typescript/hono/expected/routing/partial-route-scope.tsv new file mode 100644 index 000000000..e1d288d34 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/partial-route-scope.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: the /list route under an unknown prefix is partial; the /v1/* use against it is partial_route_scope +# census: use_scoped, route_mount_nonliteral (SPEC 3.3 [iter2] partial_route_scope) +partial index.ts:9:20 GET dynamic_mount_prefix +unknown index.ts:14:1 dynamic_mount_prefix index.ts:9:20 +unknown index.ts:14:1 partial_route_scope index.ts:6:38 diff --git a/graph/test/typescript/hono/expected/routing/path-shapes.entries b/graph/test/typescript/hono/expected/routing/path-shapes.entries new file mode 100644 index 000000000..309ea615e --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/path-shapes.entries @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: every path kept as written +# census: path_param, path_optional_param, path_regex_param, path_wildcard +entry index.ts:10:21 http +entry index.ts:11:27 http +entry index.ts:12:28 http +entry index.ts:13:23 http +entry index.ts:14:23 http +entry index.ts:7:23 http +entry index.ts:8:26 http +entry index.ts:9:31 http diff --git a/graph/test/typescript/hono/expected/routing/path-shapes.tsv b/graph/test/typescript/hono/expected/routing/path-shapes.tsv new file mode 100644 index 000000000..02835770d --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/path-shapes.tsv @@ -0,0 +1,19 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: every path kept as written +# census: path_param, path_optional_param, path_regex_param, path_wildcard +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /users/:id index.ts:7:23 index.ts:5:13 0 +route GET /posts/:year? index.ts:8:26 index.ts:5:13 1 +route GET /items/:id{[0-9]+} index.ts:9:31 index.ts:5:13 2 +route GET /files/* index.ts:10:21 index.ts:5:13 3 +route GET /img/:slug.png index.ts:11:27 index.ts:5:13 4 +route GET /v1/keys.getKey index.ts:12:28 index.ts:5:13 5 +route GET /trailing/ index.ts:13:23 index.ts:5:13 6 +route GET /a/:x/b/:y index.ts:14:23 index.ts:5:13 7 +regby index.ts:1:1 index.ts:10:21 GET /files/* index.ts:5:13 +regby index.ts:1:1 index.ts:11:27 GET /img/:slug.png index.ts:5:13 +regby index.ts:1:1 index.ts:12:28 GET /v1/keys.getKey index.ts:5:13 +regby index.ts:1:1 index.ts:13:23 GET /trailing/ index.ts:5:13 +regby index.ts:1:1 index.ts:14:23 GET /a/:x/b/:y index.ts:5:13 +regby index.ts:1:1 index.ts:7:23 GET /users/:id index.ts:5:13 +regby index.ts:1:1 index.ts:8:26 GET /posts/:year? index.ts:5:13 +regby index.ts:1:1 index.ts:9:31 GET /items/:id{[0-9]+} index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/routing/pathless-chain.entries b/graph/test/typescript/hono/expected/routing/pathless-chain.entries new file mode 100644 index 000000000..cf1a21b1c --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/pathless-chain.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: first path-less get is /, later path-less verbs continue the chain's path +# census: verb_chained +entry index.ts:10:17 http +entry index.ts:11:9 http +entry index.ts:12:8 http +entry index.ts:14:25 http +entry index.ts:14:54 http +entry index.ts:7:9 http diff --git a/graph/test/typescript/hono/expected/routing/pathless-chain.tsv b/graph/test/typescript/hono/expected/routing/pathless-chain.tsv new file mode 100644 index 000000000..a35d04cff --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/pathless-chain.tsv @@ -0,0 +1,15 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: first path-less get is /, later path-less verbs continue the chain's path +# census: verb_chained +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET / index.ts:7:9 index.ts:5:13 0 +route GET /book index.ts:10:17 index.ts:5:13 1 +route POST /book index.ts:11:9 index.ts:5:13 2 +route PUT /book index.ts:12:8 index.ts:5:13 3 +route DELETE /book/:id index.ts:14:25 index.ts:5:13 4 +route PATCH /book/:id index.ts:14:54 index.ts:5:13 5 +regby index.ts:1:1 index.ts:10:17 GET /book index.ts:5:13 +regby index.ts:1:1 index.ts:11:9 POST /book index.ts:5:13 +regby index.ts:1:1 index.ts:12:8 PUT /book index.ts:5:13 +regby index.ts:1:1 index.ts:14:25 DELETE /book/:id index.ts:5:13 +regby index.ts:1:1 index.ts:14:54 PATCH /book/:id index.ts:5:13 +regby index.ts:1:1 index.ts:7:9 GET / index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/routing/scope-table.entries b/graph/test/typescript/hono/expected/routing/scope-table.entries new file mode 100644 index 000000000..514904b0c --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/scope-table.entries @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: QD09: /x/* reaches /x, /x/, /x/a not /xy; /x* reaches all four; /a/*/c reaches only /a/b/c +# census: use_scoped, path_wildcard (SPEC 3.3 [iter2] QD09 table, settled against the pinned hono routers) +entry index.ts:15:15 http +entry index.ts:16:16 http +entry index.ts:17:17 http +entry index.ts:18:16 http +entry index.ts:19:19 http +entry index.ts:20:17 http +entry index.ts:21:21 http +entry index.ts:6:38 http +entry index.ts:7:37 http +entry index.ts:8:36 http diff --git a/graph/test/typescript/hono/expected/routing/scope-table.tsv b/graph/test/typescript/hono/expected/routing/scope-table.tsv new file mode 100644 index 000000000..d917ce6ae --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/scope-table.tsv @@ -0,0 +1,24 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: QD09: /x/* reaches /x, /x/, /x/a not /xy; /x* reaches all four; /a/*/c reaches only /a/b/c +# census: use_scoped, path_wildcard (SPEC 3.3 [iter2] QD09 table, settled against the pinned hono routers) +route GET /x index.ts:15:15 index.ts:10:13 3 +route GET /x/ index.ts:16:16 index.ts:10:13 4 +route GET /x/a index.ts:17:17 index.ts:10:13 5 +route GET /xy index.ts:18:16 index.ts:10:13 6 +route GET /a/b/c index.ts:19:19 index.ts:10:13 7 +route GET /a/c index.ts:20:17 index.ts:10:13 8 +route GET /a/b/d/c index.ts:21:21 index.ts:10:13 9 +mw index.ts:6:38 index.ts:15:15 GET /x 0 index.ts:10:13 +mw index.ts:7:37 index.ts:15:15 GET /x 1 index.ts:10:13 +mw index.ts:6:38 index.ts:16:16 GET /x/ 0 index.ts:10:13 +mw index.ts:7:37 index.ts:16:16 GET /x/ 1 index.ts:10:13 +mw index.ts:6:38 index.ts:17:17 GET /x/a 0 index.ts:10:13 +mw index.ts:7:37 index.ts:17:17 GET /x/a 1 index.ts:10:13 +mw index.ts:7:37 index.ts:18:16 GET /xy 0 index.ts:10:13 +mw index.ts:8:36 index.ts:19:19 GET /a/b/c 0 index.ts:10:13 +regby index.ts:1:1 index.ts:15:15 GET /x index.ts:10:13 +regby index.ts:1:1 index.ts:16:16 GET /x/ index.ts:10:13 +regby index.ts:1:1 index.ts:17:17 GET /x/a index.ts:10:13 +regby index.ts:1:1 index.ts:18:16 GET /xy index.ts:10:13 +regby index.ts:1:1 index.ts:19:19 GET /a/b/c index.ts:10:13 +regby index.ts:1:1 index.ts:20:17 GET /a/c index.ts:10:13 +regby index.ts:1:1 index.ts:21:21 GET /a/b/d/c index.ts:10:13 diff --git a/graph/test/typescript/hono/expected/routing/strict-false.entries b/graph/test/typescript/hono/expected/routing/strict-false.entries new file mode 100644 index 000000000..0a163f5ce --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/strict-false.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: registered paths unchanged by strict:false +# census: strict_false, new_hono_options +entry index.ts:7:20 http +entry index.ts:8:21 http diff --git a/graph/test/typescript/hono/expected/routing/strict-false.tsv b/graph/test/typescript/hono/expected/routing/strict-false.tsv new file mode 100644 index 000000000..b55df1fcc --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/strict-false.tsv @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: registered paths unchanged by strict:false +# census: strict_false, new_hono_options +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /about/ index.ts:7:20 index.ts:5:13 0 +route GET /contact index.ts:8:21 index.ts:5:13 1 +regby index.ts:1:1 index.ts:7:20 GET /about/ index.ts:5:13 +regby index.ts:1:1 index.ts:8:21 GET /contact index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/routing/websocket-project-module.entries b/graph/test/typescript/hono/expected/routing/websocket-project-module.entries new file mode 100644 index 000000000..e5299dc53 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/websocket-project-module.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O10 residual: upgradeWebSocket from a project module (relative and path alias) is a library-call handler; chat middleware precedes it +# census: verb_multi_handler (oracle gap O10 residual; SPEC R5) +entry chat.ts:6:3 http diff --git a/graph/test/typescript/hono/expected/routing/websocket-project-module.tsv b/graph/test/typescript/hono/expected/routing/websocket-project-module.tsv new file mode 100644 index 000000000..7f175a40b --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/websocket-project-module.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O10 residual: upgradeWebSocket from a project module (relative and path alias) is a library-call handler; chat middleware precedes it +# census: verb_multi_handler (oracle gap O10 residual; SPEC R5) +route GET /live lib:hono/bun.createBunWebSocket().upgradeWebSocket@index.ts:9:18 index.ts:8:13 0 +route GET /chat/ws lib:hono/bun.createBunWebSocket().upgradeWebSocket@chat.ts:10:3 index.ts:8:13 2 +mw chat.ts:6:3 lib:hono/bun.createBunWebSocket().upgradeWebSocket@chat.ts:10:3 GET /chat/ws 0 index.ts:8:13 +submount /chat index.ts:10:5 +regby chat.ts:1:1 lib:hono/bun.createBunWebSocket().upgradeWebSocket@chat.ts:10:3 GET /chat/ws index.ts:8:13 +regby index.ts:1:1 lib:hono/bun.createBunWebSocket().upgradeWebSocket@index.ts:9:18 GET /live index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/routing/websocket-sse.entries b/graph/test/typescript/hono/expected/routing/websocket-sse.entries new file mode 100644 index 000000000..7d6a5f030 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/websocket-sse.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O10/R5: upgradeWebSocket(...) is a library-call handler keyed at the call; the streamSSE route has a project handler +# census: verb_literal_path (oracle gap O10; SPEC R5 library-call handlers) +entry index.ts:17:17 http diff --git a/graph/test/typescript/hono/expected/routing/websocket-sse.tsv b/graph/test/typescript/hono/expected/routing/websocket-sse.tsv new file mode 100644 index 000000000..47cace524 --- /dev/null +++ b/graph/test/typescript/hono/expected/routing/websocket-sse.tsv @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O10/R5: upgradeWebSocket(...) is a library-call handler keyed at the call; the streamSSE route has a project handler +# census: verb_literal_path (oracle gap O10; SPEC R5 library-call handlers) +route GET /ws lib:hono/cloudflare-workers.upgradeWebSocket@index.ts:11:3 index.ts:8:13 0 +route GET /sse index.ts:17:17 index.ts:8:13 1 +regby index.ts:1:1 index.ts:17:17 GET /sse index.ts:8:13 +regby index.ts:1:1 lib:hono/cloudflare-workers.upgradeWebSocket@index.ts:11:3 GET /ws index.ts:8:13 diff --git a/graph/test/typescript/hono/expected/rpc/base-unknown-implausible.entries b/graph/test/typescript/hono/expected/rpc/base-unknown-implausible.entries new file mode 100644 index 000000000..65d62ee02 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/base-unknown-implausible.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O21: an unknown-base request joins /api/users as base_unknown; never a test-only app from non-test code, never the catch-all, never import.meta.url, never a path with no literal segment +# census: request_fetch, app_request_test (SPEC R14; oracle rule O21) +entry server.test.ts:7:28 http +entry server.ts:10:27 http +entry server.ts:11:14 http +entry server.ts:9:23 http diff --git a/graph/test/typescript/hono/expected/rpc/base-unknown-implausible.tsv b/graph/test/typescript/hono/expected/rpc/base-unknown-implausible.tsv new file mode 100644 index 000000000..2ade2ecfa --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/base-unknown-implausible.tsv @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O21: an unknown-base request joins /api/users as base_unknown; never a test-only app from non-test code, never the catch-all, never import.meta.url, never a path with no literal segment +# census: request_fetch, app_request_test (SPEC R14; oracle rule O21) +route GET /__test/probe server.test.ts:7:28 server.test.ts:6:15 0 +route GET /api/users server.ts:9:23 server.ts:8:13 0 +route GET /api/users/:id server.ts:10:27 server.ts:8:13 1 +route GET /* server.ts:11:14 server.ts:8:13 2 +request client.ts:1:1 GET /api/users server.ts:9:23 base_unknown +request server.test.ts:5:42 GET /__test/probe server.test.ts:7:28 +regby server.test.ts:5:42 server.test.ts:7:28 GET /__test/probe server.test.ts:6:15 +regby server.ts:1:1 server.ts:10:27 GET /api/users/:id server.ts:8:13 +regby server.ts:1:1 server.ts:11:14 GET /* server.ts:8:13 +regby server.ts:1:1 server.ts:9:23 GET /api/users server.ts:8:13 diff --git a/graph/test/typescript/hono/expected/rpc/fetch-unknown-base.entries b/graph/test/typescript/hono/expected/rpc/fetch-unknown-base.entries new file mode 100644 index 000000000..d89e692fb --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/fetch-unknown-base.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R14/O18: parameter, URL-base and env-or-localhost bases join on full paths as base_unknown; a literal external host never joins +# census: request_fetch (SPEC R14; oracle gap O18) +entry api.ts:7:29 http +entry api.ts:8:26 http +entry api.ts:9:20 http diff --git a/graph/test/typescript/hono/expected/rpc/fetch-unknown-base.tsv b/graph/test/typescript/hono/expected/rpc/fetch-unknown-base.tsv new file mode 100644 index 000000000..6f9fdb1fb --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/fetch-unknown-base.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R14/O18: parameter, URL-base and env-or-localhost bases join on full paths as base_unknown; a literal external host never joins +# census: request_fetch (SPEC R14; oracle gap O18) +route POST /api/oauth/register api.ts:7:29 api.ts:6:13 0 +route GET /api/projects/:id api.ts:8:26 api.ts:6:13 1 +route GET /api/health api.ts:9:20 api.ts:6:13 2 +request cli.ts:11:1 GET /api/health api.ts:9:20 base_unknown +request cli.ts:3:1 POST /api/oauth/register api.ts:7:29 base_unknown +request cli.ts:7:1 GET /api/projects/${} api.ts:8:26 base_unknown +regby api.ts:1:1 api.ts:7:29 POST /api/oauth/register api.ts:6:13 +regby api.ts:1:1 api.ts:8:26 GET /api/projects/:id api.ts:6:13 +regby api.ts:1:1 api.ts:9:20 GET /api/health api.ts:6:13 diff --git a/graph/test/typescript/hono/expected/rpc/fetch-verb-parameter.entries b/graph/test/typescript/hono/expected/rpc/fetch-verb-parameter.entries new file mode 100644 index 000000000..02237e60d --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/fetch-verb-parameter.entries @@ -0,0 +1,7 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R17/O25/hono-6-03: an undecidable method (an init the helper is handed, a parameter verb, a method set in a branch, a replayed init) joins every route on the path with method_unknown; base_unknown wins when the base is unknown too; a literal DELETE and an omitted init (GET) join one verb +# census: request_fetch, app_request_test (SPEC R17; stress-6 oracle note O25; violation hono-6-03) +entry server.ts:10:31 http +entry server.ts:11:24 http +entry server.ts:12:25 http +entry server.ts:8:28 http +entry server.ts:9:28 http diff --git a/graph/test/typescript/hono/expected/rpc/fetch-verb-parameter.tsv b/graph/test/typescript/hono/expected/rpc/fetch-verb-parameter.tsv new file mode 100644 index 000000000..650aa15ce --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/fetch-verb-parameter.tsv @@ -0,0 +1,25 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: R17/O25/hono-6-03: an undecidable method (an init the helper is handed, a parameter verb, a method set in a branch, a replayed init) joins every route on the path with method_unknown; base_unknown wins when the base is unknown too; a literal DELETE and an omitted init (GET) join one verb +# census: request_fetch, app_request_test (SPEC R17; stress-6 oracle note O25; violation hono-6-03) +route GET /api/skills/:id server.ts:8:28 server.ts:7:13 0 +route PUT /api/skills/:id server.ts:9:28 server.ts:7:13 1 +route DELETE /api/skills/:id server.ts:10:31 server.ts:7:13 2 +route GET /_discovery server.ts:11:24 server.ts:7:13 3 +route POST /_discovery server.ts:12:25 server.ts:7:13 4 +request discovery.ts:2:1 * /_discovery server.ts:11:24 method_unknown +request discovery.ts:2:1 * /_discovery server.ts:12:25 method_unknown +request server.test.ts:5:1 * /api/skills/2 server.ts:10:31 method_unknown +request server.test.ts:5:1 * /api/skills/2 server.ts:8:28 method_unknown +request server.test.ts:5:1 * /api/skills/2 server.ts:9:28 method_unknown +request server.test.ts:5:1 GET /api/skills/1 server.ts:8:28 +request skills-client.ts:12:1 DELETE /api/skills/${} server.ts:10:31 +request skills-client.ts:2:1 * /api/skills${} server.ts:10:31 base_unknown +request skills-client.ts:2:1 * /api/skills${} server.ts:8:28 base_unknown +request skills-client.ts:2:1 * /api/skills${} server.ts:9:28 base_unknown +request skills-client.ts:7:1 * /api/skills/${} server.ts:10:31 method_unknown +request skills-client.ts:7:1 * /api/skills/${} server.ts:8:28 method_unknown +request skills-client.ts:7:1 * /api/skills/${} server.ts:9:28 method_unknown +regby server.ts:1:1 server.ts:10:31 DELETE /api/skills/:id server.ts:7:13 +regby server.ts:1:1 server.ts:11:24 GET /_discovery server.ts:7:13 +regby server.ts:1:1 server.ts:12:25 POST /_discovery server.ts:7:13 +regby server.ts:1:1 server.ts:8:28 GET /api/skills/:id server.ts:7:13 +regby server.ts:1:1 server.ts:9:28 PUT /api/skills/:id server.ts:7:13 diff --git a/graph/test/typescript/hono/expected/rpc/hc-basic.entries b/graph/test/typescript/hono/expected/rpc/hc-basic.entries new file mode 100644 index 000000000..3ab3f9232 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/hc-basic.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: four client functions reach their routes; index is /; $url makes no edge +# census: hc_client, hc_dollar_call, hc_element_param, apptype_typeof +entry server.ts:4:13 http +entry server.ts:5:16 http +entry server.ts:6:14 http +entry server.ts:9:52 http diff --git a/graph/test/typescript/hono/expected/rpc/hc-basic.tsv b/graph/test/typescript/hono/expected/rpc/hc-basic.tsv new file mode 100644 index 000000000..acbf03e8c --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/hc-basic.tsv @@ -0,0 +1,16 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: four client functions reach their routes; index is /; $url makes no edge +# census: hc_client, hc_dollar_call, hc_element_param, apptype_typeof +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /users server.ts:4:13 server.ts:8:13 0 +route GET /users/:id server.ts:5:16 server.ts:8:13 1 +route POST /users server.ts:6:14 server.ts:8:13 2 +route GET / server.ts:9:52 server.ts:8:13 3 +rpc client.ts:11:1 GET /users/:id server.ts:5:16 +rpc client.ts:14:1 POST /users server.ts:6:14 +rpc client.ts:17:1 GET / server.ts:9:52 +rpc client.ts:8:1 GET /users server.ts:4:13 +submount /users server.ts:9:20 +regby server.ts:1:1 server.ts:4:13 GET /users server.ts:8:13 +regby server.ts:1:1 server.ts:5:16 GET /users/:id server.ts:8:13 +regby server.ts:1:1 server.ts:6:14 POST /users server.ts:8:13 +regby server.ts:1:1 server.ts:9:52 GET / server.ts:8:13 diff --git a/graph/test/typescript/hono/expected/rpc/helper-request-method.entries b/graph/test/typescript/hono/expected/rpc/helper-request-method.entries new file mode 100644 index 000000000..77c645e89 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/helper-request-method.entries @@ -0,0 +1,6 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-02: the post helper's literal method POST joins POST /auth/login and POST /auth/login/form; the get helper (no init) joins GET /auth/login and GET /auth/session +# census: app_request_test (violation hono-7-02: a literal method in the init object of app.request inside a +entry auth.ts:4:26 http +entry auth.ts:5:27 http +entry auth.ts:6:32 http +entry auth.ts:7:28 http diff --git a/graph/test/typescript/hono/expected/rpc/helper-request-method.tsv b/graph/test/typescript/hono/expected/rpc/helper-request-method.tsv new file mode 100644 index 000000000..32e026c43 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/helper-request-method.tsv @@ -0,0 +1,24 @@ +# hand-reviewed 2026-10-29 against the fixture and the oracle: hono-7-02: the post helper's literal method POST joins POST /auth/login and POST /auth/login/form; the get helper (no init) joins GET /auth/login and GET /auth/session +# census: app_request_test (violation hono-7-02: a literal method in the init object of app.request inside a +route GET /auth/login auth.ts:4:26 __tests__/auth.test.ts:11:15 0 +route POST /auth/login auth.ts:5:27 __tests__/auth.test.ts:11:15 1 +route POST /auth/login/form auth.ts:6:32 __tests__/auth.test.ts:11:15 2 +route GET /auth/session auth.ts:7:28 __tests__/auth.test.ts:11:15 3 +route GET /auth/login auth.ts:4:26 __tests__/auth.test.ts:19:15 0 +route POST /auth/login auth.ts:5:27 __tests__/auth.test.ts:19:15 1 +route POST /auth/login/form auth.ts:6:32 __tests__/auth.test.ts:19:15 2 +route GET /auth/session auth.ts:7:28 __tests__/auth.test.ts:19:15 3 +request __tests__/auth.test.ts:10:1 POST /auth/login auth.ts:5:27 +request __tests__/auth.test.ts:10:1 POST /auth/login/form auth.ts:6:32 +request __tests__/auth.test.ts:18:1 GET /auth/login auth.ts:4:26 +request __tests__/auth.test.ts:18:1 GET /auth/session auth.ts:7:28 +submount /auth __tests__/auth.test.ts:12:7 +submount /auth __tests__/auth.test.ts:20:7 +regby auth.ts:1:1 auth.ts:4:26 GET /auth/login __tests__/auth.test.ts:11:15 +regby auth.ts:1:1 auth.ts:4:26 GET /auth/login __tests__/auth.test.ts:19:15 +regby auth.ts:1:1 auth.ts:5:27 POST /auth/login __tests__/auth.test.ts:11:15 +regby auth.ts:1:1 auth.ts:5:27 POST /auth/login __tests__/auth.test.ts:19:15 +regby auth.ts:1:1 auth.ts:6:32 POST /auth/login/form __tests__/auth.test.ts:11:15 +regby auth.ts:1:1 auth.ts:6:32 POST /auth/login/form __tests__/auth.test.ts:19:15 +regby auth.ts:1:1 auth.ts:7:28 GET /auth/session __tests__/auth.test.ts:11:15 +regby auth.ts:1:1 auth.ts:7:28 GET /auth/session __tests__/auth.test.ts:19:15 diff --git a/graph/test/typescript/hono/expected/rpc/local-fetch-full-path.entries b/graph/test/typescript/hono/expected/rpc/local-fetch-full-path.entries new file mode 100644 index 000000000..5d62c5fd3 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/local-fetch-full-path.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-02: localhost fetches match composed full paths: /ready only to the root handler, /api/version to the sub-app, /version to nothing +# census: route_mount_root (violation hono-3-02) +entry api.ts:5:18 http +entry api.ts:6:20 http +entry main.ts:8:20 http diff --git a/graph/test/typescript/hono/expected/rpc/local-fetch-full-path.tsv b/graph/test/typescript/hono/expected/rpc/local-fetch-full-path.tsv new file mode 100644 index 000000000..2f2a8b712 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/local-fetch-full-path.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: hono-3-02: localhost fetches match composed full paths: /ready only to the root handler, /api/version to the sub-app, /version to nothing +# census: route_mount_root (violation hono-3-02) +route GET /ready main.ts:8:20 main.ts:7:14 0 +route GET /api/ready api.ts:5:18 main.ts:7:14 1 +route GET /api/version api.ts:6:20 main.ts:7:14 2 +request probe.ts:3:1 GET /ready main.ts:8:20 +request probe.ts:9:1 GET /api/version api.ts:6:20 +submount / main.ts:9:6 +regby api.ts:1:1 api.ts:5:18 GET /api/ready main.ts:7:14 +regby api.ts:1:1 api.ts:6:20 GET /api/version main.ts:7:14 +regby main.ts:1:1 main.ts:8:20 GET /ready main.ts:7:14 diff --git a/graph/test/typescript/hono/expected/rpc/mixed-segment-hole.entries b/graph/test/typescript/hono/expected/rpc/mixed-segment-hole.entries new file mode 100644 index 000000000..6e008b6f8 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/mixed-segment-hole.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m39/hono-5-07: /api/skills${path} reaches /api/skills/:id (base_unknown and local), never /api/agents +# census: request_fetch (stress-5 mutation m39 shape; violation hono-5-07) +entry index.ts:7:24 http +entry index.ts:8:28 http diff --git a/graph/test/typescript/hono/expected/rpc/mixed-segment-hole.tsv b/graph/test/typescript/hono/expected/rpc/mixed-segment-hole.tsv new file mode 100644 index 000000000..9d44b442d --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/mixed-segment-hole.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m39/hono-5-07: /api/skills${path} reaches /api/skills/:id (base_unknown and local), never /api/agents +# census: request_fetch (stress-5 mutation m39 shape; violation hono-5-07) +route GET /api/agents index.ts:7:24 index.ts:6:13 0 +route GET /api/skills/:id index.ts:8:28 index.ts:6:13 1 +request index.ts:11:1 GET /api/skills${} index.ts:8:28 base_unknown +request index.ts:14:1 GET /api/skills${} index.ts:8:28 +regby index.ts:1:1 index.ts:7:24 GET /api/agents index.ts:6:13 +regby index.ts:1:1 index.ts:8:28 GET /api/skills/:id index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/rpc/monorepo-client.entries b/graph/test/typescript/hono/expected/rpc/monorepo-client.entries new file mode 100644 index 000000000..4e501e252 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/monorepo-client.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: client through a wrapper function and inline hc reaches the basePath'd routes +# census: hc_client, hc_dollar_call, hc_element_param +entry server/app.ts:4:19 http +entry server/app.ts:5:36 http diff --git a/graph/test/typescript/hono/expected/rpc/monorepo-client.tsv b/graph/test/typescript/hono/expected/rpc/monorepo-client.tsv new file mode 100644 index 000000000..3beeceb6c --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/monorepo-client.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: client through a wrapper function and inline hc reaches the basePath'd routes +# census: hc_client, hc_dollar_call, hc_element_param +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/orders server/app.ts:4:19 server/app.ts:3:20 0 +route POST /api/orders/:orderId/cancel server/app.ts:5:36 server/app.ts:3:20 1 +rpc web/orders.ts:10:1 POST /api/orders/:orderId/cancel server/app.ts:5:36 +rpc web/orders.ts:14:1 GET /api/orders server/app.ts:4:19 +regby server/app.ts:1:1 server/app.ts:4:19 GET /api/orders server/app.ts:3:20 +regby server/app.ts:1:1 server/app.ts:5:36 POST /api/orders/:orderId/cancel server/app.ts:3:20 diff --git a/graph/test/typescript/hono/expected/rpc/query-string.entries b/graph/test/typescript/hono/expected/rpc/query-string.entries new file mode 100644 index 000000000..f49c524d2 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/query-string.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-05/R9: query string and fragment stripped: both requests reach /sessions/:id/file +# census: app_request_test (violation hono-2-05, SPEC R9) +entry app.ts:4:31 http +entry app.ts:5:36 http diff --git a/graph/test/typescript/hono/expected/rpc/query-string.tsv b/graph/test/typescript/hono/expected/rpc/query-string.tsv new file mode 100644 index 000000000..132f51a4e --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/query-string.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-05/R9: query string and fragment stripped: both requests reach /sessions/:id/file +# census: app_request_test (violation hono-2-05, SPEC R9) +route GET /sessions/:id/file app.ts:4:31 app.ts:3:20 0 +route GET /sessions/:id/objective app.ts:5:36 app.ts:3:20 1 +request app.test.ts:5:1 GET /sessions/S1/file app.ts:4:31 +request app.test.ts:8:1 GET /sessions/S1/file app.ts:4:31 +regby app.ts:1:1 app.ts:4:31 GET /sessions/:id/file app.ts:3:20 +regby app.ts:1:1 app.ts:5:36 GET /sessions/:id/objective app.ts:3:20 diff --git a/graph/test/typescript/hono/expected/rpc/reassigned-let.entries b/graph/test/typescript/hono/expected/rpc/reassigned-let.entries new file mode 100644 index 000000000..ef4fe7e70 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/reassigned-let.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-03/R7: postId is reassigned, so it is a hole: read -> GET /posts/:id, update -> PUT /posts/:id; the const fixed folds to /posts/p1 +# census: app_request_test (violation hono-2-03, SPEC R7; oracle gap O13) +entry api.ts:4:19 http +entry api.ts:5:23 http +entry api.ts:6:23 http diff --git a/graph/test/typescript/hono/expected/rpc/reassigned-let.tsv b/graph/test/typescript/hono/expected/rpc/reassigned-let.tsv new file mode 100644 index 000000000..769efe420 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/reassigned-let.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-03/R7: postId is reassigned, so it is a hole: read -> GET /posts/:id, update -> PUT /posts/:id; the const fixed folds to /posts/p1 +# census: app_request_test (violation hono-2-03, SPEC R7; oracle gap O13) +route GET /posts api.ts:4:19 api.ts:3:13 0 +route GET /posts/:id api.ts:5:23 api.ts:3:13 1 +route PUT /posts/:id api.ts:6:23 api.ts:3:13 2 +request api.test.ts:13:14 GET /posts/${} api.ts:5:23 +request api.test.ts:16:16 PUT /posts/${} api.ts:6:23 +request api.test.ts:19:15 GET /posts/p1 api.ts:5:23 +regby api.ts:1:1 api.ts:4:19 GET /posts api.ts:3:13 +regby api.ts:1:1 api.ts:5:23 GET /posts/:id api.ts:3:13 +regby api.ts:1:1 api.ts:6:23 PUT /posts/:id api.ts:3:13 diff --git a/graph/test/typescript/hono/expected/rpc/request-on-mounted-subapp.entries b/graph/test/typescript/hono/expected/rpc/request-on-mounted-subapp.entries new file mode 100644 index 000000000..521492dbc --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/request-on-mounted-subapp.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-05: worker.request('/posts') and hc.todos.$get match relative to the sub-app they root at +# census: app_request_test, hc_client (violation hono-1-05) +entry api.ts:4:19 http +entry api.ts:5:47 http diff --git a/graph/test/typescript/hono/expected/rpc/request-on-mounted-subapp.tsv b/graph/test/typescript/hono/expected/rpc/request-on-mounted-subapp.tsv new file mode 100644 index 000000000..932109e9e --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/request-on-mounted-subapp.tsv @@ -0,0 +1,11 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-1-05: worker.request('/posts') and hc.todos.$get match relative to the sub-app they root at +# census: app_request_test, hc_client (violation hono-1-05) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /api/posts api.ts:4:19 index.ts:7:13 0 +route GET /api/todos api.ts:5:47 index.ts:7:13 1 +rpc api.test.ts:8:1 GET /todos api.ts:5:47 +request api.test.ts:4:1 GET /posts api.ts:4:19 +submount / api.ts:6:5 +submount /api index.ts:8:5 +regby api.ts:1:1 api.ts:4:19 GET /api/posts index.ts:7:13 +regby api.ts:1:1 api.ts:5:47 GET /api/todos index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/rpc/single-label-host.entries b/graph/test/typescript/hono/expected/rpc/single-label-host.entries new file mode 100644 index 000000000..28d9fe87f --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/single-label-host.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m37/hono-5-08/R14a: billing:9000 and an unknown base join as base_unknown; the dotted external host never joins +# census: request_fetch (stress-5 mutation m37 shape; violation hono-5-08, SPEC R14a) +entry index.ts:7:26 http +entry index.ts:8:24 http diff --git a/graph/test/typescript/hono/expected/rpc/single-label-host.tsv b/graph/test/typescript/hono/expected/rpc/single-label-host.tsv new file mode 100644 index 000000000..a7d20c51c --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/single-label-host.tsv @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: m37/hono-5-08/R14a: billing:9000 and an unknown base join as base_unknown; the dotted external host never joins +# census: request_fetch (stress-5 mutation m37 shape; violation hono-5-08, SPEC R14a) +route GET /api/invoices index.ts:7:26 index.ts:6:13 0 +route GET /api/health index.ts:8:24 index.ts:6:13 1 +request index.ts:11:1 GET /api/invoices index.ts:7:26 base_unknown +request index.ts:17:1 GET /api/health index.ts:8:24 base_unknown +regby index.ts:1:1 index.ts:7:26 GET /api/invoices index.ts:6:13 +regby index.ts:1:1 index.ts:8:24 GET /api/health index.ts:6:13 diff --git a/graph/test/typescript/hono/expected/rpc/template-holes.entries b/graph/test/typescript/hono/expected/rpc/template-holes.entries new file mode 100644 index 000000000..8aca832a5 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/template-holes.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a hole is one segment: request and client both reach /posts/latest and /posts/:id by shape; /comments/${} is dynamic_rpc_path; the absolute URL uses its pathname +# census: app_request_test, hc_element_param (SPEC 3.5 [iter2] template holes and absolute URLs) +entry app.ts:4:18 http +entry app.ts:5:25 http +entry app.ts:6:22 http diff --git a/graph/test/typescript/hono/expected/rpc/template-holes.tsv b/graph/test/typescript/hono/expected/rpc/template-holes.tsv new file mode 100644 index 000000000..807e50666 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/template-holes.tsv @@ -0,0 +1,14 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: a hole is one segment: request and client both reach /posts/latest and /posts/:id by shape; /comments/${} is dynamic_rpc_path; the absolute URL uses its pathname +# census: app_request_test, hc_element_param (SPEC 3.5 [iter2] template holes and absolute URLs) +route GET /posts app.ts:4:18 app.ts:3:20 0 +route GET /posts/latest app.ts:5:25 app.ts:3:20 1 +route GET /posts/:id app.ts:6:22 app.ts:3:20 2 +rpc app.test.ts:10:1 GET /posts/${} app.ts:5:25 +rpc app.test.ts:10:1 GET /posts/${} app.ts:6:22 +request app.test.ts:16:1 GET /posts app.ts:4:18 +request app.test.ts:7:1 GET /posts/${} app.ts:5:25 +request app.test.ts:7:1 GET /posts/${} app.ts:6:22 +regby app.ts:1:1 app.ts:4:18 GET /posts app.ts:3:20 +regby app.ts:1:1 app.ts:5:25 GET /posts/latest app.ts:3:20 +regby app.ts:1:1 app.ts:6:22 GET /posts/:id app.ts:3:20 +unknown app.test.ts:14:10 dynamic_rpc_path app.test.ts:13:1 diff --git a/graph/test/typescript/hono/expected/rpc/workspace-dist-exports.entries b/graph/test/typescript/hono/expected/rpc/workspace-dist-exports.entries new file mode 100644 index 000000000..a71274137 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/workspace-dist-exports.entries @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O3b: exports to an unbuilt dist file resolve to the package source; the dashboard is mounted at /admin, no root of its own +# census: route_mount_literal (oracle gap O3b) +entry apps/api/src/index.ts:8:20 http +entry packages/routes/src/adapters/hono.ts:5:15 http +entry packages/routes/src/adapters/hono.ts:6:27 http diff --git a/graph/test/typescript/hono/expected/rpc/workspace-dist-exports.tsv b/graph/test/typescript/hono/expected/rpc/workspace-dist-exports.tsv new file mode 100644 index 000000000..6a89e82c0 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/workspace-dist-exports.tsv @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-28 against the fixture and the oracle: O3b: exports to an unbuilt dist file resolve to the package source; the dashboard is mounted at /admin, no root of its own +# census: route_mount_literal (oracle gap O3b) +route GET /health apps/api/src/index.ts:8:20 apps/api/src/index.ts:7:13 0 +route GET /admin packages/routes/src/adapters/hono.ts:5:15 apps/api/src/index.ts:7:13 1 +route GET /admin/api/activity packages/routes/src/adapters/hono.ts:6:27 apps/api/src/index.ts:7:13 2 +submount /admin apps/api/src/index.ts:9:5 +regby apps/api/src/index.ts:1:1 apps/api/src/index.ts:8:20 GET /health apps/api/src/index.ts:7:13 +regby packages/routes/src/adapters/hono.ts:3:1 packages/routes/src/adapters/hono.ts:5:15 GET /admin apps/api/src/index.ts:7:13 +regby packages/routes/src/adapters/hono.ts:3:1 packages/routes/src/adapters/hono.ts:6:27 GET /admin/api/activity apps/api/src/index.ts:7:13 diff --git a/graph/test/typescript/hono/expected/rpc/workspace-exports.entries b/graph/test/typescript/hono/expected/rpc/workspace-exports.entries new file mode 100644 index 000000000..c6553d39b --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/workspace-exports.entries @@ -0,0 +1,3 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-08/O3: @scope/client/v2 resolves through package.json exports; the client reaches GET /sessions +# census: hc_client (violation hono-2-08; oracle gap O3: a workspace package subpath through package.json exports) +entry packages/server/src/app.ts:4:37 http diff --git a/graph/test/typescript/hono/expected/rpc/workspace-exports.tsv b/graph/test/typescript/hono/expected/rpc/workspace-exports.tsv new file mode 100644 index 000000000..306a9d287 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/workspace-exports.tsv @@ -0,0 +1,5 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: hono-2-08/O3: @scope/client/v2 resolves through package.json exports; the client reaches GET /sessions +# census: hc_client (violation hono-2-08; oracle gap O3: a workspace package subpath through package.json exports) +route GET /sessions packages/server/src/app.ts:4:37 packages/server/src/app.ts:3:13 0 +rpc packages/client/lib/client.ts:4:1 GET /sessions packages/server/src/app.ts:4:37 +regby packages/server/src/app.ts:1:1 packages/server/src/app.ts:4:37 GET /sessions packages/server/src/app.ts:3:13 diff --git a/graph/test/typescript/hono/expected/rpc/workspace-package.entries b/graph/test/typescript/hono/expected/rpc/workspace-package.entries new file mode 100644 index 000000000..0a77739d5 --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/workspace-package.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O3: @acme/server and @acme/admin resolve as workspace packages: the /admin mount and both typed client calls cross them +# census: hc_client, route_mount_literal (oracle gap O3: workspace package imports in a monorepo) +entry packages/admin/routes.ts:3:47 http +entry packages/server/src/index.ts:5:33 http diff --git a/graph/test/typescript/hono/expected/rpc/workspace-package.tsv b/graph/test/typescript/hono/expected/rpc/workspace-package.tsv new file mode 100644 index 000000000..2a41f326d --- /dev/null +++ b/graph/test/typescript/hono/expected/rpc/workspace-package.tsv @@ -0,0 +1,10 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: O3: @acme/server and @acme/admin resolve as workspace packages: the /admin mount and both typed client calls cross them +# census: hc_client, route_mount_literal (oracle gap O3: workspace package imports in a monorepo) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /ping packages/server/src/index.ts:5:33 packages/server/src/index.ts:4:13 0 +route GET /admin/users packages/admin/routes.ts:3:47 packages/server/src/index.ts:4:13 1 +rpc packages/web/client.ts:11:1 GET /admin/users packages/admin/routes.ts:3:47 +rpc packages/web/client.ts:8:1 GET /ping packages/server/src/index.ts:5:33 +submount /admin packages/server/src/index.ts:5:56 +regby packages/admin/routes.ts:1:1 packages/admin/routes.ts:3:47 GET /admin/users packages/server/src/index.ts:4:13 +regby packages/server/src/index.ts:1:1 packages/server/src/index.ts:5:33 GET /ping packages/server/src/index.ts:4:13 diff --git a/graph/test/typescript/hono/expected/scale/deep-mount.entries b/graph/test/typescript/hono/expected/scale/deep-mount.entries new file mode 100644 index 000000000..beb63fb00 --- /dev/null +++ b/graph/test/typescript/hono/expected/scale/deep-mount.entries @@ -0,0 +1,12 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ten levels, /here at each depth /d1/.../d9; runtime agrees +# census: route_mount_literal (scale: 10-deep mounting; generated by tools/gen-scale.mjs) +entry index.ts:11:17 http +entry index.ts:13:17 http +entry index.ts:15:17 http +entry index.ts:17:17 http +entry index.ts:19:17 http +entry index.ts:21:17 http +entry index.ts:23:17 http +entry index.ts:5:17 http +entry index.ts:7:17 http +entry index.ts:9:17 http diff --git a/graph/test/typescript/hono/expected/scale/deep-mount.tsv b/graph/test/typescript/hono/expected/scale/deep-mount.tsv new file mode 100644 index 000000000..f35b8b687 --- /dev/null +++ b/graph/test/typescript/hono/expected/scale/deep-mount.tsv @@ -0,0 +1,32 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: ten levels, /here at each depth /d1/.../d9; runtime agrees +# census: route_mount_literal (scale: 10-deep mounting; generated by tools/gen-scale.mjs) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /here index.ts:5:17 index.ts:4:12 0 +route GET /d1/here index.ts:7:17 index.ts:4:12 1 +route GET /d1/d2/here index.ts:9:17 index.ts:4:12 2 +route GET /d1/d2/d3/here index.ts:11:17 index.ts:4:12 3 +route GET /d1/d2/d3/d4/here index.ts:13:17 index.ts:4:12 4 +route GET /d1/d2/d3/d4/d5/here index.ts:15:17 index.ts:4:12 5 +route GET /d1/d2/d3/d4/d5/d6/here index.ts:17:17 index.ts:4:12 6 +route GET /d1/d2/d3/d4/d5/d6/d7/here index.ts:19:17 index.ts:4:12 7 +route GET /d1/d2/d3/d4/d5/d6/d7/d8/here index.ts:21:17 index.ts:4:12 8 +route GET /d1/d2/d3/d4/d5/d6/d7/d8/d9/here index.ts:23:17 index.ts:4:12 9 +submount /d9 index.ts:24:4 +submount /d8 index.ts:25:4 +submount /d7 index.ts:26:4 +submount /d6 index.ts:27:4 +submount /d5 index.ts:28:4 +submount /d4 index.ts:29:4 +submount /d3 index.ts:30:4 +submount /d2 index.ts:31:4 +submount /d1 index.ts:32:4 +regby index.ts:1:1 index.ts:11:17 GET /d1/d2/d3/here index.ts:4:12 +regby index.ts:1:1 index.ts:13:17 GET /d1/d2/d3/d4/here index.ts:4:12 +regby index.ts:1:1 index.ts:15:17 GET /d1/d2/d3/d4/d5/here index.ts:4:12 +regby index.ts:1:1 index.ts:17:17 GET /d1/d2/d3/d4/d5/d6/here index.ts:4:12 +regby index.ts:1:1 index.ts:19:17 GET /d1/d2/d3/d4/d5/d6/d7/here index.ts:4:12 +regby index.ts:1:1 index.ts:21:17 GET /d1/d2/d3/d4/d5/d6/d7/d8/here index.ts:4:12 +regby index.ts:1:1 index.ts:23:17 GET /d1/d2/d3/d4/d5/d6/d7/d8/d9/here index.ts:4:12 +regby index.ts:1:1 index.ts:5:17 GET /here index.ts:4:12 +regby index.ts:1:1 index.ts:7:17 GET /d1/here index.ts:4:12 +regby index.ts:1:1 index.ts:9:17 GET /d1/d2/here index.ts:4:12 diff --git a/graph/test/typescript/hono/expected/scale/mw-200.entries b/graph/test/typescript/hono/expected/scale/mw-200.entries new file mode 100644 index 000000000..4eaa815d0 --- /dev/null +++ b/graph/test/typescript/hono/expected/scale/mw-200.entries @@ -0,0 +1,212 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: 200 middleware x 10 routes = 2,000 applications, positions 0..199 per route; runtime agrees +# census: use_global, await_next (scale: 200 middleware x 10 routes; generated by tools/gen-scale.mjs) +entry index.ts:100:32 http +entry index.ts:102:32 http +entry index.ts:104:32 http +entry index.ts:106:32 http +entry index.ts:108:32 http +entry index.ts:10:31 http +entry index.ts:110:32 http +entry index.ts:112:32 http +entry index.ts:114:32 http +entry index.ts:116:32 http +entry index.ts:118:32 http +entry index.ts:120:32 http +entry index.ts:122:32 http +entry index.ts:124:32 http +entry index.ts:126:32 http +entry index.ts:128:32 http +entry index.ts:12:31 http +entry index.ts:130:32 http +entry index.ts:132:32 http +entry index.ts:134:32 http +entry index.ts:136:32 http +entry index.ts:138:32 http +entry index.ts:140:32 http +entry index.ts:142:32 http +entry index.ts:144:32 http +entry index.ts:146:32 http +entry index.ts:148:32 http +entry index.ts:14:31 http +entry index.ts:150:32 http +entry index.ts:152:32 http +entry index.ts:154:32 http +entry index.ts:156:32 http +entry index.ts:158:32 http +entry index.ts:160:32 http +entry index.ts:162:32 http +entry index.ts:164:32 http +entry index.ts:166:32 http +entry index.ts:168:32 http +entry index.ts:16:31 http +entry index.ts:170:32 http +entry index.ts:172:32 http +entry index.ts:174:32 http +entry index.ts:176:32 http +entry index.ts:178:32 http +entry index.ts:180:32 http +entry index.ts:182:32 http +entry index.ts:184:32 http +entry index.ts:186:32 http +entry index.ts:188:32 http +entry index.ts:18:31 http +entry index.ts:190:32 http +entry index.ts:192:32 http +entry index.ts:194:32 http +entry index.ts:196:32 http +entry index.ts:198:32 http +entry index.ts:200:32 http +entry index.ts:202:32 http +entry index.ts:204:32 http +entry index.ts:206:33 http +entry index.ts:208:33 http +entry index.ts:20:31 http +entry index.ts:210:33 http +entry index.ts:212:33 http +entry index.ts:214:33 http +entry index.ts:216:33 http +entry index.ts:218:33 http +entry index.ts:220:33 http +entry index.ts:222:33 http +entry index.ts:224:33 http +entry index.ts:226:33 http +entry index.ts:228:33 http +entry index.ts:22:31 http +entry index.ts:230:33 http +entry index.ts:232:33 http +entry index.ts:234:33 http +entry index.ts:236:33 http +entry index.ts:238:33 http +entry index.ts:240:33 http +entry index.ts:242:33 http +entry index.ts:244:33 http +entry index.ts:246:33 http +entry index.ts:248:33 http +entry index.ts:24:31 http +entry index.ts:250:33 http +entry index.ts:252:33 http +entry index.ts:254:33 http +entry index.ts:256:33 http +entry index.ts:258:33 http +entry index.ts:260:33 http +entry index.ts:262:33 http +entry index.ts:264:33 http +entry index.ts:266:33 http +entry index.ts:268:33 http +entry index.ts:26:32 http +entry index.ts:270:33 http +entry index.ts:272:33 http +entry index.ts:274:33 http +entry index.ts:276:33 http +entry index.ts:278:33 http +entry index.ts:280:33 http +entry index.ts:282:33 http +entry index.ts:284:33 http +entry index.ts:286:33 http +entry index.ts:288:33 http +entry index.ts:28:32 http +entry index.ts:290:33 http +entry index.ts:292:33 http +entry index.ts:294:33 http +entry index.ts:296:33 http +entry index.ts:298:33 http +entry index.ts:300:33 http +entry index.ts:302:33 http +entry index.ts:304:33 http +entry index.ts:306:33 http +entry index.ts:308:33 http +entry index.ts:30:32 http +entry index.ts:310:33 http +entry index.ts:312:33 http +entry index.ts:314:33 http +entry index.ts:316:33 http +entry index.ts:318:33 http +entry index.ts:320:33 http +entry index.ts:322:33 http +entry index.ts:324:33 http +entry index.ts:326:33 http +entry index.ts:328:33 http +entry index.ts:32:32 http +entry index.ts:330:33 http +entry index.ts:332:33 http +entry index.ts:334:33 http +entry index.ts:336:33 http +entry index.ts:338:33 http +entry index.ts:340:33 http +entry index.ts:342:33 http +entry index.ts:344:33 http +entry index.ts:346:33 http +entry index.ts:348:33 http +entry index.ts:34:32 http +entry index.ts:350:33 http +entry index.ts:352:33 http +entry index.ts:354:33 http +entry index.ts:356:33 http +entry index.ts:358:33 http +entry index.ts:360:33 http +entry index.ts:362:33 http +entry index.ts:364:33 http +entry index.ts:366:33 http +entry index.ts:368:33 http +entry index.ts:36:32 http +entry index.ts:370:33 http +entry index.ts:372:33 http +entry index.ts:374:33 http +entry index.ts:376:33 http +entry index.ts:378:33 http +entry index.ts:380:33 http +entry index.ts:382:33 http +entry index.ts:384:33 http +entry index.ts:386:33 http +entry index.ts:388:33 http +entry index.ts:38:32 http +entry index.ts:390:33 http +entry index.ts:392:33 http +entry index.ts:394:33 http +entry index.ts:396:33 http +entry index.ts:398:33 http +entry index.ts:400:33 http +entry index.ts:402:33 http +entry index.ts:404:33 http +entry index.ts:406:16 http +entry index.ts:407:16 http +entry index.ts:408:16 http +entry index.ts:409:16 http +entry index.ts:40:32 http +entry index.ts:410:16 http +entry index.ts:411:16 http +entry index.ts:412:16 http +entry index.ts:413:16 http +entry index.ts:414:16 http +entry index.ts:415:16 http +entry index.ts:42:32 http +entry index.ts:44:32 http +entry index.ts:46:32 http +entry index.ts:48:32 http +entry index.ts:50:32 http +entry index.ts:52:32 http +entry index.ts:54:32 http +entry index.ts:56:32 http +entry index.ts:58:32 http +entry index.ts:60:32 http +entry index.ts:62:32 http +entry index.ts:64:32 http +entry index.ts:66:32 http +entry index.ts:68:32 http +entry index.ts:6:31 http +entry index.ts:70:32 http +entry index.ts:72:32 http +entry index.ts:74:32 http +entry index.ts:76:32 http +entry index.ts:78:32 http +entry index.ts:80:32 http +entry index.ts:82:32 http +entry index.ts:84:32 http +entry index.ts:86:32 http +entry index.ts:88:32 http +entry index.ts:8:31 http +entry index.ts:90:32 http +entry index.ts:92:32 http +entry index.ts:94:32 http +entry index.ts:96:32 http +entry index.ts:98:32 http diff --git a/graph/test/typescript/hono/expected/scale/mw-200.tsv b/graph/test/typescript/hono/expected/scale/mw-200.tsv new file mode 100644 index 000000000..a7ebfdf6f --- /dev/null +++ b/graph/test/typescript/hono/expected/scale/mw-200.tsv @@ -0,0 +1,2024 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: 200 middleware x 10 routes = 2,000 applications, positions 0..199 per route; runtime agrees +# census: use_global, await_next (scale: 200 middleware x 10 routes; generated by tools/gen-scale.mjs) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /r0 index.ts:406:16 index.ts:5:13 200 +route GET /r1 index.ts:407:16 index.ts:5:13 201 +route GET /r2 index.ts:408:16 index.ts:5:13 202 +route GET /r3 index.ts:409:16 index.ts:5:13 203 +route GET /r4 index.ts:410:16 index.ts:5:13 204 +route GET /r5 index.ts:411:16 index.ts:5:13 205 +route GET /r6 index.ts:412:16 index.ts:5:13 206 +route GET /r7 index.ts:413:16 index.ts:5:13 207 +route GET /r8 index.ts:414:16 index.ts:5:13 208 +route GET /r9 index.ts:415:16 index.ts:5:13 209 +mw index.ts:6:31 index.ts:406:16 GET /r0 0 index.ts:5:13 +mw index.ts:8:31 index.ts:406:16 GET /r0 1 index.ts:5:13 +mw index.ts:10:31 index.ts:406:16 GET /r0 2 index.ts:5:13 +mw index.ts:12:31 index.ts:406:16 GET /r0 3 index.ts:5:13 +mw index.ts:14:31 index.ts:406:16 GET /r0 4 index.ts:5:13 +mw index.ts:16:31 index.ts:406:16 GET /r0 5 index.ts:5:13 +mw index.ts:18:31 index.ts:406:16 GET /r0 6 index.ts:5:13 +mw index.ts:20:31 index.ts:406:16 GET /r0 7 index.ts:5:13 +mw index.ts:22:31 index.ts:406:16 GET /r0 8 index.ts:5:13 +mw index.ts:24:31 index.ts:406:16 GET /r0 9 index.ts:5:13 +mw index.ts:26:32 index.ts:406:16 GET /r0 10 index.ts:5:13 +mw index.ts:28:32 index.ts:406:16 GET /r0 11 index.ts:5:13 +mw index.ts:30:32 index.ts:406:16 GET /r0 12 index.ts:5:13 +mw index.ts:32:32 index.ts:406:16 GET /r0 13 index.ts:5:13 +mw index.ts:34:32 index.ts:406:16 GET /r0 14 index.ts:5:13 +mw index.ts:36:32 index.ts:406:16 GET /r0 15 index.ts:5:13 +mw index.ts:38:32 index.ts:406:16 GET /r0 16 index.ts:5:13 +mw index.ts:40:32 index.ts:406:16 GET /r0 17 index.ts:5:13 +mw index.ts:42:32 index.ts:406:16 GET /r0 18 index.ts:5:13 +mw index.ts:44:32 index.ts:406:16 GET /r0 19 index.ts:5:13 +mw index.ts:46:32 index.ts:406:16 GET /r0 20 index.ts:5:13 +mw index.ts:48:32 index.ts:406:16 GET /r0 21 index.ts:5:13 +mw index.ts:50:32 index.ts:406:16 GET /r0 22 index.ts:5:13 +mw index.ts:52:32 index.ts:406:16 GET /r0 23 index.ts:5:13 +mw index.ts:54:32 index.ts:406:16 GET /r0 24 index.ts:5:13 +mw index.ts:56:32 index.ts:406:16 GET /r0 25 index.ts:5:13 +mw index.ts:58:32 index.ts:406:16 GET /r0 26 index.ts:5:13 +mw index.ts:60:32 index.ts:406:16 GET /r0 27 index.ts:5:13 +mw index.ts:62:32 index.ts:406:16 GET /r0 28 index.ts:5:13 +mw index.ts:64:32 index.ts:406:16 GET /r0 29 index.ts:5:13 +mw index.ts:66:32 index.ts:406:16 GET /r0 30 index.ts:5:13 +mw index.ts:68:32 index.ts:406:16 GET /r0 31 index.ts:5:13 +mw index.ts:70:32 index.ts:406:16 GET /r0 32 index.ts:5:13 +mw index.ts:72:32 index.ts:406:16 GET /r0 33 index.ts:5:13 +mw index.ts:74:32 index.ts:406:16 GET /r0 34 index.ts:5:13 +mw index.ts:76:32 index.ts:406:16 GET /r0 35 index.ts:5:13 +mw index.ts:78:32 index.ts:406:16 GET /r0 36 index.ts:5:13 +mw index.ts:80:32 index.ts:406:16 GET /r0 37 index.ts:5:13 +mw index.ts:82:32 index.ts:406:16 GET /r0 38 index.ts:5:13 +mw index.ts:84:32 index.ts:406:16 GET /r0 39 index.ts:5:13 +mw index.ts:86:32 index.ts:406:16 GET /r0 40 index.ts:5:13 +mw index.ts:88:32 index.ts:406:16 GET /r0 41 index.ts:5:13 +mw index.ts:90:32 index.ts:406:16 GET /r0 42 index.ts:5:13 +mw index.ts:92:32 index.ts:406:16 GET /r0 43 index.ts:5:13 +mw index.ts:94:32 index.ts:406:16 GET /r0 44 index.ts:5:13 +mw index.ts:96:32 index.ts:406:16 GET /r0 45 index.ts:5:13 +mw index.ts:98:32 index.ts:406:16 GET /r0 46 index.ts:5:13 +mw index.ts:100:32 index.ts:406:16 GET /r0 47 index.ts:5:13 +mw index.ts:102:32 index.ts:406:16 GET /r0 48 index.ts:5:13 +mw index.ts:104:32 index.ts:406:16 GET /r0 49 index.ts:5:13 +mw index.ts:106:32 index.ts:406:16 GET /r0 50 index.ts:5:13 +mw index.ts:108:32 index.ts:406:16 GET /r0 51 index.ts:5:13 +mw index.ts:110:32 index.ts:406:16 GET /r0 52 index.ts:5:13 +mw index.ts:112:32 index.ts:406:16 GET /r0 53 index.ts:5:13 +mw index.ts:114:32 index.ts:406:16 GET /r0 54 index.ts:5:13 +mw index.ts:116:32 index.ts:406:16 GET /r0 55 index.ts:5:13 +mw index.ts:118:32 index.ts:406:16 GET /r0 56 index.ts:5:13 +mw index.ts:120:32 index.ts:406:16 GET /r0 57 index.ts:5:13 +mw index.ts:122:32 index.ts:406:16 GET /r0 58 index.ts:5:13 +mw index.ts:124:32 index.ts:406:16 GET /r0 59 index.ts:5:13 +mw index.ts:126:32 index.ts:406:16 GET /r0 60 index.ts:5:13 +mw index.ts:128:32 index.ts:406:16 GET /r0 61 index.ts:5:13 +mw index.ts:130:32 index.ts:406:16 GET /r0 62 index.ts:5:13 +mw index.ts:132:32 index.ts:406:16 GET /r0 63 index.ts:5:13 +mw index.ts:134:32 index.ts:406:16 GET /r0 64 index.ts:5:13 +mw index.ts:136:32 index.ts:406:16 GET /r0 65 index.ts:5:13 +mw index.ts:138:32 index.ts:406:16 GET /r0 66 index.ts:5:13 +mw index.ts:140:32 index.ts:406:16 GET /r0 67 index.ts:5:13 +mw index.ts:142:32 index.ts:406:16 GET /r0 68 index.ts:5:13 +mw index.ts:144:32 index.ts:406:16 GET /r0 69 index.ts:5:13 +mw index.ts:146:32 index.ts:406:16 GET /r0 70 index.ts:5:13 +mw index.ts:148:32 index.ts:406:16 GET /r0 71 index.ts:5:13 +mw index.ts:150:32 index.ts:406:16 GET /r0 72 index.ts:5:13 +mw index.ts:152:32 index.ts:406:16 GET /r0 73 index.ts:5:13 +mw index.ts:154:32 index.ts:406:16 GET /r0 74 index.ts:5:13 +mw index.ts:156:32 index.ts:406:16 GET /r0 75 index.ts:5:13 +mw index.ts:158:32 index.ts:406:16 GET /r0 76 index.ts:5:13 +mw index.ts:160:32 index.ts:406:16 GET /r0 77 index.ts:5:13 +mw index.ts:162:32 index.ts:406:16 GET /r0 78 index.ts:5:13 +mw index.ts:164:32 index.ts:406:16 GET /r0 79 index.ts:5:13 +mw index.ts:166:32 index.ts:406:16 GET /r0 80 index.ts:5:13 +mw index.ts:168:32 index.ts:406:16 GET /r0 81 index.ts:5:13 +mw index.ts:170:32 index.ts:406:16 GET /r0 82 index.ts:5:13 +mw index.ts:172:32 index.ts:406:16 GET /r0 83 index.ts:5:13 +mw index.ts:174:32 index.ts:406:16 GET /r0 84 index.ts:5:13 +mw index.ts:176:32 index.ts:406:16 GET /r0 85 index.ts:5:13 +mw index.ts:178:32 index.ts:406:16 GET /r0 86 index.ts:5:13 +mw index.ts:180:32 index.ts:406:16 GET /r0 87 index.ts:5:13 +mw index.ts:182:32 index.ts:406:16 GET /r0 88 index.ts:5:13 +mw index.ts:184:32 index.ts:406:16 GET /r0 89 index.ts:5:13 +mw index.ts:186:32 index.ts:406:16 GET /r0 90 index.ts:5:13 +mw index.ts:188:32 index.ts:406:16 GET /r0 91 index.ts:5:13 +mw index.ts:190:32 index.ts:406:16 GET /r0 92 index.ts:5:13 +mw index.ts:192:32 index.ts:406:16 GET /r0 93 index.ts:5:13 +mw index.ts:194:32 index.ts:406:16 GET /r0 94 index.ts:5:13 +mw index.ts:196:32 index.ts:406:16 GET /r0 95 index.ts:5:13 +mw index.ts:198:32 index.ts:406:16 GET /r0 96 index.ts:5:13 +mw index.ts:200:32 index.ts:406:16 GET /r0 97 index.ts:5:13 +mw index.ts:202:32 index.ts:406:16 GET /r0 98 index.ts:5:13 +mw index.ts:204:32 index.ts:406:16 GET /r0 99 index.ts:5:13 +mw index.ts:206:33 index.ts:406:16 GET /r0 100 index.ts:5:13 +mw index.ts:208:33 index.ts:406:16 GET /r0 101 index.ts:5:13 +mw index.ts:210:33 index.ts:406:16 GET /r0 102 index.ts:5:13 +mw index.ts:212:33 index.ts:406:16 GET /r0 103 index.ts:5:13 +mw index.ts:214:33 index.ts:406:16 GET /r0 104 index.ts:5:13 +mw index.ts:216:33 index.ts:406:16 GET /r0 105 index.ts:5:13 +mw index.ts:218:33 index.ts:406:16 GET /r0 106 index.ts:5:13 +mw index.ts:220:33 index.ts:406:16 GET /r0 107 index.ts:5:13 +mw index.ts:222:33 index.ts:406:16 GET /r0 108 index.ts:5:13 +mw index.ts:224:33 index.ts:406:16 GET /r0 109 index.ts:5:13 +mw index.ts:226:33 index.ts:406:16 GET /r0 110 index.ts:5:13 +mw index.ts:228:33 index.ts:406:16 GET /r0 111 index.ts:5:13 +mw index.ts:230:33 index.ts:406:16 GET /r0 112 index.ts:5:13 +mw index.ts:232:33 index.ts:406:16 GET /r0 113 index.ts:5:13 +mw index.ts:234:33 index.ts:406:16 GET /r0 114 index.ts:5:13 +mw index.ts:236:33 index.ts:406:16 GET /r0 115 index.ts:5:13 +mw index.ts:238:33 index.ts:406:16 GET /r0 116 index.ts:5:13 +mw index.ts:240:33 index.ts:406:16 GET /r0 117 index.ts:5:13 +mw index.ts:242:33 index.ts:406:16 GET /r0 118 index.ts:5:13 +mw index.ts:244:33 index.ts:406:16 GET /r0 119 index.ts:5:13 +mw index.ts:246:33 index.ts:406:16 GET /r0 120 index.ts:5:13 +mw index.ts:248:33 index.ts:406:16 GET /r0 121 index.ts:5:13 +mw index.ts:250:33 index.ts:406:16 GET /r0 122 index.ts:5:13 +mw index.ts:252:33 index.ts:406:16 GET /r0 123 index.ts:5:13 +mw index.ts:254:33 index.ts:406:16 GET /r0 124 index.ts:5:13 +mw index.ts:256:33 index.ts:406:16 GET /r0 125 index.ts:5:13 +mw index.ts:258:33 index.ts:406:16 GET /r0 126 index.ts:5:13 +mw index.ts:260:33 index.ts:406:16 GET /r0 127 index.ts:5:13 +mw index.ts:262:33 index.ts:406:16 GET /r0 128 index.ts:5:13 +mw index.ts:264:33 index.ts:406:16 GET /r0 129 index.ts:5:13 +mw index.ts:266:33 index.ts:406:16 GET /r0 130 index.ts:5:13 +mw index.ts:268:33 index.ts:406:16 GET /r0 131 index.ts:5:13 +mw index.ts:270:33 index.ts:406:16 GET /r0 132 index.ts:5:13 +mw index.ts:272:33 index.ts:406:16 GET /r0 133 index.ts:5:13 +mw index.ts:274:33 index.ts:406:16 GET /r0 134 index.ts:5:13 +mw index.ts:276:33 index.ts:406:16 GET /r0 135 index.ts:5:13 +mw index.ts:278:33 index.ts:406:16 GET /r0 136 index.ts:5:13 +mw index.ts:280:33 index.ts:406:16 GET /r0 137 index.ts:5:13 +mw index.ts:282:33 index.ts:406:16 GET /r0 138 index.ts:5:13 +mw index.ts:284:33 index.ts:406:16 GET /r0 139 index.ts:5:13 +mw index.ts:286:33 index.ts:406:16 GET /r0 140 index.ts:5:13 +mw index.ts:288:33 index.ts:406:16 GET /r0 141 index.ts:5:13 +mw index.ts:290:33 index.ts:406:16 GET /r0 142 index.ts:5:13 +mw index.ts:292:33 index.ts:406:16 GET /r0 143 index.ts:5:13 +mw index.ts:294:33 index.ts:406:16 GET /r0 144 index.ts:5:13 +mw index.ts:296:33 index.ts:406:16 GET /r0 145 index.ts:5:13 +mw index.ts:298:33 index.ts:406:16 GET /r0 146 index.ts:5:13 +mw index.ts:300:33 index.ts:406:16 GET /r0 147 index.ts:5:13 +mw index.ts:302:33 index.ts:406:16 GET /r0 148 index.ts:5:13 +mw index.ts:304:33 index.ts:406:16 GET /r0 149 index.ts:5:13 +mw index.ts:306:33 index.ts:406:16 GET /r0 150 index.ts:5:13 +mw index.ts:308:33 index.ts:406:16 GET /r0 151 index.ts:5:13 +mw index.ts:310:33 index.ts:406:16 GET /r0 152 index.ts:5:13 +mw index.ts:312:33 index.ts:406:16 GET /r0 153 index.ts:5:13 +mw index.ts:314:33 index.ts:406:16 GET /r0 154 index.ts:5:13 +mw index.ts:316:33 index.ts:406:16 GET /r0 155 index.ts:5:13 +mw index.ts:318:33 index.ts:406:16 GET /r0 156 index.ts:5:13 +mw index.ts:320:33 index.ts:406:16 GET /r0 157 index.ts:5:13 +mw index.ts:322:33 index.ts:406:16 GET /r0 158 index.ts:5:13 +mw index.ts:324:33 index.ts:406:16 GET /r0 159 index.ts:5:13 +mw index.ts:326:33 index.ts:406:16 GET /r0 160 index.ts:5:13 +mw index.ts:328:33 index.ts:406:16 GET /r0 161 index.ts:5:13 +mw index.ts:330:33 index.ts:406:16 GET /r0 162 index.ts:5:13 +mw index.ts:332:33 index.ts:406:16 GET /r0 163 index.ts:5:13 +mw index.ts:334:33 index.ts:406:16 GET /r0 164 index.ts:5:13 +mw index.ts:336:33 index.ts:406:16 GET /r0 165 index.ts:5:13 +mw index.ts:338:33 index.ts:406:16 GET /r0 166 index.ts:5:13 +mw index.ts:340:33 index.ts:406:16 GET /r0 167 index.ts:5:13 +mw index.ts:342:33 index.ts:406:16 GET /r0 168 index.ts:5:13 +mw index.ts:344:33 index.ts:406:16 GET /r0 169 index.ts:5:13 +mw index.ts:346:33 index.ts:406:16 GET /r0 170 index.ts:5:13 +mw index.ts:348:33 index.ts:406:16 GET /r0 171 index.ts:5:13 +mw index.ts:350:33 index.ts:406:16 GET /r0 172 index.ts:5:13 +mw index.ts:352:33 index.ts:406:16 GET /r0 173 index.ts:5:13 +mw index.ts:354:33 index.ts:406:16 GET /r0 174 index.ts:5:13 +mw index.ts:356:33 index.ts:406:16 GET /r0 175 index.ts:5:13 +mw index.ts:358:33 index.ts:406:16 GET /r0 176 index.ts:5:13 +mw index.ts:360:33 index.ts:406:16 GET /r0 177 index.ts:5:13 +mw index.ts:362:33 index.ts:406:16 GET /r0 178 index.ts:5:13 +mw index.ts:364:33 index.ts:406:16 GET /r0 179 index.ts:5:13 +mw index.ts:366:33 index.ts:406:16 GET /r0 180 index.ts:5:13 +mw index.ts:368:33 index.ts:406:16 GET /r0 181 index.ts:5:13 +mw index.ts:370:33 index.ts:406:16 GET /r0 182 index.ts:5:13 +mw index.ts:372:33 index.ts:406:16 GET /r0 183 index.ts:5:13 +mw index.ts:374:33 index.ts:406:16 GET /r0 184 index.ts:5:13 +mw index.ts:376:33 index.ts:406:16 GET /r0 185 index.ts:5:13 +mw index.ts:378:33 index.ts:406:16 GET /r0 186 index.ts:5:13 +mw index.ts:380:33 index.ts:406:16 GET /r0 187 index.ts:5:13 +mw index.ts:382:33 index.ts:406:16 GET /r0 188 index.ts:5:13 +mw index.ts:384:33 index.ts:406:16 GET /r0 189 index.ts:5:13 +mw index.ts:386:33 index.ts:406:16 GET /r0 190 index.ts:5:13 +mw index.ts:388:33 index.ts:406:16 GET /r0 191 index.ts:5:13 +mw index.ts:390:33 index.ts:406:16 GET /r0 192 index.ts:5:13 +mw index.ts:392:33 index.ts:406:16 GET /r0 193 index.ts:5:13 +mw index.ts:394:33 index.ts:406:16 GET /r0 194 index.ts:5:13 +mw index.ts:396:33 index.ts:406:16 GET /r0 195 index.ts:5:13 +mw index.ts:398:33 index.ts:406:16 GET /r0 196 index.ts:5:13 +mw index.ts:400:33 index.ts:406:16 GET /r0 197 index.ts:5:13 +mw index.ts:402:33 index.ts:406:16 GET /r0 198 index.ts:5:13 +mw index.ts:404:33 index.ts:406:16 GET /r0 199 index.ts:5:13 +mw index.ts:6:31 index.ts:407:16 GET /r1 0 index.ts:5:13 +mw index.ts:8:31 index.ts:407:16 GET /r1 1 index.ts:5:13 +mw index.ts:10:31 index.ts:407:16 GET /r1 2 index.ts:5:13 +mw index.ts:12:31 index.ts:407:16 GET /r1 3 index.ts:5:13 +mw index.ts:14:31 index.ts:407:16 GET /r1 4 index.ts:5:13 +mw index.ts:16:31 index.ts:407:16 GET /r1 5 index.ts:5:13 +mw index.ts:18:31 index.ts:407:16 GET /r1 6 index.ts:5:13 +mw index.ts:20:31 index.ts:407:16 GET /r1 7 index.ts:5:13 +mw index.ts:22:31 index.ts:407:16 GET /r1 8 index.ts:5:13 +mw index.ts:24:31 index.ts:407:16 GET /r1 9 index.ts:5:13 +mw index.ts:26:32 index.ts:407:16 GET /r1 10 index.ts:5:13 +mw index.ts:28:32 index.ts:407:16 GET /r1 11 index.ts:5:13 +mw index.ts:30:32 index.ts:407:16 GET /r1 12 index.ts:5:13 +mw index.ts:32:32 index.ts:407:16 GET /r1 13 index.ts:5:13 +mw index.ts:34:32 index.ts:407:16 GET /r1 14 index.ts:5:13 +mw index.ts:36:32 index.ts:407:16 GET /r1 15 index.ts:5:13 +mw index.ts:38:32 index.ts:407:16 GET /r1 16 index.ts:5:13 +mw index.ts:40:32 index.ts:407:16 GET /r1 17 index.ts:5:13 +mw index.ts:42:32 index.ts:407:16 GET /r1 18 index.ts:5:13 +mw index.ts:44:32 index.ts:407:16 GET /r1 19 index.ts:5:13 +mw index.ts:46:32 index.ts:407:16 GET /r1 20 index.ts:5:13 +mw index.ts:48:32 index.ts:407:16 GET /r1 21 index.ts:5:13 +mw index.ts:50:32 index.ts:407:16 GET /r1 22 index.ts:5:13 +mw index.ts:52:32 index.ts:407:16 GET /r1 23 index.ts:5:13 +mw index.ts:54:32 index.ts:407:16 GET /r1 24 index.ts:5:13 +mw index.ts:56:32 index.ts:407:16 GET /r1 25 index.ts:5:13 +mw index.ts:58:32 index.ts:407:16 GET /r1 26 index.ts:5:13 +mw index.ts:60:32 index.ts:407:16 GET /r1 27 index.ts:5:13 +mw index.ts:62:32 index.ts:407:16 GET /r1 28 index.ts:5:13 +mw index.ts:64:32 index.ts:407:16 GET /r1 29 index.ts:5:13 +mw index.ts:66:32 index.ts:407:16 GET /r1 30 index.ts:5:13 +mw index.ts:68:32 index.ts:407:16 GET /r1 31 index.ts:5:13 +mw index.ts:70:32 index.ts:407:16 GET /r1 32 index.ts:5:13 +mw index.ts:72:32 index.ts:407:16 GET /r1 33 index.ts:5:13 +mw index.ts:74:32 index.ts:407:16 GET /r1 34 index.ts:5:13 +mw index.ts:76:32 index.ts:407:16 GET /r1 35 index.ts:5:13 +mw index.ts:78:32 index.ts:407:16 GET /r1 36 index.ts:5:13 +mw index.ts:80:32 index.ts:407:16 GET /r1 37 index.ts:5:13 +mw index.ts:82:32 index.ts:407:16 GET /r1 38 index.ts:5:13 +mw index.ts:84:32 index.ts:407:16 GET /r1 39 index.ts:5:13 +mw index.ts:86:32 index.ts:407:16 GET /r1 40 index.ts:5:13 +mw index.ts:88:32 index.ts:407:16 GET /r1 41 index.ts:5:13 +mw index.ts:90:32 index.ts:407:16 GET /r1 42 index.ts:5:13 +mw index.ts:92:32 index.ts:407:16 GET /r1 43 index.ts:5:13 +mw index.ts:94:32 index.ts:407:16 GET /r1 44 index.ts:5:13 +mw index.ts:96:32 index.ts:407:16 GET /r1 45 index.ts:5:13 +mw index.ts:98:32 index.ts:407:16 GET /r1 46 index.ts:5:13 +mw index.ts:100:32 index.ts:407:16 GET /r1 47 index.ts:5:13 +mw index.ts:102:32 index.ts:407:16 GET /r1 48 index.ts:5:13 +mw index.ts:104:32 index.ts:407:16 GET /r1 49 index.ts:5:13 +mw index.ts:106:32 index.ts:407:16 GET /r1 50 index.ts:5:13 +mw index.ts:108:32 index.ts:407:16 GET /r1 51 index.ts:5:13 +mw index.ts:110:32 index.ts:407:16 GET /r1 52 index.ts:5:13 +mw index.ts:112:32 index.ts:407:16 GET /r1 53 index.ts:5:13 +mw index.ts:114:32 index.ts:407:16 GET /r1 54 index.ts:5:13 +mw index.ts:116:32 index.ts:407:16 GET /r1 55 index.ts:5:13 +mw index.ts:118:32 index.ts:407:16 GET /r1 56 index.ts:5:13 +mw index.ts:120:32 index.ts:407:16 GET /r1 57 index.ts:5:13 +mw index.ts:122:32 index.ts:407:16 GET /r1 58 index.ts:5:13 +mw index.ts:124:32 index.ts:407:16 GET /r1 59 index.ts:5:13 +mw index.ts:126:32 index.ts:407:16 GET /r1 60 index.ts:5:13 +mw index.ts:128:32 index.ts:407:16 GET /r1 61 index.ts:5:13 +mw index.ts:130:32 index.ts:407:16 GET /r1 62 index.ts:5:13 +mw index.ts:132:32 index.ts:407:16 GET /r1 63 index.ts:5:13 +mw index.ts:134:32 index.ts:407:16 GET /r1 64 index.ts:5:13 +mw index.ts:136:32 index.ts:407:16 GET /r1 65 index.ts:5:13 +mw index.ts:138:32 index.ts:407:16 GET /r1 66 index.ts:5:13 +mw index.ts:140:32 index.ts:407:16 GET /r1 67 index.ts:5:13 +mw index.ts:142:32 index.ts:407:16 GET /r1 68 index.ts:5:13 +mw index.ts:144:32 index.ts:407:16 GET /r1 69 index.ts:5:13 +mw index.ts:146:32 index.ts:407:16 GET /r1 70 index.ts:5:13 +mw index.ts:148:32 index.ts:407:16 GET /r1 71 index.ts:5:13 +mw index.ts:150:32 index.ts:407:16 GET /r1 72 index.ts:5:13 +mw index.ts:152:32 index.ts:407:16 GET /r1 73 index.ts:5:13 +mw index.ts:154:32 index.ts:407:16 GET /r1 74 index.ts:5:13 +mw index.ts:156:32 index.ts:407:16 GET /r1 75 index.ts:5:13 +mw index.ts:158:32 index.ts:407:16 GET /r1 76 index.ts:5:13 +mw index.ts:160:32 index.ts:407:16 GET /r1 77 index.ts:5:13 +mw index.ts:162:32 index.ts:407:16 GET /r1 78 index.ts:5:13 +mw index.ts:164:32 index.ts:407:16 GET /r1 79 index.ts:5:13 +mw index.ts:166:32 index.ts:407:16 GET /r1 80 index.ts:5:13 +mw index.ts:168:32 index.ts:407:16 GET /r1 81 index.ts:5:13 +mw index.ts:170:32 index.ts:407:16 GET /r1 82 index.ts:5:13 +mw index.ts:172:32 index.ts:407:16 GET /r1 83 index.ts:5:13 +mw index.ts:174:32 index.ts:407:16 GET /r1 84 index.ts:5:13 +mw index.ts:176:32 index.ts:407:16 GET /r1 85 index.ts:5:13 +mw index.ts:178:32 index.ts:407:16 GET /r1 86 index.ts:5:13 +mw index.ts:180:32 index.ts:407:16 GET /r1 87 index.ts:5:13 +mw index.ts:182:32 index.ts:407:16 GET /r1 88 index.ts:5:13 +mw index.ts:184:32 index.ts:407:16 GET /r1 89 index.ts:5:13 +mw index.ts:186:32 index.ts:407:16 GET /r1 90 index.ts:5:13 +mw index.ts:188:32 index.ts:407:16 GET /r1 91 index.ts:5:13 +mw index.ts:190:32 index.ts:407:16 GET /r1 92 index.ts:5:13 +mw index.ts:192:32 index.ts:407:16 GET /r1 93 index.ts:5:13 +mw index.ts:194:32 index.ts:407:16 GET /r1 94 index.ts:5:13 +mw index.ts:196:32 index.ts:407:16 GET /r1 95 index.ts:5:13 +mw index.ts:198:32 index.ts:407:16 GET /r1 96 index.ts:5:13 +mw index.ts:200:32 index.ts:407:16 GET /r1 97 index.ts:5:13 +mw index.ts:202:32 index.ts:407:16 GET /r1 98 index.ts:5:13 +mw index.ts:204:32 index.ts:407:16 GET /r1 99 index.ts:5:13 +mw index.ts:206:33 index.ts:407:16 GET /r1 100 index.ts:5:13 +mw index.ts:208:33 index.ts:407:16 GET /r1 101 index.ts:5:13 +mw index.ts:210:33 index.ts:407:16 GET /r1 102 index.ts:5:13 +mw index.ts:212:33 index.ts:407:16 GET /r1 103 index.ts:5:13 +mw index.ts:214:33 index.ts:407:16 GET /r1 104 index.ts:5:13 +mw index.ts:216:33 index.ts:407:16 GET /r1 105 index.ts:5:13 +mw index.ts:218:33 index.ts:407:16 GET /r1 106 index.ts:5:13 +mw index.ts:220:33 index.ts:407:16 GET /r1 107 index.ts:5:13 +mw index.ts:222:33 index.ts:407:16 GET /r1 108 index.ts:5:13 +mw index.ts:224:33 index.ts:407:16 GET /r1 109 index.ts:5:13 +mw index.ts:226:33 index.ts:407:16 GET /r1 110 index.ts:5:13 +mw index.ts:228:33 index.ts:407:16 GET /r1 111 index.ts:5:13 +mw index.ts:230:33 index.ts:407:16 GET /r1 112 index.ts:5:13 +mw index.ts:232:33 index.ts:407:16 GET /r1 113 index.ts:5:13 +mw index.ts:234:33 index.ts:407:16 GET /r1 114 index.ts:5:13 +mw index.ts:236:33 index.ts:407:16 GET /r1 115 index.ts:5:13 +mw index.ts:238:33 index.ts:407:16 GET /r1 116 index.ts:5:13 +mw index.ts:240:33 index.ts:407:16 GET /r1 117 index.ts:5:13 +mw index.ts:242:33 index.ts:407:16 GET /r1 118 index.ts:5:13 +mw index.ts:244:33 index.ts:407:16 GET /r1 119 index.ts:5:13 +mw index.ts:246:33 index.ts:407:16 GET /r1 120 index.ts:5:13 +mw index.ts:248:33 index.ts:407:16 GET /r1 121 index.ts:5:13 +mw index.ts:250:33 index.ts:407:16 GET /r1 122 index.ts:5:13 +mw index.ts:252:33 index.ts:407:16 GET /r1 123 index.ts:5:13 +mw index.ts:254:33 index.ts:407:16 GET /r1 124 index.ts:5:13 +mw index.ts:256:33 index.ts:407:16 GET /r1 125 index.ts:5:13 +mw index.ts:258:33 index.ts:407:16 GET /r1 126 index.ts:5:13 +mw index.ts:260:33 index.ts:407:16 GET /r1 127 index.ts:5:13 +mw index.ts:262:33 index.ts:407:16 GET /r1 128 index.ts:5:13 +mw index.ts:264:33 index.ts:407:16 GET /r1 129 index.ts:5:13 +mw index.ts:266:33 index.ts:407:16 GET /r1 130 index.ts:5:13 +mw index.ts:268:33 index.ts:407:16 GET /r1 131 index.ts:5:13 +mw index.ts:270:33 index.ts:407:16 GET /r1 132 index.ts:5:13 +mw index.ts:272:33 index.ts:407:16 GET /r1 133 index.ts:5:13 +mw index.ts:274:33 index.ts:407:16 GET /r1 134 index.ts:5:13 +mw index.ts:276:33 index.ts:407:16 GET /r1 135 index.ts:5:13 +mw index.ts:278:33 index.ts:407:16 GET /r1 136 index.ts:5:13 +mw index.ts:280:33 index.ts:407:16 GET /r1 137 index.ts:5:13 +mw index.ts:282:33 index.ts:407:16 GET /r1 138 index.ts:5:13 +mw index.ts:284:33 index.ts:407:16 GET /r1 139 index.ts:5:13 +mw index.ts:286:33 index.ts:407:16 GET /r1 140 index.ts:5:13 +mw index.ts:288:33 index.ts:407:16 GET /r1 141 index.ts:5:13 +mw index.ts:290:33 index.ts:407:16 GET /r1 142 index.ts:5:13 +mw index.ts:292:33 index.ts:407:16 GET /r1 143 index.ts:5:13 +mw index.ts:294:33 index.ts:407:16 GET /r1 144 index.ts:5:13 +mw index.ts:296:33 index.ts:407:16 GET /r1 145 index.ts:5:13 +mw index.ts:298:33 index.ts:407:16 GET /r1 146 index.ts:5:13 +mw index.ts:300:33 index.ts:407:16 GET /r1 147 index.ts:5:13 +mw index.ts:302:33 index.ts:407:16 GET /r1 148 index.ts:5:13 +mw index.ts:304:33 index.ts:407:16 GET /r1 149 index.ts:5:13 +mw index.ts:306:33 index.ts:407:16 GET /r1 150 index.ts:5:13 +mw index.ts:308:33 index.ts:407:16 GET /r1 151 index.ts:5:13 +mw index.ts:310:33 index.ts:407:16 GET /r1 152 index.ts:5:13 +mw index.ts:312:33 index.ts:407:16 GET /r1 153 index.ts:5:13 +mw index.ts:314:33 index.ts:407:16 GET /r1 154 index.ts:5:13 +mw index.ts:316:33 index.ts:407:16 GET /r1 155 index.ts:5:13 +mw index.ts:318:33 index.ts:407:16 GET /r1 156 index.ts:5:13 +mw index.ts:320:33 index.ts:407:16 GET /r1 157 index.ts:5:13 +mw index.ts:322:33 index.ts:407:16 GET /r1 158 index.ts:5:13 +mw index.ts:324:33 index.ts:407:16 GET /r1 159 index.ts:5:13 +mw index.ts:326:33 index.ts:407:16 GET /r1 160 index.ts:5:13 +mw index.ts:328:33 index.ts:407:16 GET /r1 161 index.ts:5:13 +mw index.ts:330:33 index.ts:407:16 GET /r1 162 index.ts:5:13 +mw index.ts:332:33 index.ts:407:16 GET /r1 163 index.ts:5:13 +mw index.ts:334:33 index.ts:407:16 GET /r1 164 index.ts:5:13 +mw index.ts:336:33 index.ts:407:16 GET /r1 165 index.ts:5:13 +mw index.ts:338:33 index.ts:407:16 GET /r1 166 index.ts:5:13 +mw index.ts:340:33 index.ts:407:16 GET /r1 167 index.ts:5:13 +mw index.ts:342:33 index.ts:407:16 GET /r1 168 index.ts:5:13 +mw index.ts:344:33 index.ts:407:16 GET /r1 169 index.ts:5:13 +mw index.ts:346:33 index.ts:407:16 GET /r1 170 index.ts:5:13 +mw index.ts:348:33 index.ts:407:16 GET /r1 171 index.ts:5:13 +mw index.ts:350:33 index.ts:407:16 GET /r1 172 index.ts:5:13 +mw index.ts:352:33 index.ts:407:16 GET /r1 173 index.ts:5:13 +mw index.ts:354:33 index.ts:407:16 GET /r1 174 index.ts:5:13 +mw index.ts:356:33 index.ts:407:16 GET /r1 175 index.ts:5:13 +mw index.ts:358:33 index.ts:407:16 GET /r1 176 index.ts:5:13 +mw index.ts:360:33 index.ts:407:16 GET /r1 177 index.ts:5:13 +mw index.ts:362:33 index.ts:407:16 GET /r1 178 index.ts:5:13 +mw index.ts:364:33 index.ts:407:16 GET /r1 179 index.ts:5:13 +mw index.ts:366:33 index.ts:407:16 GET /r1 180 index.ts:5:13 +mw index.ts:368:33 index.ts:407:16 GET /r1 181 index.ts:5:13 +mw index.ts:370:33 index.ts:407:16 GET /r1 182 index.ts:5:13 +mw index.ts:372:33 index.ts:407:16 GET /r1 183 index.ts:5:13 +mw index.ts:374:33 index.ts:407:16 GET /r1 184 index.ts:5:13 +mw index.ts:376:33 index.ts:407:16 GET /r1 185 index.ts:5:13 +mw index.ts:378:33 index.ts:407:16 GET /r1 186 index.ts:5:13 +mw index.ts:380:33 index.ts:407:16 GET /r1 187 index.ts:5:13 +mw index.ts:382:33 index.ts:407:16 GET /r1 188 index.ts:5:13 +mw index.ts:384:33 index.ts:407:16 GET /r1 189 index.ts:5:13 +mw index.ts:386:33 index.ts:407:16 GET /r1 190 index.ts:5:13 +mw index.ts:388:33 index.ts:407:16 GET /r1 191 index.ts:5:13 +mw index.ts:390:33 index.ts:407:16 GET /r1 192 index.ts:5:13 +mw index.ts:392:33 index.ts:407:16 GET /r1 193 index.ts:5:13 +mw index.ts:394:33 index.ts:407:16 GET /r1 194 index.ts:5:13 +mw index.ts:396:33 index.ts:407:16 GET /r1 195 index.ts:5:13 +mw index.ts:398:33 index.ts:407:16 GET /r1 196 index.ts:5:13 +mw index.ts:400:33 index.ts:407:16 GET /r1 197 index.ts:5:13 +mw index.ts:402:33 index.ts:407:16 GET /r1 198 index.ts:5:13 +mw index.ts:404:33 index.ts:407:16 GET /r1 199 index.ts:5:13 +mw index.ts:6:31 index.ts:408:16 GET /r2 0 index.ts:5:13 +mw index.ts:8:31 index.ts:408:16 GET /r2 1 index.ts:5:13 +mw index.ts:10:31 index.ts:408:16 GET /r2 2 index.ts:5:13 +mw index.ts:12:31 index.ts:408:16 GET /r2 3 index.ts:5:13 +mw index.ts:14:31 index.ts:408:16 GET /r2 4 index.ts:5:13 +mw index.ts:16:31 index.ts:408:16 GET /r2 5 index.ts:5:13 +mw index.ts:18:31 index.ts:408:16 GET /r2 6 index.ts:5:13 +mw index.ts:20:31 index.ts:408:16 GET /r2 7 index.ts:5:13 +mw index.ts:22:31 index.ts:408:16 GET /r2 8 index.ts:5:13 +mw index.ts:24:31 index.ts:408:16 GET /r2 9 index.ts:5:13 +mw index.ts:26:32 index.ts:408:16 GET /r2 10 index.ts:5:13 +mw index.ts:28:32 index.ts:408:16 GET /r2 11 index.ts:5:13 +mw index.ts:30:32 index.ts:408:16 GET /r2 12 index.ts:5:13 +mw index.ts:32:32 index.ts:408:16 GET /r2 13 index.ts:5:13 +mw index.ts:34:32 index.ts:408:16 GET /r2 14 index.ts:5:13 +mw index.ts:36:32 index.ts:408:16 GET /r2 15 index.ts:5:13 +mw index.ts:38:32 index.ts:408:16 GET /r2 16 index.ts:5:13 +mw index.ts:40:32 index.ts:408:16 GET /r2 17 index.ts:5:13 +mw index.ts:42:32 index.ts:408:16 GET /r2 18 index.ts:5:13 +mw index.ts:44:32 index.ts:408:16 GET /r2 19 index.ts:5:13 +mw index.ts:46:32 index.ts:408:16 GET /r2 20 index.ts:5:13 +mw index.ts:48:32 index.ts:408:16 GET /r2 21 index.ts:5:13 +mw index.ts:50:32 index.ts:408:16 GET /r2 22 index.ts:5:13 +mw index.ts:52:32 index.ts:408:16 GET /r2 23 index.ts:5:13 +mw index.ts:54:32 index.ts:408:16 GET /r2 24 index.ts:5:13 +mw index.ts:56:32 index.ts:408:16 GET /r2 25 index.ts:5:13 +mw index.ts:58:32 index.ts:408:16 GET /r2 26 index.ts:5:13 +mw index.ts:60:32 index.ts:408:16 GET /r2 27 index.ts:5:13 +mw index.ts:62:32 index.ts:408:16 GET /r2 28 index.ts:5:13 +mw index.ts:64:32 index.ts:408:16 GET /r2 29 index.ts:5:13 +mw index.ts:66:32 index.ts:408:16 GET /r2 30 index.ts:5:13 +mw index.ts:68:32 index.ts:408:16 GET /r2 31 index.ts:5:13 +mw index.ts:70:32 index.ts:408:16 GET /r2 32 index.ts:5:13 +mw index.ts:72:32 index.ts:408:16 GET /r2 33 index.ts:5:13 +mw index.ts:74:32 index.ts:408:16 GET /r2 34 index.ts:5:13 +mw index.ts:76:32 index.ts:408:16 GET /r2 35 index.ts:5:13 +mw index.ts:78:32 index.ts:408:16 GET /r2 36 index.ts:5:13 +mw index.ts:80:32 index.ts:408:16 GET /r2 37 index.ts:5:13 +mw index.ts:82:32 index.ts:408:16 GET /r2 38 index.ts:5:13 +mw index.ts:84:32 index.ts:408:16 GET /r2 39 index.ts:5:13 +mw index.ts:86:32 index.ts:408:16 GET /r2 40 index.ts:5:13 +mw index.ts:88:32 index.ts:408:16 GET /r2 41 index.ts:5:13 +mw index.ts:90:32 index.ts:408:16 GET /r2 42 index.ts:5:13 +mw index.ts:92:32 index.ts:408:16 GET /r2 43 index.ts:5:13 +mw index.ts:94:32 index.ts:408:16 GET /r2 44 index.ts:5:13 +mw index.ts:96:32 index.ts:408:16 GET /r2 45 index.ts:5:13 +mw index.ts:98:32 index.ts:408:16 GET /r2 46 index.ts:5:13 +mw index.ts:100:32 index.ts:408:16 GET /r2 47 index.ts:5:13 +mw index.ts:102:32 index.ts:408:16 GET /r2 48 index.ts:5:13 +mw index.ts:104:32 index.ts:408:16 GET /r2 49 index.ts:5:13 +mw index.ts:106:32 index.ts:408:16 GET /r2 50 index.ts:5:13 +mw index.ts:108:32 index.ts:408:16 GET /r2 51 index.ts:5:13 +mw index.ts:110:32 index.ts:408:16 GET /r2 52 index.ts:5:13 +mw index.ts:112:32 index.ts:408:16 GET /r2 53 index.ts:5:13 +mw index.ts:114:32 index.ts:408:16 GET /r2 54 index.ts:5:13 +mw index.ts:116:32 index.ts:408:16 GET /r2 55 index.ts:5:13 +mw index.ts:118:32 index.ts:408:16 GET /r2 56 index.ts:5:13 +mw index.ts:120:32 index.ts:408:16 GET /r2 57 index.ts:5:13 +mw index.ts:122:32 index.ts:408:16 GET /r2 58 index.ts:5:13 +mw index.ts:124:32 index.ts:408:16 GET /r2 59 index.ts:5:13 +mw index.ts:126:32 index.ts:408:16 GET /r2 60 index.ts:5:13 +mw index.ts:128:32 index.ts:408:16 GET /r2 61 index.ts:5:13 +mw index.ts:130:32 index.ts:408:16 GET /r2 62 index.ts:5:13 +mw index.ts:132:32 index.ts:408:16 GET /r2 63 index.ts:5:13 +mw index.ts:134:32 index.ts:408:16 GET /r2 64 index.ts:5:13 +mw index.ts:136:32 index.ts:408:16 GET /r2 65 index.ts:5:13 +mw index.ts:138:32 index.ts:408:16 GET /r2 66 index.ts:5:13 +mw index.ts:140:32 index.ts:408:16 GET /r2 67 index.ts:5:13 +mw index.ts:142:32 index.ts:408:16 GET /r2 68 index.ts:5:13 +mw index.ts:144:32 index.ts:408:16 GET /r2 69 index.ts:5:13 +mw index.ts:146:32 index.ts:408:16 GET /r2 70 index.ts:5:13 +mw index.ts:148:32 index.ts:408:16 GET /r2 71 index.ts:5:13 +mw index.ts:150:32 index.ts:408:16 GET /r2 72 index.ts:5:13 +mw index.ts:152:32 index.ts:408:16 GET /r2 73 index.ts:5:13 +mw index.ts:154:32 index.ts:408:16 GET /r2 74 index.ts:5:13 +mw index.ts:156:32 index.ts:408:16 GET /r2 75 index.ts:5:13 +mw index.ts:158:32 index.ts:408:16 GET /r2 76 index.ts:5:13 +mw index.ts:160:32 index.ts:408:16 GET /r2 77 index.ts:5:13 +mw index.ts:162:32 index.ts:408:16 GET /r2 78 index.ts:5:13 +mw index.ts:164:32 index.ts:408:16 GET /r2 79 index.ts:5:13 +mw index.ts:166:32 index.ts:408:16 GET /r2 80 index.ts:5:13 +mw index.ts:168:32 index.ts:408:16 GET /r2 81 index.ts:5:13 +mw index.ts:170:32 index.ts:408:16 GET /r2 82 index.ts:5:13 +mw index.ts:172:32 index.ts:408:16 GET /r2 83 index.ts:5:13 +mw index.ts:174:32 index.ts:408:16 GET /r2 84 index.ts:5:13 +mw index.ts:176:32 index.ts:408:16 GET /r2 85 index.ts:5:13 +mw index.ts:178:32 index.ts:408:16 GET /r2 86 index.ts:5:13 +mw index.ts:180:32 index.ts:408:16 GET /r2 87 index.ts:5:13 +mw index.ts:182:32 index.ts:408:16 GET /r2 88 index.ts:5:13 +mw index.ts:184:32 index.ts:408:16 GET /r2 89 index.ts:5:13 +mw index.ts:186:32 index.ts:408:16 GET /r2 90 index.ts:5:13 +mw index.ts:188:32 index.ts:408:16 GET /r2 91 index.ts:5:13 +mw index.ts:190:32 index.ts:408:16 GET /r2 92 index.ts:5:13 +mw index.ts:192:32 index.ts:408:16 GET /r2 93 index.ts:5:13 +mw index.ts:194:32 index.ts:408:16 GET /r2 94 index.ts:5:13 +mw index.ts:196:32 index.ts:408:16 GET /r2 95 index.ts:5:13 +mw index.ts:198:32 index.ts:408:16 GET /r2 96 index.ts:5:13 +mw index.ts:200:32 index.ts:408:16 GET /r2 97 index.ts:5:13 +mw index.ts:202:32 index.ts:408:16 GET /r2 98 index.ts:5:13 +mw index.ts:204:32 index.ts:408:16 GET /r2 99 index.ts:5:13 +mw index.ts:206:33 index.ts:408:16 GET /r2 100 index.ts:5:13 +mw index.ts:208:33 index.ts:408:16 GET /r2 101 index.ts:5:13 +mw index.ts:210:33 index.ts:408:16 GET /r2 102 index.ts:5:13 +mw index.ts:212:33 index.ts:408:16 GET /r2 103 index.ts:5:13 +mw index.ts:214:33 index.ts:408:16 GET /r2 104 index.ts:5:13 +mw index.ts:216:33 index.ts:408:16 GET /r2 105 index.ts:5:13 +mw index.ts:218:33 index.ts:408:16 GET /r2 106 index.ts:5:13 +mw index.ts:220:33 index.ts:408:16 GET /r2 107 index.ts:5:13 +mw index.ts:222:33 index.ts:408:16 GET /r2 108 index.ts:5:13 +mw index.ts:224:33 index.ts:408:16 GET /r2 109 index.ts:5:13 +mw index.ts:226:33 index.ts:408:16 GET /r2 110 index.ts:5:13 +mw index.ts:228:33 index.ts:408:16 GET /r2 111 index.ts:5:13 +mw index.ts:230:33 index.ts:408:16 GET /r2 112 index.ts:5:13 +mw index.ts:232:33 index.ts:408:16 GET /r2 113 index.ts:5:13 +mw index.ts:234:33 index.ts:408:16 GET /r2 114 index.ts:5:13 +mw index.ts:236:33 index.ts:408:16 GET /r2 115 index.ts:5:13 +mw index.ts:238:33 index.ts:408:16 GET /r2 116 index.ts:5:13 +mw index.ts:240:33 index.ts:408:16 GET /r2 117 index.ts:5:13 +mw index.ts:242:33 index.ts:408:16 GET /r2 118 index.ts:5:13 +mw index.ts:244:33 index.ts:408:16 GET /r2 119 index.ts:5:13 +mw index.ts:246:33 index.ts:408:16 GET /r2 120 index.ts:5:13 +mw index.ts:248:33 index.ts:408:16 GET /r2 121 index.ts:5:13 +mw index.ts:250:33 index.ts:408:16 GET /r2 122 index.ts:5:13 +mw index.ts:252:33 index.ts:408:16 GET /r2 123 index.ts:5:13 +mw index.ts:254:33 index.ts:408:16 GET /r2 124 index.ts:5:13 +mw index.ts:256:33 index.ts:408:16 GET /r2 125 index.ts:5:13 +mw index.ts:258:33 index.ts:408:16 GET /r2 126 index.ts:5:13 +mw index.ts:260:33 index.ts:408:16 GET /r2 127 index.ts:5:13 +mw index.ts:262:33 index.ts:408:16 GET /r2 128 index.ts:5:13 +mw index.ts:264:33 index.ts:408:16 GET /r2 129 index.ts:5:13 +mw index.ts:266:33 index.ts:408:16 GET /r2 130 index.ts:5:13 +mw index.ts:268:33 index.ts:408:16 GET /r2 131 index.ts:5:13 +mw index.ts:270:33 index.ts:408:16 GET /r2 132 index.ts:5:13 +mw index.ts:272:33 index.ts:408:16 GET /r2 133 index.ts:5:13 +mw index.ts:274:33 index.ts:408:16 GET /r2 134 index.ts:5:13 +mw index.ts:276:33 index.ts:408:16 GET /r2 135 index.ts:5:13 +mw index.ts:278:33 index.ts:408:16 GET /r2 136 index.ts:5:13 +mw index.ts:280:33 index.ts:408:16 GET /r2 137 index.ts:5:13 +mw index.ts:282:33 index.ts:408:16 GET /r2 138 index.ts:5:13 +mw index.ts:284:33 index.ts:408:16 GET /r2 139 index.ts:5:13 +mw index.ts:286:33 index.ts:408:16 GET /r2 140 index.ts:5:13 +mw index.ts:288:33 index.ts:408:16 GET /r2 141 index.ts:5:13 +mw index.ts:290:33 index.ts:408:16 GET /r2 142 index.ts:5:13 +mw index.ts:292:33 index.ts:408:16 GET /r2 143 index.ts:5:13 +mw index.ts:294:33 index.ts:408:16 GET /r2 144 index.ts:5:13 +mw index.ts:296:33 index.ts:408:16 GET /r2 145 index.ts:5:13 +mw index.ts:298:33 index.ts:408:16 GET /r2 146 index.ts:5:13 +mw index.ts:300:33 index.ts:408:16 GET /r2 147 index.ts:5:13 +mw index.ts:302:33 index.ts:408:16 GET /r2 148 index.ts:5:13 +mw index.ts:304:33 index.ts:408:16 GET /r2 149 index.ts:5:13 +mw index.ts:306:33 index.ts:408:16 GET /r2 150 index.ts:5:13 +mw index.ts:308:33 index.ts:408:16 GET /r2 151 index.ts:5:13 +mw index.ts:310:33 index.ts:408:16 GET /r2 152 index.ts:5:13 +mw index.ts:312:33 index.ts:408:16 GET /r2 153 index.ts:5:13 +mw index.ts:314:33 index.ts:408:16 GET /r2 154 index.ts:5:13 +mw index.ts:316:33 index.ts:408:16 GET /r2 155 index.ts:5:13 +mw index.ts:318:33 index.ts:408:16 GET /r2 156 index.ts:5:13 +mw index.ts:320:33 index.ts:408:16 GET /r2 157 index.ts:5:13 +mw index.ts:322:33 index.ts:408:16 GET /r2 158 index.ts:5:13 +mw index.ts:324:33 index.ts:408:16 GET /r2 159 index.ts:5:13 +mw index.ts:326:33 index.ts:408:16 GET /r2 160 index.ts:5:13 +mw index.ts:328:33 index.ts:408:16 GET /r2 161 index.ts:5:13 +mw index.ts:330:33 index.ts:408:16 GET /r2 162 index.ts:5:13 +mw index.ts:332:33 index.ts:408:16 GET /r2 163 index.ts:5:13 +mw index.ts:334:33 index.ts:408:16 GET /r2 164 index.ts:5:13 +mw index.ts:336:33 index.ts:408:16 GET /r2 165 index.ts:5:13 +mw index.ts:338:33 index.ts:408:16 GET /r2 166 index.ts:5:13 +mw index.ts:340:33 index.ts:408:16 GET /r2 167 index.ts:5:13 +mw index.ts:342:33 index.ts:408:16 GET /r2 168 index.ts:5:13 +mw index.ts:344:33 index.ts:408:16 GET /r2 169 index.ts:5:13 +mw index.ts:346:33 index.ts:408:16 GET /r2 170 index.ts:5:13 +mw index.ts:348:33 index.ts:408:16 GET /r2 171 index.ts:5:13 +mw index.ts:350:33 index.ts:408:16 GET /r2 172 index.ts:5:13 +mw index.ts:352:33 index.ts:408:16 GET /r2 173 index.ts:5:13 +mw index.ts:354:33 index.ts:408:16 GET /r2 174 index.ts:5:13 +mw index.ts:356:33 index.ts:408:16 GET /r2 175 index.ts:5:13 +mw index.ts:358:33 index.ts:408:16 GET /r2 176 index.ts:5:13 +mw index.ts:360:33 index.ts:408:16 GET /r2 177 index.ts:5:13 +mw index.ts:362:33 index.ts:408:16 GET /r2 178 index.ts:5:13 +mw index.ts:364:33 index.ts:408:16 GET /r2 179 index.ts:5:13 +mw index.ts:366:33 index.ts:408:16 GET /r2 180 index.ts:5:13 +mw index.ts:368:33 index.ts:408:16 GET /r2 181 index.ts:5:13 +mw index.ts:370:33 index.ts:408:16 GET /r2 182 index.ts:5:13 +mw index.ts:372:33 index.ts:408:16 GET /r2 183 index.ts:5:13 +mw index.ts:374:33 index.ts:408:16 GET /r2 184 index.ts:5:13 +mw index.ts:376:33 index.ts:408:16 GET /r2 185 index.ts:5:13 +mw index.ts:378:33 index.ts:408:16 GET /r2 186 index.ts:5:13 +mw index.ts:380:33 index.ts:408:16 GET /r2 187 index.ts:5:13 +mw index.ts:382:33 index.ts:408:16 GET /r2 188 index.ts:5:13 +mw index.ts:384:33 index.ts:408:16 GET /r2 189 index.ts:5:13 +mw index.ts:386:33 index.ts:408:16 GET /r2 190 index.ts:5:13 +mw index.ts:388:33 index.ts:408:16 GET /r2 191 index.ts:5:13 +mw index.ts:390:33 index.ts:408:16 GET /r2 192 index.ts:5:13 +mw index.ts:392:33 index.ts:408:16 GET /r2 193 index.ts:5:13 +mw index.ts:394:33 index.ts:408:16 GET /r2 194 index.ts:5:13 +mw index.ts:396:33 index.ts:408:16 GET /r2 195 index.ts:5:13 +mw index.ts:398:33 index.ts:408:16 GET /r2 196 index.ts:5:13 +mw index.ts:400:33 index.ts:408:16 GET /r2 197 index.ts:5:13 +mw index.ts:402:33 index.ts:408:16 GET /r2 198 index.ts:5:13 +mw index.ts:404:33 index.ts:408:16 GET /r2 199 index.ts:5:13 +mw index.ts:6:31 index.ts:409:16 GET /r3 0 index.ts:5:13 +mw index.ts:8:31 index.ts:409:16 GET /r3 1 index.ts:5:13 +mw index.ts:10:31 index.ts:409:16 GET /r3 2 index.ts:5:13 +mw index.ts:12:31 index.ts:409:16 GET /r3 3 index.ts:5:13 +mw index.ts:14:31 index.ts:409:16 GET /r3 4 index.ts:5:13 +mw index.ts:16:31 index.ts:409:16 GET /r3 5 index.ts:5:13 +mw index.ts:18:31 index.ts:409:16 GET /r3 6 index.ts:5:13 +mw index.ts:20:31 index.ts:409:16 GET /r3 7 index.ts:5:13 +mw index.ts:22:31 index.ts:409:16 GET /r3 8 index.ts:5:13 +mw index.ts:24:31 index.ts:409:16 GET /r3 9 index.ts:5:13 +mw index.ts:26:32 index.ts:409:16 GET /r3 10 index.ts:5:13 +mw index.ts:28:32 index.ts:409:16 GET /r3 11 index.ts:5:13 +mw index.ts:30:32 index.ts:409:16 GET /r3 12 index.ts:5:13 +mw index.ts:32:32 index.ts:409:16 GET /r3 13 index.ts:5:13 +mw index.ts:34:32 index.ts:409:16 GET /r3 14 index.ts:5:13 +mw index.ts:36:32 index.ts:409:16 GET /r3 15 index.ts:5:13 +mw index.ts:38:32 index.ts:409:16 GET /r3 16 index.ts:5:13 +mw index.ts:40:32 index.ts:409:16 GET /r3 17 index.ts:5:13 +mw index.ts:42:32 index.ts:409:16 GET /r3 18 index.ts:5:13 +mw index.ts:44:32 index.ts:409:16 GET /r3 19 index.ts:5:13 +mw index.ts:46:32 index.ts:409:16 GET /r3 20 index.ts:5:13 +mw index.ts:48:32 index.ts:409:16 GET /r3 21 index.ts:5:13 +mw index.ts:50:32 index.ts:409:16 GET /r3 22 index.ts:5:13 +mw index.ts:52:32 index.ts:409:16 GET /r3 23 index.ts:5:13 +mw index.ts:54:32 index.ts:409:16 GET /r3 24 index.ts:5:13 +mw index.ts:56:32 index.ts:409:16 GET /r3 25 index.ts:5:13 +mw index.ts:58:32 index.ts:409:16 GET /r3 26 index.ts:5:13 +mw index.ts:60:32 index.ts:409:16 GET /r3 27 index.ts:5:13 +mw index.ts:62:32 index.ts:409:16 GET /r3 28 index.ts:5:13 +mw index.ts:64:32 index.ts:409:16 GET /r3 29 index.ts:5:13 +mw index.ts:66:32 index.ts:409:16 GET /r3 30 index.ts:5:13 +mw index.ts:68:32 index.ts:409:16 GET /r3 31 index.ts:5:13 +mw index.ts:70:32 index.ts:409:16 GET /r3 32 index.ts:5:13 +mw index.ts:72:32 index.ts:409:16 GET /r3 33 index.ts:5:13 +mw index.ts:74:32 index.ts:409:16 GET /r3 34 index.ts:5:13 +mw index.ts:76:32 index.ts:409:16 GET /r3 35 index.ts:5:13 +mw index.ts:78:32 index.ts:409:16 GET /r3 36 index.ts:5:13 +mw index.ts:80:32 index.ts:409:16 GET /r3 37 index.ts:5:13 +mw index.ts:82:32 index.ts:409:16 GET /r3 38 index.ts:5:13 +mw index.ts:84:32 index.ts:409:16 GET /r3 39 index.ts:5:13 +mw index.ts:86:32 index.ts:409:16 GET /r3 40 index.ts:5:13 +mw index.ts:88:32 index.ts:409:16 GET /r3 41 index.ts:5:13 +mw index.ts:90:32 index.ts:409:16 GET /r3 42 index.ts:5:13 +mw index.ts:92:32 index.ts:409:16 GET /r3 43 index.ts:5:13 +mw index.ts:94:32 index.ts:409:16 GET /r3 44 index.ts:5:13 +mw index.ts:96:32 index.ts:409:16 GET /r3 45 index.ts:5:13 +mw index.ts:98:32 index.ts:409:16 GET /r3 46 index.ts:5:13 +mw index.ts:100:32 index.ts:409:16 GET /r3 47 index.ts:5:13 +mw index.ts:102:32 index.ts:409:16 GET /r3 48 index.ts:5:13 +mw index.ts:104:32 index.ts:409:16 GET /r3 49 index.ts:5:13 +mw index.ts:106:32 index.ts:409:16 GET /r3 50 index.ts:5:13 +mw index.ts:108:32 index.ts:409:16 GET /r3 51 index.ts:5:13 +mw index.ts:110:32 index.ts:409:16 GET /r3 52 index.ts:5:13 +mw index.ts:112:32 index.ts:409:16 GET /r3 53 index.ts:5:13 +mw index.ts:114:32 index.ts:409:16 GET /r3 54 index.ts:5:13 +mw index.ts:116:32 index.ts:409:16 GET /r3 55 index.ts:5:13 +mw index.ts:118:32 index.ts:409:16 GET /r3 56 index.ts:5:13 +mw index.ts:120:32 index.ts:409:16 GET /r3 57 index.ts:5:13 +mw index.ts:122:32 index.ts:409:16 GET /r3 58 index.ts:5:13 +mw index.ts:124:32 index.ts:409:16 GET /r3 59 index.ts:5:13 +mw index.ts:126:32 index.ts:409:16 GET /r3 60 index.ts:5:13 +mw index.ts:128:32 index.ts:409:16 GET /r3 61 index.ts:5:13 +mw index.ts:130:32 index.ts:409:16 GET /r3 62 index.ts:5:13 +mw index.ts:132:32 index.ts:409:16 GET /r3 63 index.ts:5:13 +mw index.ts:134:32 index.ts:409:16 GET /r3 64 index.ts:5:13 +mw index.ts:136:32 index.ts:409:16 GET /r3 65 index.ts:5:13 +mw index.ts:138:32 index.ts:409:16 GET /r3 66 index.ts:5:13 +mw index.ts:140:32 index.ts:409:16 GET /r3 67 index.ts:5:13 +mw index.ts:142:32 index.ts:409:16 GET /r3 68 index.ts:5:13 +mw index.ts:144:32 index.ts:409:16 GET /r3 69 index.ts:5:13 +mw index.ts:146:32 index.ts:409:16 GET /r3 70 index.ts:5:13 +mw index.ts:148:32 index.ts:409:16 GET /r3 71 index.ts:5:13 +mw index.ts:150:32 index.ts:409:16 GET /r3 72 index.ts:5:13 +mw index.ts:152:32 index.ts:409:16 GET /r3 73 index.ts:5:13 +mw index.ts:154:32 index.ts:409:16 GET /r3 74 index.ts:5:13 +mw index.ts:156:32 index.ts:409:16 GET /r3 75 index.ts:5:13 +mw index.ts:158:32 index.ts:409:16 GET /r3 76 index.ts:5:13 +mw index.ts:160:32 index.ts:409:16 GET /r3 77 index.ts:5:13 +mw index.ts:162:32 index.ts:409:16 GET /r3 78 index.ts:5:13 +mw index.ts:164:32 index.ts:409:16 GET /r3 79 index.ts:5:13 +mw index.ts:166:32 index.ts:409:16 GET /r3 80 index.ts:5:13 +mw index.ts:168:32 index.ts:409:16 GET /r3 81 index.ts:5:13 +mw index.ts:170:32 index.ts:409:16 GET /r3 82 index.ts:5:13 +mw index.ts:172:32 index.ts:409:16 GET /r3 83 index.ts:5:13 +mw index.ts:174:32 index.ts:409:16 GET /r3 84 index.ts:5:13 +mw index.ts:176:32 index.ts:409:16 GET /r3 85 index.ts:5:13 +mw index.ts:178:32 index.ts:409:16 GET /r3 86 index.ts:5:13 +mw index.ts:180:32 index.ts:409:16 GET /r3 87 index.ts:5:13 +mw index.ts:182:32 index.ts:409:16 GET /r3 88 index.ts:5:13 +mw index.ts:184:32 index.ts:409:16 GET /r3 89 index.ts:5:13 +mw index.ts:186:32 index.ts:409:16 GET /r3 90 index.ts:5:13 +mw index.ts:188:32 index.ts:409:16 GET /r3 91 index.ts:5:13 +mw index.ts:190:32 index.ts:409:16 GET /r3 92 index.ts:5:13 +mw index.ts:192:32 index.ts:409:16 GET /r3 93 index.ts:5:13 +mw index.ts:194:32 index.ts:409:16 GET /r3 94 index.ts:5:13 +mw index.ts:196:32 index.ts:409:16 GET /r3 95 index.ts:5:13 +mw index.ts:198:32 index.ts:409:16 GET /r3 96 index.ts:5:13 +mw index.ts:200:32 index.ts:409:16 GET /r3 97 index.ts:5:13 +mw index.ts:202:32 index.ts:409:16 GET /r3 98 index.ts:5:13 +mw index.ts:204:32 index.ts:409:16 GET /r3 99 index.ts:5:13 +mw index.ts:206:33 index.ts:409:16 GET /r3 100 index.ts:5:13 +mw index.ts:208:33 index.ts:409:16 GET /r3 101 index.ts:5:13 +mw index.ts:210:33 index.ts:409:16 GET /r3 102 index.ts:5:13 +mw index.ts:212:33 index.ts:409:16 GET /r3 103 index.ts:5:13 +mw index.ts:214:33 index.ts:409:16 GET /r3 104 index.ts:5:13 +mw index.ts:216:33 index.ts:409:16 GET /r3 105 index.ts:5:13 +mw index.ts:218:33 index.ts:409:16 GET /r3 106 index.ts:5:13 +mw index.ts:220:33 index.ts:409:16 GET /r3 107 index.ts:5:13 +mw index.ts:222:33 index.ts:409:16 GET /r3 108 index.ts:5:13 +mw index.ts:224:33 index.ts:409:16 GET /r3 109 index.ts:5:13 +mw index.ts:226:33 index.ts:409:16 GET /r3 110 index.ts:5:13 +mw index.ts:228:33 index.ts:409:16 GET /r3 111 index.ts:5:13 +mw index.ts:230:33 index.ts:409:16 GET /r3 112 index.ts:5:13 +mw index.ts:232:33 index.ts:409:16 GET /r3 113 index.ts:5:13 +mw index.ts:234:33 index.ts:409:16 GET /r3 114 index.ts:5:13 +mw index.ts:236:33 index.ts:409:16 GET /r3 115 index.ts:5:13 +mw index.ts:238:33 index.ts:409:16 GET /r3 116 index.ts:5:13 +mw index.ts:240:33 index.ts:409:16 GET /r3 117 index.ts:5:13 +mw index.ts:242:33 index.ts:409:16 GET /r3 118 index.ts:5:13 +mw index.ts:244:33 index.ts:409:16 GET /r3 119 index.ts:5:13 +mw index.ts:246:33 index.ts:409:16 GET /r3 120 index.ts:5:13 +mw index.ts:248:33 index.ts:409:16 GET /r3 121 index.ts:5:13 +mw index.ts:250:33 index.ts:409:16 GET /r3 122 index.ts:5:13 +mw index.ts:252:33 index.ts:409:16 GET /r3 123 index.ts:5:13 +mw index.ts:254:33 index.ts:409:16 GET /r3 124 index.ts:5:13 +mw index.ts:256:33 index.ts:409:16 GET /r3 125 index.ts:5:13 +mw index.ts:258:33 index.ts:409:16 GET /r3 126 index.ts:5:13 +mw index.ts:260:33 index.ts:409:16 GET /r3 127 index.ts:5:13 +mw index.ts:262:33 index.ts:409:16 GET /r3 128 index.ts:5:13 +mw index.ts:264:33 index.ts:409:16 GET /r3 129 index.ts:5:13 +mw index.ts:266:33 index.ts:409:16 GET /r3 130 index.ts:5:13 +mw index.ts:268:33 index.ts:409:16 GET /r3 131 index.ts:5:13 +mw index.ts:270:33 index.ts:409:16 GET /r3 132 index.ts:5:13 +mw index.ts:272:33 index.ts:409:16 GET /r3 133 index.ts:5:13 +mw index.ts:274:33 index.ts:409:16 GET /r3 134 index.ts:5:13 +mw index.ts:276:33 index.ts:409:16 GET /r3 135 index.ts:5:13 +mw index.ts:278:33 index.ts:409:16 GET /r3 136 index.ts:5:13 +mw index.ts:280:33 index.ts:409:16 GET /r3 137 index.ts:5:13 +mw index.ts:282:33 index.ts:409:16 GET /r3 138 index.ts:5:13 +mw index.ts:284:33 index.ts:409:16 GET /r3 139 index.ts:5:13 +mw index.ts:286:33 index.ts:409:16 GET /r3 140 index.ts:5:13 +mw index.ts:288:33 index.ts:409:16 GET /r3 141 index.ts:5:13 +mw index.ts:290:33 index.ts:409:16 GET /r3 142 index.ts:5:13 +mw index.ts:292:33 index.ts:409:16 GET /r3 143 index.ts:5:13 +mw index.ts:294:33 index.ts:409:16 GET /r3 144 index.ts:5:13 +mw index.ts:296:33 index.ts:409:16 GET /r3 145 index.ts:5:13 +mw index.ts:298:33 index.ts:409:16 GET /r3 146 index.ts:5:13 +mw index.ts:300:33 index.ts:409:16 GET /r3 147 index.ts:5:13 +mw index.ts:302:33 index.ts:409:16 GET /r3 148 index.ts:5:13 +mw index.ts:304:33 index.ts:409:16 GET /r3 149 index.ts:5:13 +mw index.ts:306:33 index.ts:409:16 GET /r3 150 index.ts:5:13 +mw index.ts:308:33 index.ts:409:16 GET /r3 151 index.ts:5:13 +mw index.ts:310:33 index.ts:409:16 GET /r3 152 index.ts:5:13 +mw index.ts:312:33 index.ts:409:16 GET /r3 153 index.ts:5:13 +mw index.ts:314:33 index.ts:409:16 GET /r3 154 index.ts:5:13 +mw index.ts:316:33 index.ts:409:16 GET /r3 155 index.ts:5:13 +mw index.ts:318:33 index.ts:409:16 GET /r3 156 index.ts:5:13 +mw index.ts:320:33 index.ts:409:16 GET /r3 157 index.ts:5:13 +mw index.ts:322:33 index.ts:409:16 GET /r3 158 index.ts:5:13 +mw index.ts:324:33 index.ts:409:16 GET /r3 159 index.ts:5:13 +mw index.ts:326:33 index.ts:409:16 GET /r3 160 index.ts:5:13 +mw index.ts:328:33 index.ts:409:16 GET /r3 161 index.ts:5:13 +mw index.ts:330:33 index.ts:409:16 GET /r3 162 index.ts:5:13 +mw index.ts:332:33 index.ts:409:16 GET /r3 163 index.ts:5:13 +mw index.ts:334:33 index.ts:409:16 GET /r3 164 index.ts:5:13 +mw index.ts:336:33 index.ts:409:16 GET /r3 165 index.ts:5:13 +mw index.ts:338:33 index.ts:409:16 GET /r3 166 index.ts:5:13 +mw index.ts:340:33 index.ts:409:16 GET /r3 167 index.ts:5:13 +mw index.ts:342:33 index.ts:409:16 GET /r3 168 index.ts:5:13 +mw index.ts:344:33 index.ts:409:16 GET /r3 169 index.ts:5:13 +mw index.ts:346:33 index.ts:409:16 GET /r3 170 index.ts:5:13 +mw index.ts:348:33 index.ts:409:16 GET /r3 171 index.ts:5:13 +mw index.ts:350:33 index.ts:409:16 GET /r3 172 index.ts:5:13 +mw index.ts:352:33 index.ts:409:16 GET /r3 173 index.ts:5:13 +mw index.ts:354:33 index.ts:409:16 GET /r3 174 index.ts:5:13 +mw index.ts:356:33 index.ts:409:16 GET /r3 175 index.ts:5:13 +mw index.ts:358:33 index.ts:409:16 GET /r3 176 index.ts:5:13 +mw index.ts:360:33 index.ts:409:16 GET /r3 177 index.ts:5:13 +mw index.ts:362:33 index.ts:409:16 GET /r3 178 index.ts:5:13 +mw index.ts:364:33 index.ts:409:16 GET /r3 179 index.ts:5:13 +mw index.ts:366:33 index.ts:409:16 GET /r3 180 index.ts:5:13 +mw index.ts:368:33 index.ts:409:16 GET /r3 181 index.ts:5:13 +mw index.ts:370:33 index.ts:409:16 GET /r3 182 index.ts:5:13 +mw index.ts:372:33 index.ts:409:16 GET /r3 183 index.ts:5:13 +mw index.ts:374:33 index.ts:409:16 GET /r3 184 index.ts:5:13 +mw index.ts:376:33 index.ts:409:16 GET /r3 185 index.ts:5:13 +mw index.ts:378:33 index.ts:409:16 GET /r3 186 index.ts:5:13 +mw index.ts:380:33 index.ts:409:16 GET /r3 187 index.ts:5:13 +mw index.ts:382:33 index.ts:409:16 GET /r3 188 index.ts:5:13 +mw index.ts:384:33 index.ts:409:16 GET /r3 189 index.ts:5:13 +mw index.ts:386:33 index.ts:409:16 GET /r3 190 index.ts:5:13 +mw index.ts:388:33 index.ts:409:16 GET /r3 191 index.ts:5:13 +mw index.ts:390:33 index.ts:409:16 GET /r3 192 index.ts:5:13 +mw index.ts:392:33 index.ts:409:16 GET /r3 193 index.ts:5:13 +mw index.ts:394:33 index.ts:409:16 GET /r3 194 index.ts:5:13 +mw index.ts:396:33 index.ts:409:16 GET /r3 195 index.ts:5:13 +mw index.ts:398:33 index.ts:409:16 GET /r3 196 index.ts:5:13 +mw index.ts:400:33 index.ts:409:16 GET /r3 197 index.ts:5:13 +mw index.ts:402:33 index.ts:409:16 GET /r3 198 index.ts:5:13 +mw index.ts:404:33 index.ts:409:16 GET /r3 199 index.ts:5:13 +mw index.ts:6:31 index.ts:410:16 GET /r4 0 index.ts:5:13 +mw index.ts:8:31 index.ts:410:16 GET /r4 1 index.ts:5:13 +mw index.ts:10:31 index.ts:410:16 GET /r4 2 index.ts:5:13 +mw index.ts:12:31 index.ts:410:16 GET /r4 3 index.ts:5:13 +mw index.ts:14:31 index.ts:410:16 GET /r4 4 index.ts:5:13 +mw index.ts:16:31 index.ts:410:16 GET /r4 5 index.ts:5:13 +mw index.ts:18:31 index.ts:410:16 GET /r4 6 index.ts:5:13 +mw index.ts:20:31 index.ts:410:16 GET /r4 7 index.ts:5:13 +mw index.ts:22:31 index.ts:410:16 GET /r4 8 index.ts:5:13 +mw index.ts:24:31 index.ts:410:16 GET /r4 9 index.ts:5:13 +mw index.ts:26:32 index.ts:410:16 GET /r4 10 index.ts:5:13 +mw index.ts:28:32 index.ts:410:16 GET /r4 11 index.ts:5:13 +mw index.ts:30:32 index.ts:410:16 GET /r4 12 index.ts:5:13 +mw index.ts:32:32 index.ts:410:16 GET /r4 13 index.ts:5:13 +mw index.ts:34:32 index.ts:410:16 GET /r4 14 index.ts:5:13 +mw index.ts:36:32 index.ts:410:16 GET /r4 15 index.ts:5:13 +mw index.ts:38:32 index.ts:410:16 GET /r4 16 index.ts:5:13 +mw index.ts:40:32 index.ts:410:16 GET /r4 17 index.ts:5:13 +mw index.ts:42:32 index.ts:410:16 GET /r4 18 index.ts:5:13 +mw index.ts:44:32 index.ts:410:16 GET /r4 19 index.ts:5:13 +mw index.ts:46:32 index.ts:410:16 GET /r4 20 index.ts:5:13 +mw index.ts:48:32 index.ts:410:16 GET /r4 21 index.ts:5:13 +mw index.ts:50:32 index.ts:410:16 GET /r4 22 index.ts:5:13 +mw index.ts:52:32 index.ts:410:16 GET /r4 23 index.ts:5:13 +mw index.ts:54:32 index.ts:410:16 GET /r4 24 index.ts:5:13 +mw index.ts:56:32 index.ts:410:16 GET /r4 25 index.ts:5:13 +mw index.ts:58:32 index.ts:410:16 GET /r4 26 index.ts:5:13 +mw index.ts:60:32 index.ts:410:16 GET /r4 27 index.ts:5:13 +mw index.ts:62:32 index.ts:410:16 GET /r4 28 index.ts:5:13 +mw index.ts:64:32 index.ts:410:16 GET /r4 29 index.ts:5:13 +mw index.ts:66:32 index.ts:410:16 GET /r4 30 index.ts:5:13 +mw index.ts:68:32 index.ts:410:16 GET /r4 31 index.ts:5:13 +mw index.ts:70:32 index.ts:410:16 GET /r4 32 index.ts:5:13 +mw index.ts:72:32 index.ts:410:16 GET /r4 33 index.ts:5:13 +mw index.ts:74:32 index.ts:410:16 GET /r4 34 index.ts:5:13 +mw index.ts:76:32 index.ts:410:16 GET /r4 35 index.ts:5:13 +mw index.ts:78:32 index.ts:410:16 GET /r4 36 index.ts:5:13 +mw index.ts:80:32 index.ts:410:16 GET /r4 37 index.ts:5:13 +mw index.ts:82:32 index.ts:410:16 GET /r4 38 index.ts:5:13 +mw index.ts:84:32 index.ts:410:16 GET /r4 39 index.ts:5:13 +mw index.ts:86:32 index.ts:410:16 GET /r4 40 index.ts:5:13 +mw index.ts:88:32 index.ts:410:16 GET /r4 41 index.ts:5:13 +mw index.ts:90:32 index.ts:410:16 GET /r4 42 index.ts:5:13 +mw index.ts:92:32 index.ts:410:16 GET /r4 43 index.ts:5:13 +mw index.ts:94:32 index.ts:410:16 GET /r4 44 index.ts:5:13 +mw index.ts:96:32 index.ts:410:16 GET /r4 45 index.ts:5:13 +mw index.ts:98:32 index.ts:410:16 GET /r4 46 index.ts:5:13 +mw index.ts:100:32 index.ts:410:16 GET /r4 47 index.ts:5:13 +mw index.ts:102:32 index.ts:410:16 GET /r4 48 index.ts:5:13 +mw index.ts:104:32 index.ts:410:16 GET /r4 49 index.ts:5:13 +mw index.ts:106:32 index.ts:410:16 GET /r4 50 index.ts:5:13 +mw index.ts:108:32 index.ts:410:16 GET /r4 51 index.ts:5:13 +mw index.ts:110:32 index.ts:410:16 GET /r4 52 index.ts:5:13 +mw index.ts:112:32 index.ts:410:16 GET /r4 53 index.ts:5:13 +mw index.ts:114:32 index.ts:410:16 GET /r4 54 index.ts:5:13 +mw index.ts:116:32 index.ts:410:16 GET /r4 55 index.ts:5:13 +mw index.ts:118:32 index.ts:410:16 GET /r4 56 index.ts:5:13 +mw index.ts:120:32 index.ts:410:16 GET /r4 57 index.ts:5:13 +mw index.ts:122:32 index.ts:410:16 GET /r4 58 index.ts:5:13 +mw index.ts:124:32 index.ts:410:16 GET /r4 59 index.ts:5:13 +mw index.ts:126:32 index.ts:410:16 GET /r4 60 index.ts:5:13 +mw index.ts:128:32 index.ts:410:16 GET /r4 61 index.ts:5:13 +mw index.ts:130:32 index.ts:410:16 GET /r4 62 index.ts:5:13 +mw index.ts:132:32 index.ts:410:16 GET /r4 63 index.ts:5:13 +mw index.ts:134:32 index.ts:410:16 GET /r4 64 index.ts:5:13 +mw index.ts:136:32 index.ts:410:16 GET /r4 65 index.ts:5:13 +mw index.ts:138:32 index.ts:410:16 GET /r4 66 index.ts:5:13 +mw index.ts:140:32 index.ts:410:16 GET /r4 67 index.ts:5:13 +mw index.ts:142:32 index.ts:410:16 GET /r4 68 index.ts:5:13 +mw index.ts:144:32 index.ts:410:16 GET /r4 69 index.ts:5:13 +mw index.ts:146:32 index.ts:410:16 GET /r4 70 index.ts:5:13 +mw index.ts:148:32 index.ts:410:16 GET /r4 71 index.ts:5:13 +mw index.ts:150:32 index.ts:410:16 GET /r4 72 index.ts:5:13 +mw index.ts:152:32 index.ts:410:16 GET /r4 73 index.ts:5:13 +mw index.ts:154:32 index.ts:410:16 GET /r4 74 index.ts:5:13 +mw index.ts:156:32 index.ts:410:16 GET /r4 75 index.ts:5:13 +mw index.ts:158:32 index.ts:410:16 GET /r4 76 index.ts:5:13 +mw index.ts:160:32 index.ts:410:16 GET /r4 77 index.ts:5:13 +mw index.ts:162:32 index.ts:410:16 GET /r4 78 index.ts:5:13 +mw index.ts:164:32 index.ts:410:16 GET /r4 79 index.ts:5:13 +mw index.ts:166:32 index.ts:410:16 GET /r4 80 index.ts:5:13 +mw index.ts:168:32 index.ts:410:16 GET /r4 81 index.ts:5:13 +mw index.ts:170:32 index.ts:410:16 GET /r4 82 index.ts:5:13 +mw index.ts:172:32 index.ts:410:16 GET /r4 83 index.ts:5:13 +mw index.ts:174:32 index.ts:410:16 GET /r4 84 index.ts:5:13 +mw index.ts:176:32 index.ts:410:16 GET /r4 85 index.ts:5:13 +mw index.ts:178:32 index.ts:410:16 GET /r4 86 index.ts:5:13 +mw index.ts:180:32 index.ts:410:16 GET /r4 87 index.ts:5:13 +mw index.ts:182:32 index.ts:410:16 GET /r4 88 index.ts:5:13 +mw index.ts:184:32 index.ts:410:16 GET /r4 89 index.ts:5:13 +mw index.ts:186:32 index.ts:410:16 GET /r4 90 index.ts:5:13 +mw index.ts:188:32 index.ts:410:16 GET /r4 91 index.ts:5:13 +mw index.ts:190:32 index.ts:410:16 GET /r4 92 index.ts:5:13 +mw index.ts:192:32 index.ts:410:16 GET /r4 93 index.ts:5:13 +mw index.ts:194:32 index.ts:410:16 GET /r4 94 index.ts:5:13 +mw index.ts:196:32 index.ts:410:16 GET /r4 95 index.ts:5:13 +mw index.ts:198:32 index.ts:410:16 GET /r4 96 index.ts:5:13 +mw index.ts:200:32 index.ts:410:16 GET /r4 97 index.ts:5:13 +mw index.ts:202:32 index.ts:410:16 GET /r4 98 index.ts:5:13 +mw index.ts:204:32 index.ts:410:16 GET /r4 99 index.ts:5:13 +mw index.ts:206:33 index.ts:410:16 GET /r4 100 index.ts:5:13 +mw index.ts:208:33 index.ts:410:16 GET /r4 101 index.ts:5:13 +mw index.ts:210:33 index.ts:410:16 GET /r4 102 index.ts:5:13 +mw index.ts:212:33 index.ts:410:16 GET /r4 103 index.ts:5:13 +mw index.ts:214:33 index.ts:410:16 GET /r4 104 index.ts:5:13 +mw index.ts:216:33 index.ts:410:16 GET /r4 105 index.ts:5:13 +mw index.ts:218:33 index.ts:410:16 GET /r4 106 index.ts:5:13 +mw index.ts:220:33 index.ts:410:16 GET /r4 107 index.ts:5:13 +mw index.ts:222:33 index.ts:410:16 GET /r4 108 index.ts:5:13 +mw index.ts:224:33 index.ts:410:16 GET /r4 109 index.ts:5:13 +mw index.ts:226:33 index.ts:410:16 GET /r4 110 index.ts:5:13 +mw index.ts:228:33 index.ts:410:16 GET /r4 111 index.ts:5:13 +mw index.ts:230:33 index.ts:410:16 GET /r4 112 index.ts:5:13 +mw index.ts:232:33 index.ts:410:16 GET /r4 113 index.ts:5:13 +mw index.ts:234:33 index.ts:410:16 GET /r4 114 index.ts:5:13 +mw index.ts:236:33 index.ts:410:16 GET /r4 115 index.ts:5:13 +mw index.ts:238:33 index.ts:410:16 GET /r4 116 index.ts:5:13 +mw index.ts:240:33 index.ts:410:16 GET /r4 117 index.ts:5:13 +mw index.ts:242:33 index.ts:410:16 GET /r4 118 index.ts:5:13 +mw index.ts:244:33 index.ts:410:16 GET /r4 119 index.ts:5:13 +mw index.ts:246:33 index.ts:410:16 GET /r4 120 index.ts:5:13 +mw index.ts:248:33 index.ts:410:16 GET /r4 121 index.ts:5:13 +mw index.ts:250:33 index.ts:410:16 GET /r4 122 index.ts:5:13 +mw index.ts:252:33 index.ts:410:16 GET /r4 123 index.ts:5:13 +mw index.ts:254:33 index.ts:410:16 GET /r4 124 index.ts:5:13 +mw index.ts:256:33 index.ts:410:16 GET /r4 125 index.ts:5:13 +mw index.ts:258:33 index.ts:410:16 GET /r4 126 index.ts:5:13 +mw index.ts:260:33 index.ts:410:16 GET /r4 127 index.ts:5:13 +mw index.ts:262:33 index.ts:410:16 GET /r4 128 index.ts:5:13 +mw index.ts:264:33 index.ts:410:16 GET /r4 129 index.ts:5:13 +mw index.ts:266:33 index.ts:410:16 GET /r4 130 index.ts:5:13 +mw index.ts:268:33 index.ts:410:16 GET /r4 131 index.ts:5:13 +mw index.ts:270:33 index.ts:410:16 GET /r4 132 index.ts:5:13 +mw index.ts:272:33 index.ts:410:16 GET /r4 133 index.ts:5:13 +mw index.ts:274:33 index.ts:410:16 GET /r4 134 index.ts:5:13 +mw index.ts:276:33 index.ts:410:16 GET /r4 135 index.ts:5:13 +mw index.ts:278:33 index.ts:410:16 GET /r4 136 index.ts:5:13 +mw index.ts:280:33 index.ts:410:16 GET /r4 137 index.ts:5:13 +mw index.ts:282:33 index.ts:410:16 GET /r4 138 index.ts:5:13 +mw index.ts:284:33 index.ts:410:16 GET /r4 139 index.ts:5:13 +mw index.ts:286:33 index.ts:410:16 GET /r4 140 index.ts:5:13 +mw index.ts:288:33 index.ts:410:16 GET /r4 141 index.ts:5:13 +mw index.ts:290:33 index.ts:410:16 GET /r4 142 index.ts:5:13 +mw index.ts:292:33 index.ts:410:16 GET /r4 143 index.ts:5:13 +mw index.ts:294:33 index.ts:410:16 GET /r4 144 index.ts:5:13 +mw index.ts:296:33 index.ts:410:16 GET /r4 145 index.ts:5:13 +mw index.ts:298:33 index.ts:410:16 GET /r4 146 index.ts:5:13 +mw index.ts:300:33 index.ts:410:16 GET /r4 147 index.ts:5:13 +mw index.ts:302:33 index.ts:410:16 GET /r4 148 index.ts:5:13 +mw index.ts:304:33 index.ts:410:16 GET /r4 149 index.ts:5:13 +mw index.ts:306:33 index.ts:410:16 GET /r4 150 index.ts:5:13 +mw index.ts:308:33 index.ts:410:16 GET /r4 151 index.ts:5:13 +mw index.ts:310:33 index.ts:410:16 GET /r4 152 index.ts:5:13 +mw index.ts:312:33 index.ts:410:16 GET /r4 153 index.ts:5:13 +mw index.ts:314:33 index.ts:410:16 GET /r4 154 index.ts:5:13 +mw index.ts:316:33 index.ts:410:16 GET /r4 155 index.ts:5:13 +mw index.ts:318:33 index.ts:410:16 GET /r4 156 index.ts:5:13 +mw index.ts:320:33 index.ts:410:16 GET /r4 157 index.ts:5:13 +mw index.ts:322:33 index.ts:410:16 GET /r4 158 index.ts:5:13 +mw index.ts:324:33 index.ts:410:16 GET /r4 159 index.ts:5:13 +mw index.ts:326:33 index.ts:410:16 GET /r4 160 index.ts:5:13 +mw index.ts:328:33 index.ts:410:16 GET /r4 161 index.ts:5:13 +mw index.ts:330:33 index.ts:410:16 GET /r4 162 index.ts:5:13 +mw index.ts:332:33 index.ts:410:16 GET /r4 163 index.ts:5:13 +mw index.ts:334:33 index.ts:410:16 GET /r4 164 index.ts:5:13 +mw index.ts:336:33 index.ts:410:16 GET /r4 165 index.ts:5:13 +mw index.ts:338:33 index.ts:410:16 GET /r4 166 index.ts:5:13 +mw index.ts:340:33 index.ts:410:16 GET /r4 167 index.ts:5:13 +mw index.ts:342:33 index.ts:410:16 GET /r4 168 index.ts:5:13 +mw index.ts:344:33 index.ts:410:16 GET /r4 169 index.ts:5:13 +mw index.ts:346:33 index.ts:410:16 GET /r4 170 index.ts:5:13 +mw index.ts:348:33 index.ts:410:16 GET /r4 171 index.ts:5:13 +mw index.ts:350:33 index.ts:410:16 GET /r4 172 index.ts:5:13 +mw index.ts:352:33 index.ts:410:16 GET /r4 173 index.ts:5:13 +mw index.ts:354:33 index.ts:410:16 GET /r4 174 index.ts:5:13 +mw index.ts:356:33 index.ts:410:16 GET /r4 175 index.ts:5:13 +mw index.ts:358:33 index.ts:410:16 GET /r4 176 index.ts:5:13 +mw index.ts:360:33 index.ts:410:16 GET /r4 177 index.ts:5:13 +mw index.ts:362:33 index.ts:410:16 GET /r4 178 index.ts:5:13 +mw index.ts:364:33 index.ts:410:16 GET /r4 179 index.ts:5:13 +mw index.ts:366:33 index.ts:410:16 GET /r4 180 index.ts:5:13 +mw index.ts:368:33 index.ts:410:16 GET /r4 181 index.ts:5:13 +mw index.ts:370:33 index.ts:410:16 GET /r4 182 index.ts:5:13 +mw index.ts:372:33 index.ts:410:16 GET /r4 183 index.ts:5:13 +mw index.ts:374:33 index.ts:410:16 GET /r4 184 index.ts:5:13 +mw index.ts:376:33 index.ts:410:16 GET /r4 185 index.ts:5:13 +mw index.ts:378:33 index.ts:410:16 GET /r4 186 index.ts:5:13 +mw index.ts:380:33 index.ts:410:16 GET /r4 187 index.ts:5:13 +mw index.ts:382:33 index.ts:410:16 GET /r4 188 index.ts:5:13 +mw index.ts:384:33 index.ts:410:16 GET /r4 189 index.ts:5:13 +mw index.ts:386:33 index.ts:410:16 GET /r4 190 index.ts:5:13 +mw index.ts:388:33 index.ts:410:16 GET /r4 191 index.ts:5:13 +mw index.ts:390:33 index.ts:410:16 GET /r4 192 index.ts:5:13 +mw index.ts:392:33 index.ts:410:16 GET /r4 193 index.ts:5:13 +mw index.ts:394:33 index.ts:410:16 GET /r4 194 index.ts:5:13 +mw index.ts:396:33 index.ts:410:16 GET /r4 195 index.ts:5:13 +mw index.ts:398:33 index.ts:410:16 GET /r4 196 index.ts:5:13 +mw index.ts:400:33 index.ts:410:16 GET /r4 197 index.ts:5:13 +mw index.ts:402:33 index.ts:410:16 GET /r4 198 index.ts:5:13 +mw index.ts:404:33 index.ts:410:16 GET /r4 199 index.ts:5:13 +mw index.ts:6:31 index.ts:411:16 GET /r5 0 index.ts:5:13 +mw index.ts:8:31 index.ts:411:16 GET /r5 1 index.ts:5:13 +mw index.ts:10:31 index.ts:411:16 GET /r5 2 index.ts:5:13 +mw index.ts:12:31 index.ts:411:16 GET /r5 3 index.ts:5:13 +mw index.ts:14:31 index.ts:411:16 GET /r5 4 index.ts:5:13 +mw index.ts:16:31 index.ts:411:16 GET /r5 5 index.ts:5:13 +mw index.ts:18:31 index.ts:411:16 GET /r5 6 index.ts:5:13 +mw index.ts:20:31 index.ts:411:16 GET /r5 7 index.ts:5:13 +mw index.ts:22:31 index.ts:411:16 GET /r5 8 index.ts:5:13 +mw index.ts:24:31 index.ts:411:16 GET /r5 9 index.ts:5:13 +mw index.ts:26:32 index.ts:411:16 GET /r5 10 index.ts:5:13 +mw index.ts:28:32 index.ts:411:16 GET /r5 11 index.ts:5:13 +mw index.ts:30:32 index.ts:411:16 GET /r5 12 index.ts:5:13 +mw index.ts:32:32 index.ts:411:16 GET /r5 13 index.ts:5:13 +mw index.ts:34:32 index.ts:411:16 GET /r5 14 index.ts:5:13 +mw index.ts:36:32 index.ts:411:16 GET /r5 15 index.ts:5:13 +mw index.ts:38:32 index.ts:411:16 GET /r5 16 index.ts:5:13 +mw index.ts:40:32 index.ts:411:16 GET /r5 17 index.ts:5:13 +mw index.ts:42:32 index.ts:411:16 GET /r5 18 index.ts:5:13 +mw index.ts:44:32 index.ts:411:16 GET /r5 19 index.ts:5:13 +mw index.ts:46:32 index.ts:411:16 GET /r5 20 index.ts:5:13 +mw index.ts:48:32 index.ts:411:16 GET /r5 21 index.ts:5:13 +mw index.ts:50:32 index.ts:411:16 GET /r5 22 index.ts:5:13 +mw index.ts:52:32 index.ts:411:16 GET /r5 23 index.ts:5:13 +mw index.ts:54:32 index.ts:411:16 GET /r5 24 index.ts:5:13 +mw index.ts:56:32 index.ts:411:16 GET /r5 25 index.ts:5:13 +mw index.ts:58:32 index.ts:411:16 GET /r5 26 index.ts:5:13 +mw index.ts:60:32 index.ts:411:16 GET /r5 27 index.ts:5:13 +mw index.ts:62:32 index.ts:411:16 GET /r5 28 index.ts:5:13 +mw index.ts:64:32 index.ts:411:16 GET /r5 29 index.ts:5:13 +mw index.ts:66:32 index.ts:411:16 GET /r5 30 index.ts:5:13 +mw index.ts:68:32 index.ts:411:16 GET /r5 31 index.ts:5:13 +mw index.ts:70:32 index.ts:411:16 GET /r5 32 index.ts:5:13 +mw index.ts:72:32 index.ts:411:16 GET /r5 33 index.ts:5:13 +mw index.ts:74:32 index.ts:411:16 GET /r5 34 index.ts:5:13 +mw index.ts:76:32 index.ts:411:16 GET /r5 35 index.ts:5:13 +mw index.ts:78:32 index.ts:411:16 GET /r5 36 index.ts:5:13 +mw index.ts:80:32 index.ts:411:16 GET /r5 37 index.ts:5:13 +mw index.ts:82:32 index.ts:411:16 GET /r5 38 index.ts:5:13 +mw index.ts:84:32 index.ts:411:16 GET /r5 39 index.ts:5:13 +mw index.ts:86:32 index.ts:411:16 GET /r5 40 index.ts:5:13 +mw index.ts:88:32 index.ts:411:16 GET /r5 41 index.ts:5:13 +mw index.ts:90:32 index.ts:411:16 GET /r5 42 index.ts:5:13 +mw index.ts:92:32 index.ts:411:16 GET /r5 43 index.ts:5:13 +mw index.ts:94:32 index.ts:411:16 GET /r5 44 index.ts:5:13 +mw index.ts:96:32 index.ts:411:16 GET /r5 45 index.ts:5:13 +mw index.ts:98:32 index.ts:411:16 GET /r5 46 index.ts:5:13 +mw index.ts:100:32 index.ts:411:16 GET /r5 47 index.ts:5:13 +mw index.ts:102:32 index.ts:411:16 GET /r5 48 index.ts:5:13 +mw index.ts:104:32 index.ts:411:16 GET /r5 49 index.ts:5:13 +mw index.ts:106:32 index.ts:411:16 GET /r5 50 index.ts:5:13 +mw index.ts:108:32 index.ts:411:16 GET /r5 51 index.ts:5:13 +mw index.ts:110:32 index.ts:411:16 GET /r5 52 index.ts:5:13 +mw index.ts:112:32 index.ts:411:16 GET /r5 53 index.ts:5:13 +mw index.ts:114:32 index.ts:411:16 GET /r5 54 index.ts:5:13 +mw index.ts:116:32 index.ts:411:16 GET /r5 55 index.ts:5:13 +mw index.ts:118:32 index.ts:411:16 GET /r5 56 index.ts:5:13 +mw index.ts:120:32 index.ts:411:16 GET /r5 57 index.ts:5:13 +mw index.ts:122:32 index.ts:411:16 GET /r5 58 index.ts:5:13 +mw index.ts:124:32 index.ts:411:16 GET /r5 59 index.ts:5:13 +mw index.ts:126:32 index.ts:411:16 GET /r5 60 index.ts:5:13 +mw index.ts:128:32 index.ts:411:16 GET /r5 61 index.ts:5:13 +mw index.ts:130:32 index.ts:411:16 GET /r5 62 index.ts:5:13 +mw index.ts:132:32 index.ts:411:16 GET /r5 63 index.ts:5:13 +mw index.ts:134:32 index.ts:411:16 GET /r5 64 index.ts:5:13 +mw index.ts:136:32 index.ts:411:16 GET /r5 65 index.ts:5:13 +mw index.ts:138:32 index.ts:411:16 GET /r5 66 index.ts:5:13 +mw index.ts:140:32 index.ts:411:16 GET /r5 67 index.ts:5:13 +mw index.ts:142:32 index.ts:411:16 GET /r5 68 index.ts:5:13 +mw index.ts:144:32 index.ts:411:16 GET /r5 69 index.ts:5:13 +mw index.ts:146:32 index.ts:411:16 GET /r5 70 index.ts:5:13 +mw index.ts:148:32 index.ts:411:16 GET /r5 71 index.ts:5:13 +mw index.ts:150:32 index.ts:411:16 GET /r5 72 index.ts:5:13 +mw index.ts:152:32 index.ts:411:16 GET /r5 73 index.ts:5:13 +mw index.ts:154:32 index.ts:411:16 GET /r5 74 index.ts:5:13 +mw index.ts:156:32 index.ts:411:16 GET /r5 75 index.ts:5:13 +mw index.ts:158:32 index.ts:411:16 GET /r5 76 index.ts:5:13 +mw index.ts:160:32 index.ts:411:16 GET /r5 77 index.ts:5:13 +mw index.ts:162:32 index.ts:411:16 GET /r5 78 index.ts:5:13 +mw index.ts:164:32 index.ts:411:16 GET /r5 79 index.ts:5:13 +mw index.ts:166:32 index.ts:411:16 GET /r5 80 index.ts:5:13 +mw index.ts:168:32 index.ts:411:16 GET /r5 81 index.ts:5:13 +mw index.ts:170:32 index.ts:411:16 GET /r5 82 index.ts:5:13 +mw index.ts:172:32 index.ts:411:16 GET /r5 83 index.ts:5:13 +mw index.ts:174:32 index.ts:411:16 GET /r5 84 index.ts:5:13 +mw index.ts:176:32 index.ts:411:16 GET /r5 85 index.ts:5:13 +mw index.ts:178:32 index.ts:411:16 GET /r5 86 index.ts:5:13 +mw index.ts:180:32 index.ts:411:16 GET /r5 87 index.ts:5:13 +mw index.ts:182:32 index.ts:411:16 GET /r5 88 index.ts:5:13 +mw index.ts:184:32 index.ts:411:16 GET /r5 89 index.ts:5:13 +mw index.ts:186:32 index.ts:411:16 GET /r5 90 index.ts:5:13 +mw index.ts:188:32 index.ts:411:16 GET /r5 91 index.ts:5:13 +mw index.ts:190:32 index.ts:411:16 GET /r5 92 index.ts:5:13 +mw index.ts:192:32 index.ts:411:16 GET /r5 93 index.ts:5:13 +mw index.ts:194:32 index.ts:411:16 GET /r5 94 index.ts:5:13 +mw index.ts:196:32 index.ts:411:16 GET /r5 95 index.ts:5:13 +mw index.ts:198:32 index.ts:411:16 GET /r5 96 index.ts:5:13 +mw index.ts:200:32 index.ts:411:16 GET /r5 97 index.ts:5:13 +mw index.ts:202:32 index.ts:411:16 GET /r5 98 index.ts:5:13 +mw index.ts:204:32 index.ts:411:16 GET /r5 99 index.ts:5:13 +mw index.ts:206:33 index.ts:411:16 GET /r5 100 index.ts:5:13 +mw index.ts:208:33 index.ts:411:16 GET /r5 101 index.ts:5:13 +mw index.ts:210:33 index.ts:411:16 GET /r5 102 index.ts:5:13 +mw index.ts:212:33 index.ts:411:16 GET /r5 103 index.ts:5:13 +mw index.ts:214:33 index.ts:411:16 GET /r5 104 index.ts:5:13 +mw index.ts:216:33 index.ts:411:16 GET /r5 105 index.ts:5:13 +mw index.ts:218:33 index.ts:411:16 GET /r5 106 index.ts:5:13 +mw index.ts:220:33 index.ts:411:16 GET /r5 107 index.ts:5:13 +mw index.ts:222:33 index.ts:411:16 GET /r5 108 index.ts:5:13 +mw index.ts:224:33 index.ts:411:16 GET /r5 109 index.ts:5:13 +mw index.ts:226:33 index.ts:411:16 GET /r5 110 index.ts:5:13 +mw index.ts:228:33 index.ts:411:16 GET /r5 111 index.ts:5:13 +mw index.ts:230:33 index.ts:411:16 GET /r5 112 index.ts:5:13 +mw index.ts:232:33 index.ts:411:16 GET /r5 113 index.ts:5:13 +mw index.ts:234:33 index.ts:411:16 GET /r5 114 index.ts:5:13 +mw index.ts:236:33 index.ts:411:16 GET /r5 115 index.ts:5:13 +mw index.ts:238:33 index.ts:411:16 GET /r5 116 index.ts:5:13 +mw index.ts:240:33 index.ts:411:16 GET /r5 117 index.ts:5:13 +mw index.ts:242:33 index.ts:411:16 GET /r5 118 index.ts:5:13 +mw index.ts:244:33 index.ts:411:16 GET /r5 119 index.ts:5:13 +mw index.ts:246:33 index.ts:411:16 GET /r5 120 index.ts:5:13 +mw index.ts:248:33 index.ts:411:16 GET /r5 121 index.ts:5:13 +mw index.ts:250:33 index.ts:411:16 GET /r5 122 index.ts:5:13 +mw index.ts:252:33 index.ts:411:16 GET /r5 123 index.ts:5:13 +mw index.ts:254:33 index.ts:411:16 GET /r5 124 index.ts:5:13 +mw index.ts:256:33 index.ts:411:16 GET /r5 125 index.ts:5:13 +mw index.ts:258:33 index.ts:411:16 GET /r5 126 index.ts:5:13 +mw index.ts:260:33 index.ts:411:16 GET /r5 127 index.ts:5:13 +mw index.ts:262:33 index.ts:411:16 GET /r5 128 index.ts:5:13 +mw index.ts:264:33 index.ts:411:16 GET /r5 129 index.ts:5:13 +mw index.ts:266:33 index.ts:411:16 GET /r5 130 index.ts:5:13 +mw index.ts:268:33 index.ts:411:16 GET /r5 131 index.ts:5:13 +mw index.ts:270:33 index.ts:411:16 GET /r5 132 index.ts:5:13 +mw index.ts:272:33 index.ts:411:16 GET /r5 133 index.ts:5:13 +mw index.ts:274:33 index.ts:411:16 GET /r5 134 index.ts:5:13 +mw index.ts:276:33 index.ts:411:16 GET /r5 135 index.ts:5:13 +mw index.ts:278:33 index.ts:411:16 GET /r5 136 index.ts:5:13 +mw index.ts:280:33 index.ts:411:16 GET /r5 137 index.ts:5:13 +mw index.ts:282:33 index.ts:411:16 GET /r5 138 index.ts:5:13 +mw index.ts:284:33 index.ts:411:16 GET /r5 139 index.ts:5:13 +mw index.ts:286:33 index.ts:411:16 GET /r5 140 index.ts:5:13 +mw index.ts:288:33 index.ts:411:16 GET /r5 141 index.ts:5:13 +mw index.ts:290:33 index.ts:411:16 GET /r5 142 index.ts:5:13 +mw index.ts:292:33 index.ts:411:16 GET /r5 143 index.ts:5:13 +mw index.ts:294:33 index.ts:411:16 GET /r5 144 index.ts:5:13 +mw index.ts:296:33 index.ts:411:16 GET /r5 145 index.ts:5:13 +mw index.ts:298:33 index.ts:411:16 GET /r5 146 index.ts:5:13 +mw index.ts:300:33 index.ts:411:16 GET /r5 147 index.ts:5:13 +mw index.ts:302:33 index.ts:411:16 GET /r5 148 index.ts:5:13 +mw index.ts:304:33 index.ts:411:16 GET /r5 149 index.ts:5:13 +mw index.ts:306:33 index.ts:411:16 GET /r5 150 index.ts:5:13 +mw index.ts:308:33 index.ts:411:16 GET /r5 151 index.ts:5:13 +mw index.ts:310:33 index.ts:411:16 GET /r5 152 index.ts:5:13 +mw index.ts:312:33 index.ts:411:16 GET /r5 153 index.ts:5:13 +mw index.ts:314:33 index.ts:411:16 GET /r5 154 index.ts:5:13 +mw index.ts:316:33 index.ts:411:16 GET /r5 155 index.ts:5:13 +mw index.ts:318:33 index.ts:411:16 GET /r5 156 index.ts:5:13 +mw index.ts:320:33 index.ts:411:16 GET /r5 157 index.ts:5:13 +mw index.ts:322:33 index.ts:411:16 GET /r5 158 index.ts:5:13 +mw index.ts:324:33 index.ts:411:16 GET /r5 159 index.ts:5:13 +mw index.ts:326:33 index.ts:411:16 GET /r5 160 index.ts:5:13 +mw index.ts:328:33 index.ts:411:16 GET /r5 161 index.ts:5:13 +mw index.ts:330:33 index.ts:411:16 GET /r5 162 index.ts:5:13 +mw index.ts:332:33 index.ts:411:16 GET /r5 163 index.ts:5:13 +mw index.ts:334:33 index.ts:411:16 GET /r5 164 index.ts:5:13 +mw index.ts:336:33 index.ts:411:16 GET /r5 165 index.ts:5:13 +mw index.ts:338:33 index.ts:411:16 GET /r5 166 index.ts:5:13 +mw index.ts:340:33 index.ts:411:16 GET /r5 167 index.ts:5:13 +mw index.ts:342:33 index.ts:411:16 GET /r5 168 index.ts:5:13 +mw index.ts:344:33 index.ts:411:16 GET /r5 169 index.ts:5:13 +mw index.ts:346:33 index.ts:411:16 GET /r5 170 index.ts:5:13 +mw index.ts:348:33 index.ts:411:16 GET /r5 171 index.ts:5:13 +mw index.ts:350:33 index.ts:411:16 GET /r5 172 index.ts:5:13 +mw index.ts:352:33 index.ts:411:16 GET /r5 173 index.ts:5:13 +mw index.ts:354:33 index.ts:411:16 GET /r5 174 index.ts:5:13 +mw index.ts:356:33 index.ts:411:16 GET /r5 175 index.ts:5:13 +mw index.ts:358:33 index.ts:411:16 GET /r5 176 index.ts:5:13 +mw index.ts:360:33 index.ts:411:16 GET /r5 177 index.ts:5:13 +mw index.ts:362:33 index.ts:411:16 GET /r5 178 index.ts:5:13 +mw index.ts:364:33 index.ts:411:16 GET /r5 179 index.ts:5:13 +mw index.ts:366:33 index.ts:411:16 GET /r5 180 index.ts:5:13 +mw index.ts:368:33 index.ts:411:16 GET /r5 181 index.ts:5:13 +mw index.ts:370:33 index.ts:411:16 GET /r5 182 index.ts:5:13 +mw index.ts:372:33 index.ts:411:16 GET /r5 183 index.ts:5:13 +mw index.ts:374:33 index.ts:411:16 GET /r5 184 index.ts:5:13 +mw index.ts:376:33 index.ts:411:16 GET /r5 185 index.ts:5:13 +mw index.ts:378:33 index.ts:411:16 GET /r5 186 index.ts:5:13 +mw index.ts:380:33 index.ts:411:16 GET /r5 187 index.ts:5:13 +mw index.ts:382:33 index.ts:411:16 GET /r5 188 index.ts:5:13 +mw index.ts:384:33 index.ts:411:16 GET /r5 189 index.ts:5:13 +mw index.ts:386:33 index.ts:411:16 GET /r5 190 index.ts:5:13 +mw index.ts:388:33 index.ts:411:16 GET /r5 191 index.ts:5:13 +mw index.ts:390:33 index.ts:411:16 GET /r5 192 index.ts:5:13 +mw index.ts:392:33 index.ts:411:16 GET /r5 193 index.ts:5:13 +mw index.ts:394:33 index.ts:411:16 GET /r5 194 index.ts:5:13 +mw index.ts:396:33 index.ts:411:16 GET /r5 195 index.ts:5:13 +mw index.ts:398:33 index.ts:411:16 GET /r5 196 index.ts:5:13 +mw index.ts:400:33 index.ts:411:16 GET /r5 197 index.ts:5:13 +mw index.ts:402:33 index.ts:411:16 GET /r5 198 index.ts:5:13 +mw index.ts:404:33 index.ts:411:16 GET /r5 199 index.ts:5:13 +mw index.ts:6:31 index.ts:412:16 GET /r6 0 index.ts:5:13 +mw index.ts:8:31 index.ts:412:16 GET /r6 1 index.ts:5:13 +mw index.ts:10:31 index.ts:412:16 GET /r6 2 index.ts:5:13 +mw index.ts:12:31 index.ts:412:16 GET /r6 3 index.ts:5:13 +mw index.ts:14:31 index.ts:412:16 GET /r6 4 index.ts:5:13 +mw index.ts:16:31 index.ts:412:16 GET /r6 5 index.ts:5:13 +mw index.ts:18:31 index.ts:412:16 GET /r6 6 index.ts:5:13 +mw index.ts:20:31 index.ts:412:16 GET /r6 7 index.ts:5:13 +mw index.ts:22:31 index.ts:412:16 GET /r6 8 index.ts:5:13 +mw index.ts:24:31 index.ts:412:16 GET /r6 9 index.ts:5:13 +mw index.ts:26:32 index.ts:412:16 GET /r6 10 index.ts:5:13 +mw index.ts:28:32 index.ts:412:16 GET /r6 11 index.ts:5:13 +mw index.ts:30:32 index.ts:412:16 GET /r6 12 index.ts:5:13 +mw index.ts:32:32 index.ts:412:16 GET /r6 13 index.ts:5:13 +mw index.ts:34:32 index.ts:412:16 GET /r6 14 index.ts:5:13 +mw index.ts:36:32 index.ts:412:16 GET /r6 15 index.ts:5:13 +mw index.ts:38:32 index.ts:412:16 GET /r6 16 index.ts:5:13 +mw index.ts:40:32 index.ts:412:16 GET /r6 17 index.ts:5:13 +mw index.ts:42:32 index.ts:412:16 GET /r6 18 index.ts:5:13 +mw index.ts:44:32 index.ts:412:16 GET /r6 19 index.ts:5:13 +mw index.ts:46:32 index.ts:412:16 GET /r6 20 index.ts:5:13 +mw index.ts:48:32 index.ts:412:16 GET /r6 21 index.ts:5:13 +mw index.ts:50:32 index.ts:412:16 GET /r6 22 index.ts:5:13 +mw index.ts:52:32 index.ts:412:16 GET /r6 23 index.ts:5:13 +mw index.ts:54:32 index.ts:412:16 GET /r6 24 index.ts:5:13 +mw index.ts:56:32 index.ts:412:16 GET /r6 25 index.ts:5:13 +mw index.ts:58:32 index.ts:412:16 GET /r6 26 index.ts:5:13 +mw index.ts:60:32 index.ts:412:16 GET /r6 27 index.ts:5:13 +mw index.ts:62:32 index.ts:412:16 GET /r6 28 index.ts:5:13 +mw index.ts:64:32 index.ts:412:16 GET /r6 29 index.ts:5:13 +mw index.ts:66:32 index.ts:412:16 GET /r6 30 index.ts:5:13 +mw index.ts:68:32 index.ts:412:16 GET /r6 31 index.ts:5:13 +mw index.ts:70:32 index.ts:412:16 GET /r6 32 index.ts:5:13 +mw index.ts:72:32 index.ts:412:16 GET /r6 33 index.ts:5:13 +mw index.ts:74:32 index.ts:412:16 GET /r6 34 index.ts:5:13 +mw index.ts:76:32 index.ts:412:16 GET /r6 35 index.ts:5:13 +mw index.ts:78:32 index.ts:412:16 GET /r6 36 index.ts:5:13 +mw index.ts:80:32 index.ts:412:16 GET /r6 37 index.ts:5:13 +mw index.ts:82:32 index.ts:412:16 GET /r6 38 index.ts:5:13 +mw index.ts:84:32 index.ts:412:16 GET /r6 39 index.ts:5:13 +mw index.ts:86:32 index.ts:412:16 GET /r6 40 index.ts:5:13 +mw index.ts:88:32 index.ts:412:16 GET /r6 41 index.ts:5:13 +mw index.ts:90:32 index.ts:412:16 GET /r6 42 index.ts:5:13 +mw index.ts:92:32 index.ts:412:16 GET /r6 43 index.ts:5:13 +mw index.ts:94:32 index.ts:412:16 GET /r6 44 index.ts:5:13 +mw index.ts:96:32 index.ts:412:16 GET /r6 45 index.ts:5:13 +mw index.ts:98:32 index.ts:412:16 GET /r6 46 index.ts:5:13 +mw index.ts:100:32 index.ts:412:16 GET /r6 47 index.ts:5:13 +mw index.ts:102:32 index.ts:412:16 GET /r6 48 index.ts:5:13 +mw index.ts:104:32 index.ts:412:16 GET /r6 49 index.ts:5:13 +mw index.ts:106:32 index.ts:412:16 GET /r6 50 index.ts:5:13 +mw index.ts:108:32 index.ts:412:16 GET /r6 51 index.ts:5:13 +mw index.ts:110:32 index.ts:412:16 GET /r6 52 index.ts:5:13 +mw index.ts:112:32 index.ts:412:16 GET /r6 53 index.ts:5:13 +mw index.ts:114:32 index.ts:412:16 GET /r6 54 index.ts:5:13 +mw index.ts:116:32 index.ts:412:16 GET /r6 55 index.ts:5:13 +mw index.ts:118:32 index.ts:412:16 GET /r6 56 index.ts:5:13 +mw index.ts:120:32 index.ts:412:16 GET /r6 57 index.ts:5:13 +mw index.ts:122:32 index.ts:412:16 GET /r6 58 index.ts:5:13 +mw index.ts:124:32 index.ts:412:16 GET /r6 59 index.ts:5:13 +mw index.ts:126:32 index.ts:412:16 GET /r6 60 index.ts:5:13 +mw index.ts:128:32 index.ts:412:16 GET /r6 61 index.ts:5:13 +mw index.ts:130:32 index.ts:412:16 GET /r6 62 index.ts:5:13 +mw index.ts:132:32 index.ts:412:16 GET /r6 63 index.ts:5:13 +mw index.ts:134:32 index.ts:412:16 GET /r6 64 index.ts:5:13 +mw index.ts:136:32 index.ts:412:16 GET /r6 65 index.ts:5:13 +mw index.ts:138:32 index.ts:412:16 GET /r6 66 index.ts:5:13 +mw index.ts:140:32 index.ts:412:16 GET /r6 67 index.ts:5:13 +mw index.ts:142:32 index.ts:412:16 GET /r6 68 index.ts:5:13 +mw index.ts:144:32 index.ts:412:16 GET /r6 69 index.ts:5:13 +mw index.ts:146:32 index.ts:412:16 GET /r6 70 index.ts:5:13 +mw index.ts:148:32 index.ts:412:16 GET /r6 71 index.ts:5:13 +mw index.ts:150:32 index.ts:412:16 GET /r6 72 index.ts:5:13 +mw index.ts:152:32 index.ts:412:16 GET /r6 73 index.ts:5:13 +mw index.ts:154:32 index.ts:412:16 GET /r6 74 index.ts:5:13 +mw index.ts:156:32 index.ts:412:16 GET /r6 75 index.ts:5:13 +mw index.ts:158:32 index.ts:412:16 GET /r6 76 index.ts:5:13 +mw index.ts:160:32 index.ts:412:16 GET /r6 77 index.ts:5:13 +mw index.ts:162:32 index.ts:412:16 GET /r6 78 index.ts:5:13 +mw index.ts:164:32 index.ts:412:16 GET /r6 79 index.ts:5:13 +mw index.ts:166:32 index.ts:412:16 GET /r6 80 index.ts:5:13 +mw index.ts:168:32 index.ts:412:16 GET /r6 81 index.ts:5:13 +mw index.ts:170:32 index.ts:412:16 GET /r6 82 index.ts:5:13 +mw index.ts:172:32 index.ts:412:16 GET /r6 83 index.ts:5:13 +mw index.ts:174:32 index.ts:412:16 GET /r6 84 index.ts:5:13 +mw index.ts:176:32 index.ts:412:16 GET /r6 85 index.ts:5:13 +mw index.ts:178:32 index.ts:412:16 GET /r6 86 index.ts:5:13 +mw index.ts:180:32 index.ts:412:16 GET /r6 87 index.ts:5:13 +mw index.ts:182:32 index.ts:412:16 GET /r6 88 index.ts:5:13 +mw index.ts:184:32 index.ts:412:16 GET /r6 89 index.ts:5:13 +mw index.ts:186:32 index.ts:412:16 GET /r6 90 index.ts:5:13 +mw index.ts:188:32 index.ts:412:16 GET /r6 91 index.ts:5:13 +mw index.ts:190:32 index.ts:412:16 GET /r6 92 index.ts:5:13 +mw index.ts:192:32 index.ts:412:16 GET /r6 93 index.ts:5:13 +mw index.ts:194:32 index.ts:412:16 GET /r6 94 index.ts:5:13 +mw index.ts:196:32 index.ts:412:16 GET /r6 95 index.ts:5:13 +mw index.ts:198:32 index.ts:412:16 GET /r6 96 index.ts:5:13 +mw index.ts:200:32 index.ts:412:16 GET /r6 97 index.ts:5:13 +mw index.ts:202:32 index.ts:412:16 GET /r6 98 index.ts:5:13 +mw index.ts:204:32 index.ts:412:16 GET /r6 99 index.ts:5:13 +mw index.ts:206:33 index.ts:412:16 GET /r6 100 index.ts:5:13 +mw index.ts:208:33 index.ts:412:16 GET /r6 101 index.ts:5:13 +mw index.ts:210:33 index.ts:412:16 GET /r6 102 index.ts:5:13 +mw index.ts:212:33 index.ts:412:16 GET /r6 103 index.ts:5:13 +mw index.ts:214:33 index.ts:412:16 GET /r6 104 index.ts:5:13 +mw index.ts:216:33 index.ts:412:16 GET /r6 105 index.ts:5:13 +mw index.ts:218:33 index.ts:412:16 GET /r6 106 index.ts:5:13 +mw index.ts:220:33 index.ts:412:16 GET /r6 107 index.ts:5:13 +mw index.ts:222:33 index.ts:412:16 GET /r6 108 index.ts:5:13 +mw index.ts:224:33 index.ts:412:16 GET /r6 109 index.ts:5:13 +mw index.ts:226:33 index.ts:412:16 GET /r6 110 index.ts:5:13 +mw index.ts:228:33 index.ts:412:16 GET /r6 111 index.ts:5:13 +mw index.ts:230:33 index.ts:412:16 GET /r6 112 index.ts:5:13 +mw index.ts:232:33 index.ts:412:16 GET /r6 113 index.ts:5:13 +mw index.ts:234:33 index.ts:412:16 GET /r6 114 index.ts:5:13 +mw index.ts:236:33 index.ts:412:16 GET /r6 115 index.ts:5:13 +mw index.ts:238:33 index.ts:412:16 GET /r6 116 index.ts:5:13 +mw index.ts:240:33 index.ts:412:16 GET /r6 117 index.ts:5:13 +mw index.ts:242:33 index.ts:412:16 GET /r6 118 index.ts:5:13 +mw index.ts:244:33 index.ts:412:16 GET /r6 119 index.ts:5:13 +mw index.ts:246:33 index.ts:412:16 GET /r6 120 index.ts:5:13 +mw index.ts:248:33 index.ts:412:16 GET /r6 121 index.ts:5:13 +mw index.ts:250:33 index.ts:412:16 GET /r6 122 index.ts:5:13 +mw index.ts:252:33 index.ts:412:16 GET /r6 123 index.ts:5:13 +mw index.ts:254:33 index.ts:412:16 GET /r6 124 index.ts:5:13 +mw index.ts:256:33 index.ts:412:16 GET /r6 125 index.ts:5:13 +mw index.ts:258:33 index.ts:412:16 GET /r6 126 index.ts:5:13 +mw index.ts:260:33 index.ts:412:16 GET /r6 127 index.ts:5:13 +mw index.ts:262:33 index.ts:412:16 GET /r6 128 index.ts:5:13 +mw index.ts:264:33 index.ts:412:16 GET /r6 129 index.ts:5:13 +mw index.ts:266:33 index.ts:412:16 GET /r6 130 index.ts:5:13 +mw index.ts:268:33 index.ts:412:16 GET /r6 131 index.ts:5:13 +mw index.ts:270:33 index.ts:412:16 GET /r6 132 index.ts:5:13 +mw index.ts:272:33 index.ts:412:16 GET /r6 133 index.ts:5:13 +mw index.ts:274:33 index.ts:412:16 GET /r6 134 index.ts:5:13 +mw index.ts:276:33 index.ts:412:16 GET /r6 135 index.ts:5:13 +mw index.ts:278:33 index.ts:412:16 GET /r6 136 index.ts:5:13 +mw index.ts:280:33 index.ts:412:16 GET /r6 137 index.ts:5:13 +mw index.ts:282:33 index.ts:412:16 GET /r6 138 index.ts:5:13 +mw index.ts:284:33 index.ts:412:16 GET /r6 139 index.ts:5:13 +mw index.ts:286:33 index.ts:412:16 GET /r6 140 index.ts:5:13 +mw index.ts:288:33 index.ts:412:16 GET /r6 141 index.ts:5:13 +mw index.ts:290:33 index.ts:412:16 GET /r6 142 index.ts:5:13 +mw index.ts:292:33 index.ts:412:16 GET /r6 143 index.ts:5:13 +mw index.ts:294:33 index.ts:412:16 GET /r6 144 index.ts:5:13 +mw index.ts:296:33 index.ts:412:16 GET /r6 145 index.ts:5:13 +mw index.ts:298:33 index.ts:412:16 GET /r6 146 index.ts:5:13 +mw index.ts:300:33 index.ts:412:16 GET /r6 147 index.ts:5:13 +mw index.ts:302:33 index.ts:412:16 GET /r6 148 index.ts:5:13 +mw index.ts:304:33 index.ts:412:16 GET /r6 149 index.ts:5:13 +mw index.ts:306:33 index.ts:412:16 GET /r6 150 index.ts:5:13 +mw index.ts:308:33 index.ts:412:16 GET /r6 151 index.ts:5:13 +mw index.ts:310:33 index.ts:412:16 GET /r6 152 index.ts:5:13 +mw index.ts:312:33 index.ts:412:16 GET /r6 153 index.ts:5:13 +mw index.ts:314:33 index.ts:412:16 GET /r6 154 index.ts:5:13 +mw index.ts:316:33 index.ts:412:16 GET /r6 155 index.ts:5:13 +mw index.ts:318:33 index.ts:412:16 GET /r6 156 index.ts:5:13 +mw index.ts:320:33 index.ts:412:16 GET /r6 157 index.ts:5:13 +mw index.ts:322:33 index.ts:412:16 GET /r6 158 index.ts:5:13 +mw index.ts:324:33 index.ts:412:16 GET /r6 159 index.ts:5:13 +mw index.ts:326:33 index.ts:412:16 GET /r6 160 index.ts:5:13 +mw index.ts:328:33 index.ts:412:16 GET /r6 161 index.ts:5:13 +mw index.ts:330:33 index.ts:412:16 GET /r6 162 index.ts:5:13 +mw index.ts:332:33 index.ts:412:16 GET /r6 163 index.ts:5:13 +mw index.ts:334:33 index.ts:412:16 GET /r6 164 index.ts:5:13 +mw index.ts:336:33 index.ts:412:16 GET /r6 165 index.ts:5:13 +mw index.ts:338:33 index.ts:412:16 GET /r6 166 index.ts:5:13 +mw index.ts:340:33 index.ts:412:16 GET /r6 167 index.ts:5:13 +mw index.ts:342:33 index.ts:412:16 GET /r6 168 index.ts:5:13 +mw index.ts:344:33 index.ts:412:16 GET /r6 169 index.ts:5:13 +mw index.ts:346:33 index.ts:412:16 GET /r6 170 index.ts:5:13 +mw index.ts:348:33 index.ts:412:16 GET /r6 171 index.ts:5:13 +mw index.ts:350:33 index.ts:412:16 GET /r6 172 index.ts:5:13 +mw index.ts:352:33 index.ts:412:16 GET /r6 173 index.ts:5:13 +mw index.ts:354:33 index.ts:412:16 GET /r6 174 index.ts:5:13 +mw index.ts:356:33 index.ts:412:16 GET /r6 175 index.ts:5:13 +mw index.ts:358:33 index.ts:412:16 GET /r6 176 index.ts:5:13 +mw index.ts:360:33 index.ts:412:16 GET /r6 177 index.ts:5:13 +mw index.ts:362:33 index.ts:412:16 GET /r6 178 index.ts:5:13 +mw index.ts:364:33 index.ts:412:16 GET /r6 179 index.ts:5:13 +mw index.ts:366:33 index.ts:412:16 GET /r6 180 index.ts:5:13 +mw index.ts:368:33 index.ts:412:16 GET /r6 181 index.ts:5:13 +mw index.ts:370:33 index.ts:412:16 GET /r6 182 index.ts:5:13 +mw index.ts:372:33 index.ts:412:16 GET /r6 183 index.ts:5:13 +mw index.ts:374:33 index.ts:412:16 GET /r6 184 index.ts:5:13 +mw index.ts:376:33 index.ts:412:16 GET /r6 185 index.ts:5:13 +mw index.ts:378:33 index.ts:412:16 GET /r6 186 index.ts:5:13 +mw index.ts:380:33 index.ts:412:16 GET /r6 187 index.ts:5:13 +mw index.ts:382:33 index.ts:412:16 GET /r6 188 index.ts:5:13 +mw index.ts:384:33 index.ts:412:16 GET /r6 189 index.ts:5:13 +mw index.ts:386:33 index.ts:412:16 GET /r6 190 index.ts:5:13 +mw index.ts:388:33 index.ts:412:16 GET /r6 191 index.ts:5:13 +mw index.ts:390:33 index.ts:412:16 GET /r6 192 index.ts:5:13 +mw index.ts:392:33 index.ts:412:16 GET /r6 193 index.ts:5:13 +mw index.ts:394:33 index.ts:412:16 GET /r6 194 index.ts:5:13 +mw index.ts:396:33 index.ts:412:16 GET /r6 195 index.ts:5:13 +mw index.ts:398:33 index.ts:412:16 GET /r6 196 index.ts:5:13 +mw index.ts:400:33 index.ts:412:16 GET /r6 197 index.ts:5:13 +mw index.ts:402:33 index.ts:412:16 GET /r6 198 index.ts:5:13 +mw index.ts:404:33 index.ts:412:16 GET /r6 199 index.ts:5:13 +mw index.ts:6:31 index.ts:413:16 GET /r7 0 index.ts:5:13 +mw index.ts:8:31 index.ts:413:16 GET /r7 1 index.ts:5:13 +mw index.ts:10:31 index.ts:413:16 GET /r7 2 index.ts:5:13 +mw index.ts:12:31 index.ts:413:16 GET /r7 3 index.ts:5:13 +mw index.ts:14:31 index.ts:413:16 GET /r7 4 index.ts:5:13 +mw index.ts:16:31 index.ts:413:16 GET /r7 5 index.ts:5:13 +mw index.ts:18:31 index.ts:413:16 GET /r7 6 index.ts:5:13 +mw index.ts:20:31 index.ts:413:16 GET /r7 7 index.ts:5:13 +mw index.ts:22:31 index.ts:413:16 GET /r7 8 index.ts:5:13 +mw index.ts:24:31 index.ts:413:16 GET /r7 9 index.ts:5:13 +mw index.ts:26:32 index.ts:413:16 GET /r7 10 index.ts:5:13 +mw index.ts:28:32 index.ts:413:16 GET /r7 11 index.ts:5:13 +mw index.ts:30:32 index.ts:413:16 GET /r7 12 index.ts:5:13 +mw index.ts:32:32 index.ts:413:16 GET /r7 13 index.ts:5:13 +mw index.ts:34:32 index.ts:413:16 GET /r7 14 index.ts:5:13 +mw index.ts:36:32 index.ts:413:16 GET /r7 15 index.ts:5:13 +mw index.ts:38:32 index.ts:413:16 GET /r7 16 index.ts:5:13 +mw index.ts:40:32 index.ts:413:16 GET /r7 17 index.ts:5:13 +mw index.ts:42:32 index.ts:413:16 GET /r7 18 index.ts:5:13 +mw index.ts:44:32 index.ts:413:16 GET /r7 19 index.ts:5:13 +mw index.ts:46:32 index.ts:413:16 GET /r7 20 index.ts:5:13 +mw index.ts:48:32 index.ts:413:16 GET /r7 21 index.ts:5:13 +mw index.ts:50:32 index.ts:413:16 GET /r7 22 index.ts:5:13 +mw index.ts:52:32 index.ts:413:16 GET /r7 23 index.ts:5:13 +mw index.ts:54:32 index.ts:413:16 GET /r7 24 index.ts:5:13 +mw index.ts:56:32 index.ts:413:16 GET /r7 25 index.ts:5:13 +mw index.ts:58:32 index.ts:413:16 GET /r7 26 index.ts:5:13 +mw index.ts:60:32 index.ts:413:16 GET /r7 27 index.ts:5:13 +mw index.ts:62:32 index.ts:413:16 GET /r7 28 index.ts:5:13 +mw index.ts:64:32 index.ts:413:16 GET /r7 29 index.ts:5:13 +mw index.ts:66:32 index.ts:413:16 GET /r7 30 index.ts:5:13 +mw index.ts:68:32 index.ts:413:16 GET /r7 31 index.ts:5:13 +mw index.ts:70:32 index.ts:413:16 GET /r7 32 index.ts:5:13 +mw index.ts:72:32 index.ts:413:16 GET /r7 33 index.ts:5:13 +mw index.ts:74:32 index.ts:413:16 GET /r7 34 index.ts:5:13 +mw index.ts:76:32 index.ts:413:16 GET /r7 35 index.ts:5:13 +mw index.ts:78:32 index.ts:413:16 GET /r7 36 index.ts:5:13 +mw index.ts:80:32 index.ts:413:16 GET /r7 37 index.ts:5:13 +mw index.ts:82:32 index.ts:413:16 GET /r7 38 index.ts:5:13 +mw index.ts:84:32 index.ts:413:16 GET /r7 39 index.ts:5:13 +mw index.ts:86:32 index.ts:413:16 GET /r7 40 index.ts:5:13 +mw index.ts:88:32 index.ts:413:16 GET /r7 41 index.ts:5:13 +mw index.ts:90:32 index.ts:413:16 GET /r7 42 index.ts:5:13 +mw index.ts:92:32 index.ts:413:16 GET /r7 43 index.ts:5:13 +mw index.ts:94:32 index.ts:413:16 GET /r7 44 index.ts:5:13 +mw index.ts:96:32 index.ts:413:16 GET /r7 45 index.ts:5:13 +mw index.ts:98:32 index.ts:413:16 GET /r7 46 index.ts:5:13 +mw index.ts:100:32 index.ts:413:16 GET /r7 47 index.ts:5:13 +mw index.ts:102:32 index.ts:413:16 GET /r7 48 index.ts:5:13 +mw index.ts:104:32 index.ts:413:16 GET /r7 49 index.ts:5:13 +mw index.ts:106:32 index.ts:413:16 GET /r7 50 index.ts:5:13 +mw index.ts:108:32 index.ts:413:16 GET /r7 51 index.ts:5:13 +mw index.ts:110:32 index.ts:413:16 GET /r7 52 index.ts:5:13 +mw index.ts:112:32 index.ts:413:16 GET /r7 53 index.ts:5:13 +mw index.ts:114:32 index.ts:413:16 GET /r7 54 index.ts:5:13 +mw index.ts:116:32 index.ts:413:16 GET /r7 55 index.ts:5:13 +mw index.ts:118:32 index.ts:413:16 GET /r7 56 index.ts:5:13 +mw index.ts:120:32 index.ts:413:16 GET /r7 57 index.ts:5:13 +mw index.ts:122:32 index.ts:413:16 GET /r7 58 index.ts:5:13 +mw index.ts:124:32 index.ts:413:16 GET /r7 59 index.ts:5:13 +mw index.ts:126:32 index.ts:413:16 GET /r7 60 index.ts:5:13 +mw index.ts:128:32 index.ts:413:16 GET /r7 61 index.ts:5:13 +mw index.ts:130:32 index.ts:413:16 GET /r7 62 index.ts:5:13 +mw index.ts:132:32 index.ts:413:16 GET /r7 63 index.ts:5:13 +mw index.ts:134:32 index.ts:413:16 GET /r7 64 index.ts:5:13 +mw index.ts:136:32 index.ts:413:16 GET /r7 65 index.ts:5:13 +mw index.ts:138:32 index.ts:413:16 GET /r7 66 index.ts:5:13 +mw index.ts:140:32 index.ts:413:16 GET /r7 67 index.ts:5:13 +mw index.ts:142:32 index.ts:413:16 GET /r7 68 index.ts:5:13 +mw index.ts:144:32 index.ts:413:16 GET /r7 69 index.ts:5:13 +mw index.ts:146:32 index.ts:413:16 GET /r7 70 index.ts:5:13 +mw index.ts:148:32 index.ts:413:16 GET /r7 71 index.ts:5:13 +mw index.ts:150:32 index.ts:413:16 GET /r7 72 index.ts:5:13 +mw index.ts:152:32 index.ts:413:16 GET /r7 73 index.ts:5:13 +mw index.ts:154:32 index.ts:413:16 GET /r7 74 index.ts:5:13 +mw index.ts:156:32 index.ts:413:16 GET /r7 75 index.ts:5:13 +mw index.ts:158:32 index.ts:413:16 GET /r7 76 index.ts:5:13 +mw index.ts:160:32 index.ts:413:16 GET /r7 77 index.ts:5:13 +mw index.ts:162:32 index.ts:413:16 GET /r7 78 index.ts:5:13 +mw index.ts:164:32 index.ts:413:16 GET /r7 79 index.ts:5:13 +mw index.ts:166:32 index.ts:413:16 GET /r7 80 index.ts:5:13 +mw index.ts:168:32 index.ts:413:16 GET /r7 81 index.ts:5:13 +mw index.ts:170:32 index.ts:413:16 GET /r7 82 index.ts:5:13 +mw index.ts:172:32 index.ts:413:16 GET /r7 83 index.ts:5:13 +mw index.ts:174:32 index.ts:413:16 GET /r7 84 index.ts:5:13 +mw index.ts:176:32 index.ts:413:16 GET /r7 85 index.ts:5:13 +mw index.ts:178:32 index.ts:413:16 GET /r7 86 index.ts:5:13 +mw index.ts:180:32 index.ts:413:16 GET /r7 87 index.ts:5:13 +mw index.ts:182:32 index.ts:413:16 GET /r7 88 index.ts:5:13 +mw index.ts:184:32 index.ts:413:16 GET /r7 89 index.ts:5:13 +mw index.ts:186:32 index.ts:413:16 GET /r7 90 index.ts:5:13 +mw index.ts:188:32 index.ts:413:16 GET /r7 91 index.ts:5:13 +mw index.ts:190:32 index.ts:413:16 GET /r7 92 index.ts:5:13 +mw index.ts:192:32 index.ts:413:16 GET /r7 93 index.ts:5:13 +mw index.ts:194:32 index.ts:413:16 GET /r7 94 index.ts:5:13 +mw index.ts:196:32 index.ts:413:16 GET /r7 95 index.ts:5:13 +mw index.ts:198:32 index.ts:413:16 GET /r7 96 index.ts:5:13 +mw index.ts:200:32 index.ts:413:16 GET /r7 97 index.ts:5:13 +mw index.ts:202:32 index.ts:413:16 GET /r7 98 index.ts:5:13 +mw index.ts:204:32 index.ts:413:16 GET /r7 99 index.ts:5:13 +mw index.ts:206:33 index.ts:413:16 GET /r7 100 index.ts:5:13 +mw index.ts:208:33 index.ts:413:16 GET /r7 101 index.ts:5:13 +mw index.ts:210:33 index.ts:413:16 GET /r7 102 index.ts:5:13 +mw index.ts:212:33 index.ts:413:16 GET /r7 103 index.ts:5:13 +mw index.ts:214:33 index.ts:413:16 GET /r7 104 index.ts:5:13 +mw index.ts:216:33 index.ts:413:16 GET /r7 105 index.ts:5:13 +mw index.ts:218:33 index.ts:413:16 GET /r7 106 index.ts:5:13 +mw index.ts:220:33 index.ts:413:16 GET /r7 107 index.ts:5:13 +mw index.ts:222:33 index.ts:413:16 GET /r7 108 index.ts:5:13 +mw index.ts:224:33 index.ts:413:16 GET /r7 109 index.ts:5:13 +mw index.ts:226:33 index.ts:413:16 GET /r7 110 index.ts:5:13 +mw index.ts:228:33 index.ts:413:16 GET /r7 111 index.ts:5:13 +mw index.ts:230:33 index.ts:413:16 GET /r7 112 index.ts:5:13 +mw index.ts:232:33 index.ts:413:16 GET /r7 113 index.ts:5:13 +mw index.ts:234:33 index.ts:413:16 GET /r7 114 index.ts:5:13 +mw index.ts:236:33 index.ts:413:16 GET /r7 115 index.ts:5:13 +mw index.ts:238:33 index.ts:413:16 GET /r7 116 index.ts:5:13 +mw index.ts:240:33 index.ts:413:16 GET /r7 117 index.ts:5:13 +mw index.ts:242:33 index.ts:413:16 GET /r7 118 index.ts:5:13 +mw index.ts:244:33 index.ts:413:16 GET /r7 119 index.ts:5:13 +mw index.ts:246:33 index.ts:413:16 GET /r7 120 index.ts:5:13 +mw index.ts:248:33 index.ts:413:16 GET /r7 121 index.ts:5:13 +mw index.ts:250:33 index.ts:413:16 GET /r7 122 index.ts:5:13 +mw index.ts:252:33 index.ts:413:16 GET /r7 123 index.ts:5:13 +mw index.ts:254:33 index.ts:413:16 GET /r7 124 index.ts:5:13 +mw index.ts:256:33 index.ts:413:16 GET /r7 125 index.ts:5:13 +mw index.ts:258:33 index.ts:413:16 GET /r7 126 index.ts:5:13 +mw index.ts:260:33 index.ts:413:16 GET /r7 127 index.ts:5:13 +mw index.ts:262:33 index.ts:413:16 GET /r7 128 index.ts:5:13 +mw index.ts:264:33 index.ts:413:16 GET /r7 129 index.ts:5:13 +mw index.ts:266:33 index.ts:413:16 GET /r7 130 index.ts:5:13 +mw index.ts:268:33 index.ts:413:16 GET /r7 131 index.ts:5:13 +mw index.ts:270:33 index.ts:413:16 GET /r7 132 index.ts:5:13 +mw index.ts:272:33 index.ts:413:16 GET /r7 133 index.ts:5:13 +mw index.ts:274:33 index.ts:413:16 GET /r7 134 index.ts:5:13 +mw index.ts:276:33 index.ts:413:16 GET /r7 135 index.ts:5:13 +mw index.ts:278:33 index.ts:413:16 GET /r7 136 index.ts:5:13 +mw index.ts:280:33 index.ts:413:16 GET /r7 137 index.ts:5:13 +mw index.ts:282:33 index.ts:413:16 GET /r7 138 index.ts:5:13 +mw index.ts:284:33 index.ts:413:16 GET /r7 139 index.ts:5:13 +mw index.ts:286:33 index.ts:413:16 GET /r7 140 index.ts:5:13 +mw index.ts:288:33 index.ts:413:16 GET /r7 141 index.ts:5:13 +mw index.ts:290:33 index.ts:413:16 GET /r7 142 index.ts:5:13 +mw index.ts:292:33 index.ts:413:16 GET /r7 143 index.ts:5:13 +mw index.ts:294:33 index.ts:413:16 GET /r7 144 index.ts:5:13 +mw index.ts:296:33 index.ts:413:16 GET /r7 145 index.ts:5:13 +mw index.ts:298:33 index.ts:413:16 GET /r7 146 index.ts:5:13 +mw index.ts:300:33 index.ts:413:16 GET /r7 147 index.ts:5:13 +mw index.ts:302:33 index.ts:413:16 GET /r7 148 index.ts:5:13 +mw index.ts:304:33 index.ts:413:16 GET /r7 149 index.ts:5:13 +mw index.ts:306:33 index.ts:413:16 GET /r7 150 index.ts:5:13 +mw index.ts:308:33 index.ts:413:16 GET /r7 151 index.ts:5:13 +mw index.ts:310:33 index.ts:413:16 GET /r7 152 index.ts:5:13 +mw index.ts:312:33 index.ts:413:16 GET /r7 153 index.ts:5:13 +mw index.ts:314:33 index.ts:413:16 GET /r7 154 index.ts:5:13 +mw index.ts:316:33 index.ts:413:16 GET /r7 155 index.ts:5:13 +mw index.ts:318:33 index.ts:413:16 GET /r7 156 index.ts:5:13 +mw index.ts:320:33 index.ts:413:16 GET /r7 157 index.ts:5:13 +mw index.ts:322:33 index.ts:413:16 GET /r7 158 index.ts:5:13 +mw index.ts:324:33 index.ts:413:16 GET /r7 159 index.ts:5:13 +mw index.ts:326:33 index.ts:413:16 GET /r7 160 index.ts:5:13 +mw index.ts:328:33 index.ts:413:16 GET /r7 161 index.ts:5:13 +mw index.ts:330:33 index.ts:413:16 GET /r7 162 index.ts:5:13 +mw index.ts:332:33 index.ts:413:16 GET /r7 163 index.ts:5:13 +mw index.ts:334:33 index.ts:413:16 GET /r7 164 index.ts:5:13 +mw index.ts:336:33 index.ts:413:16 GET /r7 165 index.ts:5:13 +mw index.ts:338:33 index.ts:413:16 GET /r7 166 index.ts:5:13 +mw index.ts:340:33 index.ts:413:16 GET /r7 167 index.ts:5:13 +mw index.ts:342:33 index.ts:413:16 GET /r7 168 index.ts:5:13 +mw index.ts:344:33 index.ts:413:16 GET /r7 169 index.ts:5:13 +mw index.ts:346:33 index.ts:413:16 GET /r7 170 index.ts:5:13 +mw index.ts:348:33 index.ts:413:16 GET /r7 171 index.ts:5:13 +mw index.ts:350:33 index.ts:413:16 GET /r7 172 index.ts:5:13 +mw index.ts:352:33 index.ts:413:16 GET /r7 173 index.ts:5:13 +mw index.ts:354:33 index.ts:413:16 GET /r7 174 index.ts:5:13 +mw index.ts:356:33 index.ts:413:16 GET /r7 175 index.ts:5:13 +mw index.ts:358:33 index.ts:413:16 GET /r7 176 index.ts:5:13 +mw index.ts:360:33 index.ts:413:16 GET /r7 177 index.ts:5:13 +mw index.ts:362:33 index.ts:413:16 GET /r7 178 index.ts:5:13 +mw index.ts:364:33 index.ts:413:16 GET /r7 179 index.ts:5:13 +mw index.ts:366:33 index.ts:413:16 GET /r7 180 index.ts:5:13 +mw index.ts:368:33 index.ts:413:16 GET /r7 181 index.ts:5:13 +mw index.ts:370:33 index.ts:413:16 GET /r7 182 index.ts:5:13 +mw index.ts:372:33 index.ts:413:16 GET /r7 183 index.ts:5:13 +mw index.ts:374:33 index.ts:413:16 GET /r7 184 index.ts:5:13 +mw index.ts:376:33 index.ts:413:16 GET /r7 185 index.ts:5:13 +mw index.ts:378:33 index.ts:413:16 GET /r7 186 index.ts:5:13 +mw index.ts:380:33 index.ts:413:16 GET /r7 187 index.ts:5:13 +mw index.ts:382:33 index.ts:413:16 GET /r7 188 index.ts:5:13 +mw index.ts:384:33 index.ts:413:16 GET /r7 189 index.ts:5:13 +mw index.ts:386:33 index.ts:413:16 GET /r7 190 index.ts:5:13 +mw index.ts:388:33 index.ts:413:16 GET /r7 191 index.ts:5:13 +mw index.ts:390:33 index.ts:413:16 GET /r7 192 index.ts:5:13 +mw index.ts:392:33 index.ts:413:16 GET /r7 193 index.ts:5:13 +mw index.ts:394:33 index.ts:413:16 GET /r7 194 index.ts:5:13 +mw index.ts:396:33 index.ts:413:16 GET /r7 195 index.ts:5:13 +mw index.ts:398:33 index.ts:413:16 GET /r7 196 index.ts:5:13 +mw index.ts:400:33 index.ts:413:16 GET /r7 197 index.ts:5:13 +mw index.ts:402:33 index.ts:413:16 GET /r7 198 index.ts:5:13 +mw index.ts:404:33 index.ts:413:16 GET /r7 199 index.ts:5:13 +mw index.ts:6:31 index.ts:414:16 GET /r8 0 index.ts:5:13 +mw index.ts:8:31 index.ts:414:16 GET /r8 1 index.ts:5:13 +mw index.ts:10:31 index.ts:414:16 GET /r8 2 index.ts:5:13 +mw index.ts:12:31 index.ts:414:16 GET /r8 3 index.ts:5:13 +mw index.ts:14:31 index.ts:414:16 GET /r8 4 index.ts:5:13 +mw index.ts:16:31 index.ts:414:16 GET /r8 5 index.ts:5:13 +mw index.ts:18:31 index.ts:414:16 GET /r8 6 index.ts:5:13 +mw index.ts:20:31 index.ts:414:16 GET /r8 7 index.ts:5:13 +mw index.ts:22:31 index.ts:414:16 GET /r8 8 index.ts:5:13 +mw index.ts:24:31 index.ts:414:16 GET /r8 9 index.ts:5:13 +mw index.ts:26:32 index.ts:414:16 GET /r8 10 index.ts:5:13 +mw index.ts:28:32 index.ts:414:16 GET /r8 11 index.ts:5:13 +mw index.ts:30:32 index.ts:414:16 GET /r8 12 index.ts:5:13 +mw index.ts:32:32 index.ts:414:16 GET /r8 13 index.ts:5:13 +mw index.ts:34:32 index.ts:414:16 GET /r8 14 index.ts:5:13 +mw index.ts:36:32 index.ts:414:16 GET /r8 15 index.ts:5:13 +mw index.ts:38:32 index.ts:414:16 GET /r8 16 index.ts:5:13 +mw index.ts:40:32 index.ts:414:16 GET /r8 17 index.ts:5:13 +mw index.ts:42:32 index.ts:414:16 GET /r8 18 index.ts:5:13 +mw index.ts:44:32 index.ts:414:16 GET /r8 19 index.ts:5:13 +mw index.ts:46:32 index.ts:414:16 GET /r8 20 index.ts:5:13 +mw index.ts:48:32 index.ts:414:16 GET /r8 21 index.ts:5:13 +mw index.ts:50:32 index.ts:414:16 GET /r8 22 index.ts:5:13 +mw index.ts:52:32 index.ts:414:16 GET /r8 23 index.ts:5:13 +mw index.ts:54:32 index.ts:414:16 GET /r8 24 index.ts:5:13 +mw index.ts:56:32 index.ts:414:16 GET /r8 25 index.ts:5:13 +mw index.ts:58:32 index.ts:414:16 GET /r8 26 index.ts:5:13 +mw index.ts:60:32 index.ts:414:16 GET /r8 27 index.ts:5:13 +mw index.ts:62:32 index.ts:414:16 GET /r8 28 index.ts:5:13 +mw index.ts:64:32 index.ts:414:16 GET /r8 29 index.ts:5:13 +mw index.ts:66:32 index.ts:414:16 GET /r8 30 index.ts:5:13 +mw index.ts:68:32 index.ts:414:16 GET /r8 31 index.ts:5:13 +mw index.ts:70:32 index.ts:414:16 GET /r8 32 index.ts:5:13 +mw index.ts:72:32 index.ts:414:16 GET /r8 33 index.ts:5:13 +mw index.ts:74:32 index.ts:414:16 GET /r8 34 index.ts:5:13 +mw index.ts:76:32 index.ts:414:16 GET /r8 35 index.ts:5:13 +mw index.ts:78:32 index.ts:414:16 GET /r8 36 index.ts:5:13 +mw index.ts:80:32 index.ts:414:16 GET /r8 37 index.ts:5:13 +mw index.ts:82:32 index.ts:414:16 GET /r8 38 index.ts:5:13 +mw index.ts:84:32 index.ts:414:16 GET /r8 39 index.ts:5:13 +mw index.ts:86:32 index.ts:414:16 GET /r8 40 index.ts:5:13 +mw index.ts:88:32 index.ts:414:16 GET /r8 41 index.ts:5:13 +mw index.ts:90:32 index.ts:414:16 GET /r8 42 index.ts:5:13 +mw index.ts:92:32 index.ts:414:16 GET /r8 43 index.ts:5:13 +mw index.ts:94:32 index.ts:414:16 GET /r8 44 index.ts:5:13 +mw index.ts:96:32 index.ts:414:16 GET /r8 45 index.ts:5:13 +mw index.ts:98:32 index.ts:414:16 GET /r8 46 index.ts:5:13 +mw index.ts:100:32 index.ts:414:16 GET /r8 47 index.ts:5:13 +mw index.ts:102:32 index.ts:414:16 GET /r8 48 index.ts:5:13 +mw index.ts:104:32 index.ts:414:16 GET /r8 49 index.ts:5:13 +mw index.ts:106:32 index.ts:414:16 GET /r8 50 index.ts:5:13 +mw index.ts:108:32 index.ts:414:16 GET /r8 51 index.ts:5:13 +mw index.ts:110:32 index.ts:414:16 GET /r8 52 index.ts:5:13 +mw index.ts:112:32 index.ts:414:16 GET /r8 53 index.ts:5:13 +mw index.ts:114:32 index.ts:414:16 GET /r8 54 index.ts:5:13 +mw index.ts:116:32 index.ts:414:16 GET /r8 55 index.ts:5:13 +mw index.ts:118:32 index.ts:414:16 GET /r8 56 index.ts:5:13 +mw index.ts:120:32 index.ts:414:16 GET /r8 57 index.ts:5:13 +mw index.ts:122:32 index.ts:414:16 GET /r8 58 index.ts:5:13 +mw index.ts:124:32 index.ts:414:16 GET /r8 59 index.ts:5:13 +mw index.ts:126:32 index.ts:414:16 GET /r8 60 index.ts:5:13 +mw index.ts:128:32 index.ts:414:16 GET /r8 61 index.ts:5:13 +mw index.ts:130:32 index.ts:414:16 GET /r8 62 index.ts:5:13 +mw index.ts:132:32 index.ts:414:16 GET /r8 63 index.ts:5:13 +mw index.ts:134:32 index.ts:414:16 GET /r8 64 index.ts:5:13 +mw index.ts:136:32 index.ts:414:16 GET /r8 65 index.ts:5:13 +mw index.ts:138:32 index.ts:414:16 GET /r8 66 index.ts:5:13 +mw index.ts:140:32 index.ts:414:16 GET /r8 67 index.ts:5:13 +mw index.ts:142:32 index.ts:414:16 GET /r8 68 index.ts:5:13 +mw index.ts:144:32 index.ts:414:16 GET /r8 69 index.ts:5:13 +mw index.ts:146:32 index.ts:414:16 GET /r8 70 index.ts:5:13 +mw index.ts:148:32 index.ts:414:16 GET /r8 71 index.ts:5:13 +mw index.ts:150:32 index.ts:414:16 GET /r8 72 index.ts:5:13 +mw index.ts:152:32 index.ts:414:16 GET /r8 73 index.ts:5:13 +mw index.ts:154:32 index.ts:414:16 GET /r8 74 index.ts:5:13 +mw index.ts:156:32 index.ts:414:16 GET /r8 75 index.ts:5:13 +mw index.ts:158:32 index.ts:414:16 GET /r8 76 index.ts:5:13 +mw index.ts:160:32 index.ts:414:16 GET /r8 77 index.ts:5:13 +mw index.ts:162:32 index.ts:414:16 GET /r8 78 index.ts:5:13 +mw index.ts:164:32 index.ts:414:16 GET /r8 79 index.ts:5:13 +mw index.ts:166:32 index.ts:414:16 GET /r8 80 index.ts:5:13 +mw index.ts:168:32 index.ts:414:16 GET /r8 81 index.ts:5:13 +mw index.ts:170:32 index.ts:414:16 GET /r8 82 index.ts:5:13 +mw index.ts:172:32 index.ts:414:16 GET /r8 83 index.ts:5:13 +mw index.ts:174:32 index.ts:414:16 GET /r8 84 index.ts:5:13 +mw index.ts:176:32 index.ts:414:16 GET /r8 85 index.ts:5:13 +mw index.ts:178:32 index.ts:414:16 GET /r8 86 index.ts:5:13 +mw index.ts:180:32 index.ts:414:16 GET /r8 87 index.ts:5:13 +mw index.ts:182:32 index.ts:414:16 GET /r8 88 index.ts:5:13 +mw index.ts:184:32 index.ts:414:16 GET /r8 89 index.ts:5:13 +mw index.ts:186:32 index.ts:414:16 GET /r8 90 index.ts:5:13 +mw index.ts:188:32 index.ts:414:16 GET /r8 91 index.ts:5:13 +mw index.ts:190:32 index.ts:414:16 GET /r8 92 index.ts:5:13 +mw index.ts:192:32 index.ts:414:16 GET /r8 93 index.ts:5:13 +mw index.ts:194:32 index.ts:414:16 GET /r8 94 index.ts:5:13 +mw index.ts:196:32 index.ts:414:16 GET /r8 95 index.ts:5:13 +mw index.ts:198:32 index.ts:414:16 GET /r8 96 index.ts:5:13 +mw index.ts:200:32 index.ts:414:16 GET /r8 97 index.ts:5:13 +mw index.ts:202:32 index.ts:414:16 GET /r8 98 index.ts:5:13 +mw index.ts:204:32 index.ts:414:16 GET /r8 99 index.ts:5:13 +mw index.ts:206:33 index.ts:414:16 GET /r8 100 index.ts:5:13 +mw index.ts:208:33 index.ts:414:16 GET /r8 101 index.ts:5:13 +mw index.ts:210:33 index.ts:414:16 GET /r8 102 index.ts:5:13 +mw index.ts:212:33 index.ts:414:16 GET /r8 103 index.ts:5:13 +mw index.ts:214:33 index.ts:414:16 GET /r8 104 index.ts:5:13 +mw index.ts:216:33 index.ts:414:16 GET /r8 105 index.ts:5:13 +mw index.ts:218:33 index.ts:414:16 GET /r8 106 index.ts:5:13 +mw index.ts:220:33 index.ts:414:16 GET /r8 107 index.ts:5:13 +mw index.ts:222:33 index.ts:414:16 GET /r8 108 index.ts:5:13 +mw index.ts:224:33 index.ts:414:16 GET /r8 109 index.ts:5:13 +mw index.ts:226:33 index.ts:414:16 GET /r8 110 index.ts:5:13 +mw index.ts:228:33 index.ts:414:16 GET /r8 111 index.ts:5:13 +mw index.ts:230:33 index.ts:414:16 GET /r8 112 index.ts:5:13 +mw index.ts:232:33 index.ts:414:16 GET /r8 113 index.ts:5:13 +mw index.ts:234:33 index.ts:414:16 GET /r8 114 index.ts:5:13 +mw index.ts:236:33 index.ts:414:16 GET /r8 115 index.ts:5:13 +mw index.ts:238:33 index.ts:414:16 GET /r8 116 index.ts:5:13 +mw index.ts:240:33 index.ts:414:16 GET /r8 117 index.ts:5:13 +mw index.ts:242:33 index.ts:414:16 GET /r8 118 index.ts:5:13 +mw index.ts:244:33 index.ts:414:16 GET /r8 119 index.ts:5:13 +mw index.ts:246:33 index.ts:414:16 GET /r8 120 index.ts:5:13 +mw index.ts:248:33 index.ts:414:16 GET /r8 121 index.ts:5:13 +mw index.ts:250:33 index.ts:414:16 GET /r8 122 index.ts:5:13 +mw index.ts:252:33 index.ts:414:16 GET /r8 123 index.ts:5:13 +mw index.ts:254:33 index.ts:414:16 GET /r8 124 index.ts:5:13 +mw index.ts:256:33 index.ts:414:16 GET /r8 125 index.ts:5:13 +mw index.ts:258:33 index.ts:414:16 GET /r8 126 index.ts:5:13 +mw index.ts:260:33 index.ts:414:16 GET /r8 127 index.ts:5:13 +mw index.ts:262:33 index.ts:414:16 GET /r8 128 index.ts:5:13 +mw index.ts:264:33 index.ts:414:16 GET /r8 129 index.ts:5:13 +mw index.ts:266:33 index.ts:414:16 GET /r8 130 index.ts:5:13 +mw index.ts:268:33 index.ts:414:16 GET /r8 131 index.ts:5:13 +mw index.ts:270:33 index.ts:414:16 GET /r8 132 index.ts:5:13 +mw index.ts:272:33 index.ts:414:16 GET /r8 133 index.ts:5:13 +mw index.ts:274:33 index.ts:414:16 GET /r8 134 index.ts:5:13 +mw index.ts:276:33 index.ts:414:16 GET /r8 135 index.ts:5:13 +mw index.ts:278:33 index.ts:414:16 GET /r8 136 index.ts:5:13 +mw index.ts:280:33 index.ts:414:16 GET /r8 137 index.ts:5:13 +mw index.ts:282:33 index.ts:414:16 GET /r8 138 index.ts:5:13 +mw index.ts:284:33 index.ts:414:16 GET /r8 139 index.ts:5:13 +mw index.ts:286:33 index.ts:414:16 GET /r8 140 index.ts:5:13 +mw index.ts:288:33 index.ts:414:16 GET /r8 141 index.ts:5:13 +mw index.ts:290:33 index.ts:414:16 GET /r8 142 index.ts:5:13 +mw index.ts:292:33 index.ts:414:16 GET /r8 143 index.ts:5:13 +mw index.ts:294:33 index.ts:414:16 GET /r8 144 index.ts:5:13 +mw index.ts:296:33 index.ts:414:16 GET /r8 145 index.ts:5:13 +mw index.ts:298:33 index.ts:414:16 GET /r8 146 index.ts:5:13 +mw index.ts:300:33 index.ts:414:16 GET /r8 147 index.ts:5:13 +mw index.ts:302:33 index.ts:414:16 GET /r8 148 index.ts:5:13 +mw index.ts:304:33 index.ts:414:16 GET /r8 149 index.ts:5:13 +mw index.ts:306:33 index.ts:414:16 GET /r8 150 index.ts:5:13 +mw index.ts:308:33 index.ts:414:16 GET /r8 151 index.ts:5:13 +mw index.ts:310:33 index.ts:414:16 GET /r8 152 index.ts:5:13 +mw index.ts:312:33 index.ts:414:16 GET /r8 153 index.ts:5:13 +mw index.ts:314:33 index.ts:414:16 GET /r8 154 index.ts:5:13 +mw index.ts:316:33 index.ts:414:16 GET /r8 155 index.ts:5:13 +mw index.ts:318:33 index.ts:414:16 GET /r8 156 index.ts:5:13 +mw index.ts:320:33 index.ts:414:16 GET /r8 157 index.ts:5:13 +mw index.ts:322:33 index.ts:414:16 GET /r8 158 index.ts:5:13 +mw index.ts:324:33 index.ts:414:16 GET /r8 159 index.ts:5:13 +mw index.ts:326:33 index.ts:414:16 GET /r8 160 index.ts:5:13 +mw index.ts:328:33 index.ts:414:16 GET /r8 161 index.ts:5:13 +mw index.ts:330:33 index.ts:414:16 GET /r8 162 index.ts:5:13 +mw index.ts:332:33 index.ts:414:16 GET /r8 163 index.ts:5:13 +mw index.ts:334:33 index.ts:414:16 GET /r8 164 index.ts:5:13 +mw index.ts:336:33 index.ts:414:16 GET /r8 165 index.ts:5:13 +mw index.ts:338:33 index.ts:414:16 GET /r8 166 index.ts:5:13 +mw index.ts:340:33 index.ts:414:16 GET /r8 167 index.ts:5:13 +mw index.ts:342:33 index.ts:414:16 GET /r8 168 index.ts:5:13 +mw index.ts:344:33 index.ts:414:16 GET /r8 169 index.ts:5:13 +mw index.ts:346:33 index.ts:414:16 GET /r8 170 index.ts:5:13 +mw index.ts:348:33 index.ts:414:16 GET /r8 171 index.ts:5:13 +mw index.ts:350:33 index.ts:414:16 GET /r8 172 index.ts:5:13 +mw index.ts:352:33 index.ts:414:16 GET /r8 173 index.ts:5:13 +mw index.ts:354:33 index.ts:414:16 GET /r8 174 index.ts:5:13 +mw index.ts:356:33 index.ts:414:16 GET /r8 175 index.ts:5:13 +mw index.ts:358:33 index.ts:414:16 GET /r8 176 index.ts:5:13 +mw index.ts:360:33 index.ts:414:16 GET /r8 177 index.ts:5:13 +mw index.ts:362:33 index.ts:414:16 GET /r8 178 index.ts:5:13 +mw index.ts:364:33 index.ts:414:16 GET /r8 179 index.ts:5:13 +mw index.ts:366:33 index.ts:414:16 GET /r8 180 index.ts:5:13 +mw index.ts:368:33 index.ts:414:16 GET /r8 181 index.ts:5:13 +mw index.ts:370:33 index.ts:414:16 GET /r8 182 index.ts:5:13 +mw index.ts:372:33 index.ts:414:16 GET /r8 183 index.ts:5:13 +mw index.ts:374:33 index.ts:414:16 GET /r8 184 index.ts:5:13 +mw index.ts:376:33 index.ts:414:16 GET /r8 185 index.ts:5:13 +mw index.ts:378:33 index.ts:414:16 GET /r8 186 index.ts:5:13 +mw index.ts:380:33 index.ts:414:16 GET /r8 187 index.ts:5:13 +mw index.ts:382:33 index.ts:414:16 GET /r8 188 index.ts:5:13 +mw index.ts:384:33 index.ts:414:16 GET /r8 189 index.ts:5:13 +mw index.ts:386:33 index.ts:414:16 GET /r8 190 index.ts:5:13 +mw index.ts:388:33 index.ts:414:16 GET /r8 191 index.ts:5:13 +mw index.ts:390:33 index.ts:414:16 GET /r8 192 index.ts:5:13 +mw index.ts:392:33 index.ts:414:16 GET /r8 193 index.ts:5:13 +mw index.ts:394:33 index.ts:414:16 GET /r8 194 index.ts:5:13 +mw index.ts:396:33 index.ts:414:16 GET /r8 195 index.ts:5:13 +mw index.ts:398:33 index.ts:414:16 GET /r8 196 index.ts:5:13 +mw index.ts:400:33 index.ts:414:16 GET /r8 197 index.ts:5:13 +mw index.ts:402:33 index.ts:414:16 GET /r8 198 index.ts:5:13 +mw index.ts:404:33 index.ts:414:16 GET /r8 199 index.ts:5:13 +mw index.ts:6:31 index.ts:415:16 GET /r9 0 index.ts:5:13 +mw index.ts:8:31 index.ts:415:16 GET /r9 1 index.ts:5:13 +mw index.ts:10:31 index.ts:415:16 GET /r9 2 index.ts:5:13 +mw index.ts:12:31 index.ts:415:16 GET /r9 3 index.ts:5:13 +mw index.ts:14:31 index.ts:415:16 GET /r9 4 index.ts:5:13 +mw index.ts:16:31 index.ts:415:16 GET /r9 5 index.ts:5:13 +mw index.ts:18:31 index.ts:415:16 GET /r9 6 index.ts:5:13 +mw index.ts:20:31 index.ts:415:16 GET /r9 7 index.ts:5:13 +mw index.ts:22:31 index.ts:415:16 GET /r9 8 index.ts:5:13 +mw index.ts:24:31 index.ts:415:16 GET /r9 9 index.ts:5:13 +mw index.ts:26:32 index.ts:415:16 GET /r9 10 index.ts:5:13 +mw index.ts:28:32 index.ts:415:16 GET /r9 11 index.ts:5:13 +mw index.ts:30:32 index.ts:415:16 GET /r9 12 index.ts:5:13 +mw index.ts:32:32 index.ts:415:16 GET /r9 13 index.ts:5:13 +mw index.ts:34:32 index.ts:415:16 GET /r9 14 index.ts:5:13 +mw index.ts:36:32 index.ts:415:16 GET /r9 15 index.ts:5:13 +mw index.ts:38:32 index.ts:415:16 GET /r9 16 index.ts:5:13 +mw index.ts:40:32 index.ts:415:16 GET /r9 17 index.ts:5:13 +mw index.ts:42:32 index.ts:415:16 GET /r9 18 index.ts:5:13 +mw index.ts:44:32 index.ts:415:16 GET /r9 19 index.ts:5:13 +mw index.ts:46:32 index.ts:415:16 GET /r9 20 index.ts:5:13 +mw index.ts:48:32 index.ts:415:16 GET /r9 21 index.ts:5:13 +mw index.ts:50:32 index.ts:415:16 GET /r9 22 index.ts:5:13 +mw index.ts:52:32 index.ts:415:16 GET /r9 23 index.ts:5:13 +mw index.ts:54:32 index.ts:415:16 GET /r9 24 index.ts:5:13 +mw index.ts:56:32 index.ts:415:16 GET /r9 25 index.ts:5:13 +mw index.ts:58:32 index.ts:415:16 GET /r9 26 index.ts:5:13 +mw index.ts:60:32 index.ts:415:16 GET /r9 27 index.ts:5:13 +mw index.ts:62:32 index.ts:415:16 GET /r9 28 index.ts:5:13 +mw index.ts:64:32 index.ts:415:16 GET /r9 29 index.ts:5:13 +mw index.ts:66:32 index.ts:415:16 GET /r9 30 index.ts:5:13 +mw index.ts:68:32 index.ts:415:16 GET /r9 31 index.ts:5:13 +mw index.ts:70:32 index.ts:415:16 GET /r9 32 index.ts:5:13 +mw index.ts:72:32 index.ts:415:16 GET /r9 33 index.ts:5:13 +mw index.ts:74:32 index.ts:415:16 GET /r9 34 index.ts:5:13 +mw index.ts:76:32 index.ts:415:16 GET /r9 35 index.ts:5:13 +mw index.ts:78:32 index.ts:415:16 GET /r9 36 index.ts:5:13 +mw index.ts:80:32 index.ts:415:16 GET /r9 37 index.ts:5:13 +mw index.ts:82:32 index.ts:415:16 GET /r9 38 index.ts:5:13 +mw index.ts:84:32 index.ts:415:16 GET /r9 39 index.ts:5:13 +mw index.ts:86:32 index.ts:415:16 GET /r9 40 index.ts:5:13 +mw index.ts:88:32 index.ts:415:16 GET /r9 41 index.ts:5:13 +mw index.ts:90:32 index.ts:415:16 GET /r9 42 index.ts:5:13 +mw index.ts:92:32 index.ts:415:16 GET /r9 43 index.ts:5:13 +mw index.ts:94:32 index.ts:415:16 GET /r9 44 index.ts:5:13 +mw index.ts:96:32 index.ts:415:16 GET /r9 45 index.ts:5:13 +mw index.ts:98:32 index.ts:415:16 GET /r9 46 index.ts:5:13 +mw index.ts:100:32 index.ts:415:16 GET /r9 47 index.ts:5:13 +mw index.ts:102:32 index.ts:415:16 GET /r9 48 index.ts:5:13 +mw index.ts:104:32 index.ts:415:16 GET /r9 49 index.ts:5:13 +mw index.ts:106:32 index.ts:415:16 GET /r9 50 index.ts:5:13 +mw index.ts:108:32 index.ts:415:16 GET /r9 51 index.ts:5:13 +mw index.ts:110:32 index.ts:415:16 GET /r9 52 index.ts:5:13 +mw index.ts:112:32 index.ts:415:16 GET /r9 53 index.ts:5:13 +mw index.ts:114:32 index.ts:415:16 GET /r9 54 index.ts:5:13 +mw index.ts:116:32 index.ts:415:16 GET /r9 55 index.ts:5:13 +mw index.ts:118:32 index.ts:415:16 GET /r9 56 index.ts:5:13 +mw index.ts:120:32 index.ts:415:16 GET /r9 57 index.ts:5:13 +mw index.ts:122:32 index.ts:415:16 GET /r9 58 index.ts:5:13 +mw index.ts:124:32 index.ts:415:16 GET /r9 59 index.ts:5:13 +mw index.ts:126:32 index.ts:415:16 GET /r9 60 index.ts:5:13 +mw index.ts:128:32 index.ts:415:16 GET /r9 61 index.ts:5:13 +mw index.ts:130:32 index.ts:415:16 GET /r9 62 index.ts:5:13 +mw index.ts:132:32 index.ts:415:16 GET /r9 63 index.ts:5:13 +mw index.ts:134:32 index.ts:415:16 GET /r9 64 index.ts:5:13 +mw index.ts:136:32 index.ts:415:16 GET /r9 65 index.ts:5:13 +mw index.ts:138:32 index.ts:415:16 GET /r9 66 index.ts:5:13 +mw index.ts:140:32 index.ts:415:16 GET /r9 67 index.ts:5:13 +mw index.ts:142:32 index.ts:415:16 GET /r9 68 index.ts:5:13 +mw index.ts:144:32 index.ts:415:16 GET /r9 69 index.ts:5:13 +mw index.ts:146:32 index.ts:415:16 GET /r9 70 index.ts:5:13 +mw index.ts:148:32 index.ts:415:16 GET /r9 71 index.ts:5:13 +mw index.ts:150:32 index.ts:415:16 GET /r9 72 index.ts:5:13 +mw index.ts:152:32 index.ts:415:16 GET /r9 73 index.ts:5:13 +mw index.ts:154:32 index.ts:415:16 GET /r9 74 index.ts:5:13 +mw index.ts:156:32 index.ts:415:16 GET /r9 75 index.ts:5:13 +mw index.ts:158:32 index.ts:415:16 GET /r9 76 index.ts:5:13 +mw index.ts:160:32 index.ts:415:16 GET /r9 77 index.ts:5:13 +mw index.ts:162:32 index.ts:415:16 GET /r9 78 index.ts:5:13 +mw index.ts:164:32 index.ts:415:16 GET /r9 79 index.ts:5:13 +mw index.ts:166:32 index.ts:415:16 GET /r9 80 index.ts:5:13 +mw index.ts:168:32 index.ts:415:16 GET /r9 81 index.ts:5:13 +mw index.ts:170:32 index.ts:415:16 GET /r9 82 index.ts:5:13 +mw index.ts:172:32 index.ts:415:16 GET /r9 83 index.ts:5:13 +mw index.ts:174:32 index.ts:415:16 GET /r9 84 index.ts:5:13 +mw index.ts:176:32 index.ts:415:16 GET /r9 85 index.ts:5:13 +mw index.ts:178:32 index.ts:415:16 GET /r9 86 index.ts:5:13 +mw index.ts:180:32 index.ts:415:16 GET /r9 87 index.ts:5:13 +mw index.ts:182:32 index.ts:415:16 GET /r9 88 index.ts:5:13 +mw index.ts:184:32 index.ts:415:16 GET /r9 89 index.ts:5:13 +mw index.ts:186:32 index.ts:415:16 GET /r9 90 index.ts:5:13 +mw index.ts:188:32 index.ts:415:16 GET /r9 91 index.ts:5:13 +mw index.ts:190:32 index.ts:415:16 GET /r9 92 index.ts:5:13 +mw index.ts:192:32 index.ts:415:16 GET /r9 93 index.ts:5:13 +mw index.ts:194:32 index.ts:415:16 GET /r9 94 index.ts:5:13 +mw index.ts:196:32 index.ts:415:16 GET /r9 95 index.ts:5:13 +mw index.ts:198:32 index.ts:415:16 GET /r9 96 index.ts:5:13 +mw index.ts:200:32 index.ts:415:16 GET /r9 97 index.ts:5:13 +mw index.ts:202:32 index.ts:415:16 GET /r9 98 index.ts:5:13 +mw index.ts:204:32 index.ts:415:16 GET /r9 99 index.ts:5:13 +mw index.ts:206:33 index.ts:415:16 GET /r9 100 index.ts:5:13 +mw index.ts:208:33 index.ts:415:16 GET /r9 101 index.ts:5:13 +mw index.ts:210:33 index.ts:415:16 GET /r9 102 index.ts:5:13 +mw index.ts:212:33 index.ts:415:16 GET /r9 103 index.ts:5:13 +mw index.ts:214:33 index.ts:415:16 GET /r9 104 index.ts:5:13 +mw index.ts:216:33 index.ts:415:16 GET /r9 105 index.ts:5:13 +mw index.ts:218:33 index.ts:415:16 GET /r9 106 index.ts:5:13 +mw index.ts:220:33 index.ts:415:16 GET /r9 107 index.ts:5:13 +mw index.ts:222:33 index.ts:415:16 GET /r9 108 index.ts:5:13 +mw index.ts:224:33 index.ts:415:16 GET /r9 109 index.ts:5:13 +mw index.ts:226:33 index.ts:415:16 GET /r9 110 index.ts:5:13 +mw index.ts:228:33 index.ts:415:16 GET /r9 111 index.ts:5:13 +mw index.ts:230:33 index.ts:415:16 GET /r9 112 index.ts:5:13 +mw index.ts:232:33 index.ts:415:16 GET /r9 113 index.ts:5:13 +mw index.ts:234:33 index.ts:415:16 GET /r9 114 index.ts:5:13 +mw index.ts:236:33 index.ts:415:16 GET /r9 115 index.ts:5:13 +mw index.ts:238:33 index.ts:415:16 GET /r9 116 index.ts:5:13 +mw index.ts:240:33 index.ts:415:16 GET /r9 117 index.ts:5:13 +mw index.ts:242:33 index.ts:415:16 GET /r9 118 index.ts:5:13 +mw index.ts:244:33 index.ts:415:16 GET /r9 119 index.ts:5:13 +mw index.ts:246:33 index.ts:415:16 GET /r9 120 index.ts:5:13 +mw index.ts:248:33 index.ts:415:16 GET /r9 121 index.ts:5:13 +mw index.ts:250:33 index.ts:415:16 GET /r9 122 index.ts:5:13 +mw index.ts:252:33 index.ts:415:16 GET /r9 123 index.ts:5:13 +mw index.ts:254:33 index.ts:415:16 GET /r9 124 index.ts:5:13 +mw index.ts:256:33 index.ts:415:16 GET /r9 125 index.ts:5:13 +mw index.ts:258:33 index.ts:415:16 GET /r9 126 index.ts:5:13 +mw index.ts:260:33 index.ts:415:16 GET /r9 127 index.ts:5:13 +mw index.ts:262:33 index.ts:415:16 GET /r9 128 index.ts:5:13 +mw index.ts:264:33 index.ts:415:16 GET /r9 129 index.ts:5:13 +mw index.ts:266:33 index.ts:415:16 GET /r9 130 index.ts:5:13 +mw index.ts:268:33 index.ts:415:16 GET /r9 131 index.ts:5:13 +mw index.ts:270:33 index.ts:415:16 GET /r9 132 index.ts:5:13 +mw index.ts:272:33 index.ts:415:16 GET /r9 133 index.ts:5:13 +mw index.ts:274:33 index.ts:415:16 GET /r9 134 index.ts:5:13 +mw index.ts:276:33 index.ts:415:16 GET /r9 135 index.ts:5:13 +mw index.ts:278:33 index.ts:415:16 GET /r9 136 index.ts:5:13 +mw index.ts:280:33 index.ts:415:16 GET /r9 137 index.ts:5:13 +mw index.ts:282:33 index.ts:415:16 GET /r9 138 index.ts:5:13 +mw index.ts:284:33 index.ts:415:16 GET /r9 139 index.ts:5:13 +mw index.ts:286:33 index.ts:415:16 GET /r9 140 index.ts:5:13 +mw index.ts:288:33 index.ts:415:16 GET /r9 141 index.ts:5:13 +mw index.ts:290:33 index.ts:415:16 GET /r9 142 index.ts:5:13 +mw index.ts:292:33 index.ts:415:16 GET /r9 143 index.ts:5:13 +mw index.ts:294:33 index.ts:415:16 GET /r9 144 index.ts:5:13 +mw index.ts:296:33 index.ts:415:16 GET /r9 145 index.ts:5:13 +mw index.ts:298:33 index.ts:415:16 GET /r9 146 index.ts:5:13 +mw index.ts:300:33 index.ts:415:16 GET /r9 147 index.ts:5:13 +mw index.ts:302:33 index.ts:415:16 GET /r9 148 index.ts:5:13 +mw index.ts:304:33 index.ts:415:16 GET /r9 149 index.ts:5:13 +mw index.ts:306:33 index.ts:415:16 GET /r9 150 index.ts:5:13 +mw index.ts:308:33 index.ts:415:16 GET /r9 151 index.ts:5:13 +mw index.ts:310:33 index.ts:415:16 GET /r9 152 index.ts:5:13 +mw index.ts:312:33 index.ts:415:16 GET /r9 153 index.ts:5:13 +mw index.ts:314:33 index.ts:415:16 GET /r9 154 index.ts:5:13 +mw index.ts:316:33 index.ts:415:16 GET /r9 155 index.ts:5:13 +mw index.ts:318:33 index.ts:415:16 GET /r9 156 index.ts:5:13 +mw index.ts:320:33 index.ts:415:16 GET /r9 157 index.ts:5:13 +mw index.ts:322:33 index.ts:415:16 GET /r9 158 index.ts:5:13 +mw index.ts:324:33 index.ts:415:16 GET /r9 159 index.ts:5:13 +mw index.ts:326:33 index.ts:415:16 GET /r9 160 index.ts:5:13 +mw index.ts:328:33 index.ts:415:16 GET /r9 161 index.ts:5:13 +mw index.ts:330:33 index.ts:415:16 GET /r9 162 index.ts:5:13 +mw index.ts:332:33 index.ts:415:16 GET /r9 163 index.ts:5:13 +mw index.ts:334:33 index.ts:415:16 GET /r9 164 index.ts:5:13 +mw index.ts:336:33 index.ts:415:16 GET /r9 165 index.ts:5:13 +mw index.ts:338:33 index.ts:415:16 GET /r9 166 index.ts:5:13 +mw index.ts:340:33 index.ts:415:16 GET /r9 167 index.ts:5:13 +mw index.ts:342:33 index.ts:415:16 GET /r9 168 index.ts:5:13 +mw index.ts:344:33 index.ts:415:16 GET /r9 169 index.ts:5:13 +mw index.ts:346:33 index.ts:415:16 GET /r9 170 index.ts:5:13 +mw index.ts:348:33 index.ts:415:16 GET /r9 171 index.ts:5:13 +mw index.ts:350:33 index.ts:415:16 GET /r9 172 index.ts:5:13 +mw index.ts:352:33 index.ts:415:16 GET /r9 173 index.ts:5:13 +mw index.ts:354:33 index.ts:415:16 GET /r9 174 index.ts:5:13 +mw index.ts:356:33 index.ts:415:16 GET /r9 175 index.ts:5:13 +mw index.ts:358:33 index.ts:415:16 GET /r9 176 index.ts:5:13 +mw index.ts:360:33 index.ts:415:16 GET /r9 177 index.ts:5:13 +mw index.ts:362:33 index.ts:415:16 GET /r9 178 index.ts:5:13 +mw index.ts:364:33 index.ts:415:16 GET /r9 179 index.ts:5:13 +mw index.ts:366:33 index.ts:415:16 GET /r9 180 index.ts:5:13 +mw index.ts:368:33 index.ts:415:16 GET /r9 181 index.ts:5:13 +mw index.ts:370:33 index.ts:415:16 GET /r9 182 index.ts:5:13 +mw index.ts:372:33 index.ts:415:16 GET /r9 183 index.ts:5:13 +mw index.ts:374:33 index.ts:415:16 GET /r9 184 index.ts:5:13 +mw index.ts:376:33 index.ts:415:16 GET /r9 185 index.ts:5:13 +mw index.ts:378:33 index.ts:415:16 GET /r9 186 index.ts:5:13 +mw index.ts:380:33 index.ts:415:16 GET /r9 187 index.ts:5:13 +mw index.ts:382:33 index.ts:415:16 GET /r9 188 index.ts:5:13 +mw index.ts:384:33 index.ts:415:16 GET /r9 189 index.ts:5:13 +mw index.ts:386:33 index.ts:415:16 GET /r9 190 index.ts:5:13 +mw index.ts:388:33 index.ts:415:16 GET /r9 191 index.ts:5:13 +mw index.ts:390:33 index.ts:415:16 GET /r9 192 index.ts:5:13 +mw index.ts:392:33 index.ts:415:16 GET /r9 193 index.ts:5:13 +mw index.ts:394:33 index.ts:415:16 GET /r9 194 index.ts:5:13 +mw index.ts:396:33 index.ts:415:16 GET /r9 195 index.ts:5:13 +mw index.ts:398:33 index.ts:415:16 GET /r9 196 index.ts:5:13 +mw index.ts:400:33 index.ts:415:16 GET /r9 197 index.ts:5:13 +mw index.ts:402:33 index.ts:415:16 GET /r9 198 index.ts:5:13 +mw index.ts:404:33 index.ts:415:16 GET /r9 199 index.ts:5:13 +regby index.ts:1:1 index.ts:406:16 GET /r0 index.ts:5:13 +regby index.ts:1:1 index.ts:407:16 GET /r1 index.ts:5:13 +regby index.ts:1:1 index.ts:408:16 GET /r2 index.ts:5:13 +regby index.ts:1:1 index.ts:409:16 GET /r3 index.ts:5:13 +regby index.ts:1:1 index.ts:410:16 GET /r4 index.ts:5:13 +regby index.ts:1:1 index.ts:411:16 GET /r5 index.ts:5:13 +regby index.ts:1:1 index.ts:412:16 GET /r6 index.ts:5:13 +regby index.ts:1:1 index.ts:413:16 GET /r7 index.ts:5:13 +regby index.ts:1:1 index.ts:414:16 GET /r8 index.ts:5:13 +regby index.ts:1:1 index.ts:415:16 GET /r9 index.ts:5:13 diff --git a/graph/test/typescript/hono/expected/scale/routes-2k.entries b/graph/test/typescript/hono/expected/scale/routes-2k.entries new file mode 100644 index 000000000..03323bffb --- /dev/null +++ b/graph/test/typescript/hono/expected/scale/routes-2k.entries @@ -0,0 +1,2002 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: reviewed by count and endpoints: 2,000 routes over 20 mounted modules, first /m0/res0/:id, last PATCH /m19/res99/:id; runtime agrees on all +# census: route_mount_literal, verb_literal_path (scale: 2,000 routes; generated by tools/gen-scale.mjs) +entry mod0.ts:100:23 http +entry mod0.ts:101:22 http +entry mod0.ts:102:25 http +entry mod0.ts:103:24 http +entry mod0.ts:10:22 http +entry mod0.ts:11:21 http +entry mod0.ts:12:24 http +entry mod0.ts:13:23 http +entry mod0.ts:14:22 http +entry mod0.ts:15:23 http +entry mod0.ts:16:22 http +entry mod0.ts:17:25 http +entry mod0.ts:18:24 http +entry mod0.ts:19:22 http +entry mod0.ts:20:23 http +entry mod0.ts:21:22 http +entry mod0.ts:22:25 http +entry mod0.ts:23:24 http +entry mod0.ts:24:22 http +entry mod0.ts:25:23 http +entry mod0.ts:26:22 http +entry mod0.ts:27:25 http +entry mod0.ts:28:24 http +entry mod0.ts:29:22 http +entry mod0.ts:30:23 http +entry mod0.ts:31:22 http +entry mod0.ts:32:25 http +entry mod0.ts:33:24 http +entry mod0.ts:34:22 http +entry mod0.ts:35:23 http +entry mod0.ts:36:22 http +entry mod0.ts:37:25 http +entry mod0.ts:38:24 http +entry mod0.ts:39:22 http +entry mod0.ts:40:23 http +entry mod0.ts:41:22 http +entry mod0.ts:42:25 http +entry mod0.ts:43:24 http +entry mod0.ts:44:22 http +entry mod0.ts:45:23 http +entry mod0.ts:46:22 http +entry mod0.ts:47:25 http +entry mod0.ts:48:24 http +entry mod0.ts:49:22 http +entry mod0.ts:4:21 http +entry mod0.ts:50:23 http +entry mod0.ts:51:22 http +entry mod0.ts:52:25 http +entry mod0.ts:53:24 http +entry mod0.ts:54:22 http +entry mod0.ts:55:23 http +entry mod0.ts:56:22 http +entry mod0.ts:57:25 http +entry mod0.ts:58:24 http +entry mod0.ts:59:22 http +entry mod0.ts:5:22 http +entry mod0.ts:60:23 http +entry mod0.ts:61:22 http +entry mod0.ts:62:25 http +entry mod0.ts:63:24 http +entry mod0.ts:64:22 http +entry mod0.ts:65:23 http +entry mod0.ts:66:22 http +entry mod0.ts:67:25 http +entry mod0.ts:68:24 http +entry mod0.ts:69:22 http +entry mod0.ts:6:21 http +entry mod0.ts:70:23 http +entry mod0.ts:71:22 http +entry mod0.ts:72:25 http +entry mod0.ts:73:24 http +entry mod0.ts:74:22 http +entry mod0.ts:75:23 http +entry mod0.ts:76:22 http +entry mod0.ts:77:25 http +entry mod0.ts:78:24 http +entry mod0.ts:79:22 http +entry mod0.ts:7:24 http +entry mod0.ts:80:23 http +entry mod0.ts:81:22 http +entry mod0.ts:82:25 http +entry mod0.ts:83:24 http +entry mod0.ts:84:22 http +entry mod0.ts:85:23 http +entry mod0.ts:86:22 http +entry mod0.ts:87:25 http +entry mod0.ts:88:24 http +entry mod0.ts:89:22 http +entry mod0.ts:8:23 http +entry mod0.ts:90:23 http +entry mod0.ts:91:22 http +entry mod0.ts:92:25 http +entry mod0.ts:93:24 http +entry mod0.ts:94:22 http +entry mod0.ts:95:23 http +entry mod0.ts:96:22 http +entry mod0.ts:97:25 http +entry mod0.ts:98:24 http +entry mod0.ts:99:22 http +entry mod0.ts:9:21 http +entry mod1.ts:100:23 http +entry mod1.ts:101:22 http +entry mod1.ts:102:25 http +entry mod1.ts:103:24 http +entry mod1.ts:10:22 http +entry mod1.ts:11:21 http +entry mod1.ts:12:24 http +entry mod1.ts:13:23 http +entry mod1.ts:14:22 http +entry mod1.ts:15:23 http +entry mod1.ts:16:22 http +entry mod1.ts:17:25 http +entry mod1.ts:18:24 http +entry mod1.ts:19:22 http +entry mod1.ts:20:23 http +entry mod1.ts:21:22 http +entry mod1.ts:22:25 http +entry mod1.ts:23:24 http +entry mod1.ts:24:22 http +entry mod1.ts:25:23 http +entry mod1.ts:26:22 http +entry mod1.ts:27:25 http +entry mod1.ts:28:24 http +entry mod1.ts:29:22 http +entry mod1.ts:30:23 http +entry mod1.ts:31:22 http +entry mod1.ts:32:25 http +entry mod1.ts:33:24 http +entry mod1.ts:34:22 http +entry mod1.ts:35:23 http +entry mod1.ts:36:22 http +entry mod1.ts:37:25 http +entry mod1.ts:38:24 http +entry mod1.ts:39:22 http +entry mod1.ts:40:23 http +entry mod1.ts:41:22 http +entry mod1.ts:42:25 http +entry mod1.ts:43:24 http +entry mod1.ts:44:22 http +entry mod1.ts:45:23 http +entry mod1.ts:46:22 http +entry mod1.ts:47:25 http +entry mod1.ts:48:24 http +entry mod1.ts:49:22 http +entry mod1.ts:4:21 http +entry mod1.ts:50:23 http +entry mod1.ts:51:22 http +entry mod1.ts:52:25 http +entry mod1.ts:53:24 http +entry mod1.ts:54:22 http +entry mod1.ts:55:23 http +entry mod1.ts:56:22 http +entry mod1.ts:57:25 http +entry mod1.ts:58:24 http +entry mod1.ts:59:22 http +entry mod1.ts:5:22 http +entry mod1.ts:60:23 http +entry mod1.ts:61:22 http +entry mod1.ts:62:25 http +entry mod1.ts:63:24 http +entry mod1.ts:64:22 http +entry mod1.ts:65:23 http +entry mod1.ts:66:22 http +entry mod1.ts:67:25 http +entry mod1.ts:68:24 http +entry mod1.ts:69:22 http +entry mod1.ts:6:21 http +entry mod1.ts:70:23 http +entry mod1.ts:71:22 http +entry mod1.ts:72:25 http +entry mod1.ts:73:24 http +entry mod1.ts:74:22 http +entry mod1.ts:75:23 http +entry mod1.ts:76:22 http +entry mod1.ts:77:25 http +entry mod1.ts:78:24 http +entry mod1.ts:79:22 http +entry mod1.ts:7:24 http +entry mod1.ts:80:23 http +entry mod1.ts:81:22 http +entry mod1.ts:82:25 http +entry mod1.ts:83:24 http +entry mod1.ts:84:22 http +entry mod1.ts:85:23 http +entry mod1.ts:86:22 http +entry mod1.ts:87:25 http +entry mod1.ts:88:24 http +entry mod1.ts:89:22 http +entry mod1.ts:8:23 http +entry mod1.ts:90:23 http +entry mod1.ts:91:22 http +entry mod1.ts:92:25 http +entry mod1.ts:93:24 http +entry mod1.ts:94:22 http +entry mod1.ts:95:23 http +entry mod1.ts:96:22 http +entry mod1.ts:97:25 http +entry mod1.ts:98:24 http +entry mod1.ts:99:22 http +entry mod1.ts:9:21 http +entry mod10.ts:100:24 http +entry mod10.ts:101:23 http +entry mod10.ts:102:26 http +entry mod10.ts:103:25 http +entry mod10.ts:10:23 http +entry mod10.ts:11:22 http +entry mod10.ts:12:25 http +entry mod10.ts:13:24 http +entry mod10.ts:14:23 http +entry mod10.ts:15:24 http +entry mod10.ts:16:23 http +entry mod10.ts:17:26 http +entry mod10.ts:18:25 http +entry mod10.ts:19:23 http +entry mod10.ts:20:24 http +entry mod10.ts:21:23 http +entry mod10.ts:22:26 http +entry mod10.ts:23:25 http +entry mod10.ts:24:23 http +entry mod10.ts:25:24 http +entry mod10.ts:26:23 http +entry mod10.ts:27:26 http +entry mod10.ts:28:25 http +entry mod10.ts:29:23 http +entry mod10.ts:30:24 http +entry mod10.ts:31:23 http +entry mod10.ts:32:26 http +entry mod10.ts:33:25 http +entry mod10.ts:34:23 http +entry mod10.ts:35:24 http +entry mod10.ts:36:23 http +entry mod10.ts:37:26 http +entry mod10.ts:38:25 http +entry mod10.ts:39:23 http +entry mod10.ts:40:24 http +entry mod10.ts:41:23 http +entry mod10.ts:42:26 http +entry mod10.ts:43:25 http +entry mod10.ts:44:23 http +entry mod10.ts:45:24 http +entry mod10.ts:46:23 http +entry mod10.ts:47:26 http +entry mod10.ts:48:25 http +entry mod10.ts:49:23 http +entry mod10.ts:4:22 http +entry mod10.ts:50:24 http +entry mod10.ts:51:23 http +entry mod10.ts:52:26 http +entry mod10.ts:53:25 http +entry mod10.ts:54:23 http +entry mod10.ts:55:24 http +entry mod10.ts:56:23 http +entry mod10.ts:57:26 http +entry mod10.ts:58:25 http +entry mod10.ts:59:23 http +entry mod10.ts:5:23 http +entry mod10.ts:60:24 http +entry mod10.ts:61:23 http +entry mod10.ts:62:26 http +entry mod10.ts:63:25 http +entry mod10.ts:64:23 http +entry mod10.ts:65:24 http +entry mod10.ts:66:23 http +entry mod10.ts:67:26 http +entry mod10.ts:68:25 http +entry mod10.ts:69:23 http +entry mod10.ts:6:22 http +entry mod10.ts:70:24 http +entry mod10.ts:71:23 http +entry mod10.ts:72:26 http +entry mod10.ts:73:25 http +entry mod10.ts:74:23 http +entry mod10.ts:75:24 http +entry mod10.ts:76:23 http +entry mod10.ts:77:26 http +entry mod10.ts:78:25 http +entry mod10.ts:79:23 http +entry mod10.ts:7:25 http +entry mod10.ts:80:24 http +entry mod10.ts:81:23 http +entry mod10.ts:82:26 http +entry mod10.ts:83:25 http +entry mod10.ts:84:23 http +entry mod10.ts:85:24 http +entry mod10.ts:86:23 http +entry mod10.ts:87:26 http +entry mod10.ts:88:25 http +entry mod10.ts:89:23 http +entry mod10.ts:8:24 http +entry mod10.ts:90:24 http +entry mod10.ts:91:23 http +entry mod10.ts:92:26 http +entry mod10.ts:93:25 http +entry mod10.ts:94:23 http +entry mod10.ts:95:24 http +entry mod10.ts:96:23 http +entry mod10.ts:97:26 http +entry mod10.ts:98:25 http +entry mod10.ts:99:23 http +entry mod10.ts:9:22 http +entry mod11.ts:100:24 http +entry mod11.ts:101:23 http +entry mod11.ts:102:26 http +entry mod11.ts:103:25 http +entry mod11.ts:10:23 http +entry mod11.ts:11:22 http +entry mod11.ts:12:25 http +entry mod11.ts:13:24 http +entry mod11.ts:14:23 http +entry mod11.ts:15:24 http +entry mod11.ts:16:23 http +entry mod11.ts:17:26 http +entry mod11.ts:18:25 http +entry mod11.ts:19:23 http +entry mod11.ts:20:24 http +entry mod11.ts:21:23 http +entry mod11.ts:22:26 http +entry mod11.ts:23:25 http +entry mod11.ts:24:23 http +entry mod11.ts:25:24 http +entry mod11.ts:26:23 http +entry mod11.ts:27:26 http +entry mod11.ts:28:25 http +entry mod11.ts:29:23 http +entry mod11.ts:30:24 http +entry mod11.ts:31:23 http +entry mod11.ts:32:26 http +entry mod11.ts:33:25 http +entry mod11.ts:34:23 http +entry mod11.ts:35:24 http +entry mod11.ts:36:23 http +entry mod11.ts:37:26 http +entry mod11.ts:38:25 http +entry mod11.ts:39:23 http +entry mod11.ts:40:24 http +entry mod11.ts:41:23 http +entry mod11.ts:42:26 http +entry mod11.ts:43:25 http +entry mod11.ts:44:23 http +entry mod11.ts:45:24 http +entry mod11.ts:46:23 http +entry mod11.ts:47:26 http +entry mod11.ts:48:25 http +entry mod11.ts:49:23 http +entry mod11.ts:4:22 http +entry mod11.ts:50:24 http +entry mod11.ts:51:23 http +entry mod11.ts:52:26 http +entry mod11.ts:53:25 http +entry mod11.ts:54:23 http +entry mod11.ts:55:24 http +entry mod11.ts:56:23 http +entry mod11.ts:57:26 http +entry mod11.ts:58:25 http +entry mod11.ts:59:23 http +entry mod11.ts:5:23 http +entry mod11.ts:60:24 http +entry mod11.ts:61:23 http +entry mod11.ts:62:26 http +entry mod11.ts:63:25 http +entry mod11.ts:64:23 http +entry mod11.ts:65:24 http +entry mod11.ts:66:23 http +entry mod11.ts:67:26 http +entry mod11.ts:68:25 http +entry mod11.ts:69:23 http +entry mod11.ts:6:22 http +entry mod11.ts:70:24 http +entry mod11.ts:71:23 http +entry mod11.ts:72:26 http +entry mod11.ts:73:25 http +entry mod11.ts:74:23 http +entry mod11.ts:75:24 http +entry mod11.ts:76:23 http +entry mod11.ts:77:26 http +entry mod11.ts:78:25 http +entry mod11.ts:79:23 http +entry mod11.ts:7:25 http +entry mod11.ts:80:24 http +entry mod11.ts:81:23 http +entry mod11.ts:82:26 http +entry mod11.ts:83:25 http +entry mod11.ts:84:23 http +entry mod11.ts:85:24 http +entry mod11.ts:86:23 http +entry mod11.ts:87:26 http +entry mod11.ts:88:25 http +entry mod11.ts:89:23 http +entry mod11.ts:8:24 http +entry mod11.ts:90:24 http +entry mod11.ts:91:23 http +entry mod11.ts:92:26 http +entry mod11.ts:93:25 http +entry mod11.ts:94:23 http +entry mod11.ts:95:24 http +entry mod11.ts:96:23 http +entry mod11.ts:97:26 http +entry mod11.ts:98:25 http +entry mod11.ts:99:23 http +entry mod11.ts:9:22 http +entry mod12.ts:100:24 http +entry mod12.ts:101:23 http +entry mod12.ts:102:26 http +entry mod12.ts:103:25 http +entry mod12.ts:10:23 http +entry mod12.ts:11:22 http +entry mod12.ts:12:25 http +entry mod12.ts:13:24 http +entry mod12.ts:14:23 http +entry mod12.ts:15:24 http +entry mod12.ts:16:23 http +entry mod12.ts:17:26 http +entry mod12.ts:18:25 http +entry mod12.ts:19:23 http +entry mod12.ts:20:24 http +entry mod12.ts:21:23 http +entry mod12.ts:22:26 http +entry mod12.ts:23:25 http +entry mod12.ts:24:23 http +entry mod12.ts:25:24 http +entry mod12.ts:26:23 http +entry mod12.ts:27:26 http +entry mod12.ts:28:25 http +entry mod12.ts:29:23 http +entry mod12.ts:30:24 http +entry mod12.ts:31:23 http +entry mod12.ts:32:26 http +entry mod12.ts:33:25 http +entry mod12.ts:34:23 http +entry mod12.ts:35:24 http +entry mod12.ts:36:23 http +entry mod12.ts:37:26 http +entry mod12.ts:38:25 http +entry mod12.ts:39:23 http +entry mod12.ts:40:24 http +entry mod12.ts:41:23 http +entry mod12.ts:42:26 http +entry mod12.ts:43:25 http +entry mod12.ts:44:23 http +entry mod12.ts:45:24 http +entry mod12.ts:46:23 http +entry mod12.ts:47:26 http +entry mod12.ts:48:25 http +entry mod12.ts:49:23 http +entry mod12.ts:4:22 http +entry mod12.ts:50:24 http +entry mod12.ts:51:23 http +entry mod12.ts:52:26 http +entry mod12.ts:53:25 http +entry mod12.ts:54:23 http +entry mod12.ts:55:24 http +entry mod12.ts:56:23 http +entry mod12.ts:57:26 http +entry mod12.ts:58:25 http +entry mod12.ts:59:23 http +entry mod12.ts:5:23 http +entry mod12.ts:60:24 http +entry mod12.ts:61:23 http +entry mod12.ts:62:26 http +entry mod12.ts:63:25 http +entry mod12.ts:64:23 http +entry mod12.ts:65:24 http +entry mod12.ts:66:23 http +entry mod12.ts:67:26 http +entry mod12.ts:68:25 http +entry mod12.ts:69:23 http +entry mod12.ts:6:22 http +entry mod12.ts:70:24 http +entry mod12.ts:71:23 http +entry mod12.ts:72:26 http +entry mod12.ts:73:25 http +entry mod12.ts:74:23 http +entry mod12.ts:75:24 http +entry mod12.ts:76:23 http +entry mod12.ts:77:26 http +entry mod12.ts:78:25 http +entry mod12.ts:79:23 http +entry mod12.ts:7:25 http +entry mod12.ts:80:24 http +entry mod12.ts:81:23 http +entry mod12.ts:82:26 http +entry mod12.ts:83:25 http +entry mod12.ts:84:23 http +entry mod12.ts:85:24 http +entry mod12.ts:86:23 http +entry mod12.ts:87:26 http +entry mod12.ts:88:25 http +entry mod12.ts:89:23 http +entry mod12.ts:8:24 http +entry mod12.ts:90:24 http +entry mod12.ts:91:23 http +entry mod12.ts:92:26 http +entry mod12.ts:93:25 http +entry mod12.ts:94:23 http +entry mod12.ts:95:24 http +entry mod12.ts:96:23 http +entry mod12.ts:97:26 http +entry mod12.ts:98:25 http +entry mod12.ts:99:23 http +entry mod12.ts:9:22 http +entry mod13.ts:100:24 http +entry mod13.ts:101:23 http +entry mod13.ts:102:26 http +entry mod13.ts:103:25 http +entry mod13.ts:10:23 http +entry mod13.ts:11:22 http +entry mod13.ts:12:25 http +entry mod13.ts:13:24 http +entry mod13.ts:14:23 http +entry mod13.ts:15:24 http +entry mod13.ts:16:23 http +entry mod13.ts:17:26 http +entry mod13.ts:18:25 http +entry mod13.ts:19:23 http +entry mod13.ts:20:24 http +entry mod13.ts:21:23 http +entry mod13.ts:22:26 http +entry mod13.ts:23:25 http +entry mod13.ts:24:23 http +entry mod13.ts:25:24 http +entry mod13.ts:26:23 http +entry mod13.ts:27:26 http +entry mod13.ts:28:25 http +entry mod13.ts:29:23 http +entry mod13.ts:30:24 http +entry mod13.ts:31:23 http +entry mod13.ts:32:26 http +entry mod13.ts:33:25 http +entry mod13.ts:34:23 http +entry mod13.ts:35:24 http +entry mod13.ts:36:23 http +entry mod13.ts:37:26 http +entry mod13.ts:38:25 http +entry mod13.ts:39:23 http +entry mod13.ts:40:24 http +entry mod13.ts:41:23 http +entry mod13.ts:42:26 http +entry mod13.ts:43:25 http +entry mod13.ts:44:23 http +entry mod13.ts:45:24 http +entry mod13.ts:46:23 http +entry mod13.ts:47:26 http +entry mod13.ts:48:25 http +entry mod13.ts:49:23 http +entry mod13.ts:4:22 http +entry mod13.ts:50:24 http +entry mod13.ts:51:23 http +entry mod13.ts:52:26 http +entry mod13.ts:53:25 http +entry mod13.ts:54:23 http +entry mod13.ts:55:24 http +entry mod13.ts:56:23 http +entry mod13.ts:57:26 http +entry mod13.ts:58:25 http +entry mod13.ts:59:23 http +entry mod13.ts:5:23 http +entry mod13.ts:60:24 http +entry mod13.ts:61:23 http +entry mod13.ts:62:26 http +entry mod13.ts:63:25 http +entry mod13.ts:64:23 http +entry mod13.ts:65:24 http +entry mod13.ts:66:23 http +entry mod13.ts:67:26 http +entry mod13.ts:68:25 http +entry mod13.ts:69:23 http +entry mod13.ts:6:22 http +entry mod13.ts:70:24 http +entry mod13.ts:71:23 http +entry mod13.ts:72:26 http +entry mod13.ts:73:25 http +entry mod13.ts:74:23 http +entry mod13.ts:75:24 http +entry mod13.ts:76:23 http +entry mod13.ts:77:26 http +entry mod13.ts:78:25 http +entry mod13.ts:79:23 http +entry mod13.ts:7:25 http +entry mod13.ts:80:24 http +entry mod13.ts:81:23 http +entry mod13.ts:82:26 http +entry mod13.ts:83:25 http +entry mod13.ts:84:23 http +entry mod13.ts:85:24 http +entry mod13.ts:86:23 http +entry mod13.ts:87:26 http +entry mod13.ts:88:25 http +entry mod13.ts:89:23 http +entry mod13.ts:8:24 http +entry mod13.ts:90:24 http +entry mod13.ts:91:23 http +entry mod13.ts:92:26 http +entry mod13.ts:93:25 http +entry mod13.ts:94:23 http +entry mod13.ts:95:24 http +entry mod13.ts:96:23 http +entry mod13.ts:97:26 http +entry mod13.ts:98:25 http +entry mod13.ts:99:23 http +entry mod13.ts:9:22 http +entry mod14.ts:100:24 http +entry mod14.ts:101:23 http +entry mod14.ts:102:26 http +entry mod14.ts:103:25 http +entry mod14.ts:10:23 http +entry mod14.ts:11:22 http +entry mod14.ts:12:25 http +entry mod14.ts:13:24 http +entry mod14.ts:14:23 http +entry mod14.ts:15:24 http +entry mod14.ts:16:23 http +entry mod14.ts:17:26 http +entry mod14.ts:18:25 http +entry mod14.ts:19:23 http +entry mod14.ts:20:24 http +entry mod14.ts:21:23 http +entry mod14.ts:22:26 http +entry mod14.ts:23:25 http +entry mod14.ts:24:23 http +entry mod14.ts:25:24 http +entry mod14.ts:26:23 http +entry mod14.ts:27:26 http +entry mod14.ts:28:25 http +entry mod14.ts:29:23 http +entry mod14.ts:30:24 http +entry mod14.ts:31:23 http +entry mod14.ts:32:26 http +entry mod14.ts:33:25 http +entry mod14.ts:34:23 http +entry mod14.ts:35:24 http +entry mod14.ts:36:23 http +entry mod14.ts:37:26 http +entry mod14.ts:38:25 http +entry mod14.ts:39:23 http +entry mod14.ts:40:24 http +entry mod14.ts:41:23 http +entry mod14.ts:42:26 http +entry mod14.ts:43:25 http +entry mod14.ts:44:23 http +entry mod14.ts:45:24 http +entry mod14.ts:46:23 http +entry mod14.ts:47:26 http +entry mod14.ts:48:25 http +entry mod14.ts:49:23 http +entry mod14.ts:4:22 http +entry mod14.ts:50:24 http +entry mod14.ts:51:23 http +entry mod14.ts:52:26 http +entry mod14.ts:53:25 http +entry mod14.ts:54:23 http +entry mod14.ts:55:24 http +entry mod14.ts:56:23 http +entry mod14.ts:57:26 http +entry mod14.ts:58:25 http +entry mod14.ts:59:23 http +entry mod14.ts:5:23 http +entry mod14.ts:60:24 http +entry mod14.ts:61:23 http +entry mod14.ts:62:26 http +entry mod14.ts:63:25 http +entry mod14.ts:64:23 http +entry mod14.ts:65:24 http +entry mod14.ts:66:23 http +entry mod14.ts:67:26 http +entry mod14.ts:68:25 http +entry mod14.ts:69:23 http +entry mod14.ts:6:22 http +entry mod14.ts:70:24 http +entry mod14.ts:71:23 http +entry mod14.ts:72:26 http +entry mod14.ts:73:25 http +entry mod14.ts:74:23 http +entry mod14.ts:75:24 http +entry mod14.ts:76:23 http +entry mod14.ts:77:26 http +entry mod14.ts:78:25 http +entry mod14.ts:79:23 http +entry mod14.ts:7:25 http +entry mod14.ts:80:24 http +entry mod14.ts:81:23 http +entry mod14.ts:82:26 http +entry mod14.ts:83:25 http +entry mod14.ts:84:23 http +entry mod14.ts:85:24 http +entry mod14.ts:86:23 http +entry mod14.ts:87:26 http +entry mod14.ts:88:25 http +entry mod14.ts:89:23 http +entry mod14.ts:8:24 http +entry mod14.ts:90:24 http +entry mod14.ts:91:23 http +entry mod14.ts:92:26 http +entry mod14.ts:93:25 http +entry mod14.ts:94:23 http +entry mod14.ts:95:24 http +entry mod14.ts:96:23 http +entry mod14.ts:97:26 http +entry mod14.ts:98:25 http +entry mod14.ts:99:23 http +entry mod14.ts:9:22 http +entry mod15.ts:100:24 http +entry mod15.ts:101:23 http +entry mod15.ts:102:26 http +entry mod15.ts:103:25 http +entry mod15.ts:10:23 http +entry mod15.ts:11:22 http +entry mod15.ts:12:25 http +entry mod15.ts:13:24 http +entry mod15.ts:14:23 http +entry mod15.ts:15:24 http +entry mod15.ts:16:23 http +entry mod15.ts:17:26 http +entry mod15.ts:18:25 http +entry mod15.ts:19:23 http +entry mod15.ts:20:24 http +entry mod15.ts:21:23 http +entry mod15.ts:22:26 http +entry mod15.ts:23:25 http +entry mod15.ts:24:23 http +entry mod15.ts:25:24 http +entry mod15.ts:26:23 http +entry mod15.ts:27:26 http +entry mod15.ts:28:25 http +entry mod15.ts:29:23 http +entry mod15.ts:30:24 http +entry mod15.ts:31:23 http +entry mod15.ts:32:26 http +entry mod15.ts:33:25 http +entry mod15.ts:34:23 http +entry mod15.ts:35:24 http +entry mod15.ts:36:23 http +entry mod15.ts:37:26 http +entry mod15.ts:38:25 http +entry mod15.ts:39:23 http +entry mod15.ts:40:24 http +entry mod15.ts:41:23 http +entry mod15.ts:42:26 http +entry mod15.ts:43:25 http +entry mod15.ts:44:23 http +entry mod15.ts:45:24 http +entry mod15.ts:46:23 http +entry mod15.ts:47:26 http +entry mod15.ts:48:25 http +entry mod15.ts:49:23 http +entry mod15.ts:4:22 http +entry mod15.ts:50:24 http +entry mod15.ts:51:23 http +entry mod15.ts:52:26 http +entry mod15.ts:53:25 http +entry mod15.ts:54:23 http +entry mod15.ts:55:24 http +entry mod15.ts:56:23 http +entry mod15.ts:57:26 http +entry mod15.ts:58:25 http +entry mod15.ts:59:23 http +entry mod15.ts:5:23 http +entry mod15.ts:60:24 http +entry mod15.ts:61:23 http +entry mod15.ts:62:26 http +entry mod15.ts:63:25 http +entry mod15.ts:64:23 http +entry mod15.ts:65:24 http +entry mod15.ts:66:23 http +entry mod15.ts:67:26 http +entry mod15.ts:68:25 http +entry mod15.ts:69:23 http +entry mod15.ts:6:22 http +entry mod15.ts:70:24 http +entry mod15.ts:71:23 http +entry mod15.ts:72:26 http +entry mod15.ts:73:25 http +entry mod15.ts:74:23 http +entry mod15.ts:75:24 http +entry mod15.ts:76:23 http +entry mod15.ts:77:26 http +entry mod15.ts:78:25 http +entry mod15.ts:79:23 http +entry mod15.ts:7:25 http +entry mod15.ts:80:24 http +entry mod15.ts:81:23 http +entry mod15.ts:82:26 http +entry mod15.ts:83:25 http +entry mod15.ts:84:23 http +entry mod15.ts:85:24 http +entry mod15.ts:86:23 http +entry mod15.ts:87:26 http +entry mod15.ts:88:25 http +entry mod15.ts:89:23 http +entry mod15.ts:8:24 http +entry mod15.ts:90:24 http +entry mod15.ts:91:23 http +entry mod15.ts:92:26 http +entry mod15.ts:93:25 http +entry mod15.ts:94:23 http +entry mod15.ts:95:24 http +entry mod15.ts:96:23 http +entry mod15.ts:97:26 http +entry mod15.ts:98:25 http +entry mod15.ts:99:23 http +entry mod15.ts:9:22 http +entry mod16.ts:100:24 http +entry mod16.ts:101:23 http +entry mod16.ts:102:26 http +entry mod16.ts:103:25 http +entry mod16.ts:10:23 http +entry mod16.ts:11:22 http +entry mod16.ts:12:25 http +entry mod16.ts:13:24 http +entry mod16.ts:14:23 http +entry mod16.ts:15:24 http +entry mod16.ts:16:23 http +entry mod16.ts:17:26 http +entry mod16.ts:18:25 http +entry mod16.ts:19:23 http +entry mod16.ts:20:24 http +entry mod16.ts:21:23 http +entry mod16.ts:22:26 http +entry mod16.ts:23:25 http +entry mod16.ts:24:23 http +entry mod16.ts:25:24 http +entry mod16.ts:26:23 http +entry mod16.ts:27:26 http +entry mod16.ts:28:25 http +entry mod16.ts:29:23 http +entry mod16.ts:30:24 http +entry mod16.ts:31:23 http +entry mod16.ts:32:26 http +entry mod16.ts:33:25 http +entry mod16.ts:34:23 http +entry mod16.ts:35:24 http +entry mod16.ts:36:23 http +entry mod16.ts:37:26 http +entry mod16.ts:38:25 http +entry mod16.ts:39:23 http +entry mod16.ts:40:24 http +entry mod16.ts:41:23 http +entry mod16.ts:42:26 http +entry mod16.ts:43:25 http +entry mod16.ts:44:23 http +entry mod16.ts:45:24 http +entry mod16.ts:46:23 http +entry mod16.ts:47:26 http +entry mod16.ts:48:25 http +entry mod16.ts:49:23 http +entry mod16.ts:4:22 http +entry mod16.ts:50:24 http +entry mod16.ts:51:23 http +entry mod16.ts:52:26 http +entry mod16.ts:53:25 http +entry mod16.ts:54:23 http +entry mod16.ts:55:24 http +entry mod16.ts:56:23 http +entry mod16.ts:57:26 http +entry mod16.ts:58:25 http +entry mod16.ts:59:23 http +entry mod16.ts:5:23 http +entry mod16.ts:60:24 http +entry mod16.ts:61:23 http +entry mod16.ts:62:26 http +entry mod16.ts:63:25 http +entry mod16.ts:64:23 http +entry mod16.ts:65:24 http +entry mod16.ts:66:23 http +entry mod16.ts:67:26 http +entry mod16.ts:68:25 http +entry mod16.ts:69:23 http +entry mod16.ts:6:22 http +entry mod16.ts:70:24 http +entry mod16.ts:71:23 http +entry mod16.ts:72:26 http +entry mod16.ts:73:25 http +entry mod16.ts:74:23 http +entry mod16.ts:75:24 http +entry mod16.ts:76:23 http +entry mod16.ts:77:26 http +entry mod16.ts:78:25 http +entry mod16.ts:79:23 http +entry mod16.ts:7:25 http +entry mod16.ts:80:24 http +entry mod16.ts:81:23 http +entry mod16.ts:82:26 http +entry mod16.ts:83:25 http +entry mod16.ts:84:23 http +entry mod16.ts:85:24 http +entry mod16.ts:86:23 http +entry mod16.ts:87:26 http +entry mod16.ts:88:25 http +entry mod16.ts:89:23 http +entry mod16.ts:8:24 http +entry mod16.ts:90:24 http +entry mod16.ts:91:23 http +entry mod16.ts:92:26 http +entry mod16.ts:93:25 http +entry mod16.ts:94:23 http +entry mod16.ts:95:24 http +entry mod16.ts:96:23 http +entry mod16.ts:97:26 http +entry mod16.ts:98:25 http +entry mod16.ts:99:23 http +entry mod16.ts:9:22 http +entry mod17.ts:100:24 http +entry mod17.ts:101:23 http +entry mod17.ts:102:26 http +entry mod17.ts:103:25 http +entry mod17.ts:10:23 http +entry mod17.ts:11:22 http +entry mod17.ts:12:25 http +entry mod17.ts:13:24 http +entry mod17.ts:14:23 http +entry mod17.ts:15:24 http +entry mod17.ts:16:23 http +entry mod17.ts:17:26 http +entry mod17.ts:18:25 http +entry mod17.ts:19:23 http +entry mod17.ts:20:24 http +entry mod17.ts:21:23 http +entry mod17.ts:22:26 http +entry mod17.ts:23:25 http +entry mod17.ts:24:23 http +entry mod17.ts:25:24 http +entry mod17.ts:26:23 http +entry mod17.ts:27:26 http +entry mod17.ts:28:25 http +entry mod17.ts:29:23 http +entry mod17.ts:30:24 http +entry mod17.ts:31:23 http +entry mod17.ts:32:26 http +entry mod17.ts:33:25 http +entry mod17.ts:34:23 http +entry mod17.ts:35:24 http +entry mod17.ts:36:23 http +entry mod17.ts:37:26 http +entry mod17.ts:38:25 http +entry mod17.ts:39:23 http +entry mod17.ts:40:24 http +entry mod17.ts:41:23 http +entry mod17.ts:42:26 http +entry mod17.ts:43:25 http +entry mod17.ts:44:23 http +entry mod17.ts:45:24 http +entry mod17.ts:46:23 http +entry mod17.ts:47:26 http +entry mod17.ts:48:25 http +entry mod17.ts:49:23 http +entry mod17.ts:4:22 http +entry mod17.ts:50:24 http +entry mod17.ts:51:23 http +entry mod17.ts:52:26 http +entry mod17.ts:53:25 http +entry mod17.ts:54:23 http +entry mod17.ts:55:24 http +entry mod17.ts:56:23 http +entry mod17.ts:57:26 http +entry mod17.ts:58:25 http +entry mod17.ts:59:23 http +entry mod17.ts:5:23 http +entry mod17.ts:60:24 http +entry mod17.ts:61:23 http +entry mod17.ts:62:26 http +entry mod17.ts:63:25 http +entry mod17.ts:64:23 http +entry mod17.ts:65:24 http +entry mod17.ts:66:23 http +entry mod17.ts:67:26 http +entry mod17.ts:68:25 http +entry mod17.ts:69:23 http +entry mod17.ts:6:22 http +entry mod17.ts:70:24 http +entry mod17.ts:71:23 http +entry mod17.ts:72:26 http +entry mod17.ts:73:25 http +entry mod17.ts:74:23 http +entry mod17.ts:75:24 http +entry mod17.ts:76:23 http +entry mod17.ts:77:26 http +entry mod17.ts:78:25 http +entry mod17.ts:79:23 http +entry mod17.ts:7:25 http +entry mod17.ts:80:24 http +entry mod17.ts:81:23 http +entry mod17.ts:82:26 http +entry mod17.ts:83:25 http +entry mod17.ts:84:23 http +entry mod17.ts:85:24 http +entry mod17.ts:86:23 http +entry mod17.ts:87:26 http +entry mod17.ts:88:25 http +entry mod17.ts:89:23 http +entry mod17.ts:8:24 http +entry mod17.ts:90:24 http +entry mod17.ts:91:23 http +entry mod17.ts:92:26 http +entry mod17.ts:93:25 http +entry mod17.ts:94:23 http +entry mod17.ts:95:24 http +entry mod17.ts:96:23 http +entry mod17.ts:97:26 http +entry mod17.ts:98:25 http +entry mod17.ts:99:23 http +entry mod17.ts:9:22 http +entry mod18.ts:100:24 http +entry mod18.ts:101:23 http +entry mod18.ts:102:26 http +entry mod18.ts:103:25 http +entry mod18.ts:10:23 http +entry mod18.ts:11:22 http +entry mod18.ts:12:25 http +entry mod18.ts:13:24 http +entry mod18.ts:14:23 http +entry mod18.ts:15:24 http +entry mod18.ts:16:23 http +entry mod18.ts:17:26 http +entry mod18.ts:18:25 http +entry mod18.ts:19:23 http +entry mod18.ts:20:24 http +entry mod18.ts:21:23 http +entry mod18.ts:22:26 http +entry mod18.ts:23:25 http +entry mod18.ts:24:23 http +entry mod18.ts:25:24 http +entry mod18.ts:26:23 http +entry mod18.ts:27:26 http +entry mod18.ts:28:25 http +entry mod18.ts:29:23 http +entry mod18.ts:30:24 http +entry mod18.ts:31:23 http +entry mod18.ts:32:26 http +entry mod18.ts:33:25 http +entry mod18.ts:34:23 http +entry mod18.ts:35:24 http +entry mod18.ts:36:23 http +entry mod18.ts:37:26 http +entry mod18.ts:38:25 http +entry mod18.ts:39:23 http +entry mod18.ts:40:24 http +entry mod18.ts:41:23 http +entry mod18.ts:42:26 http +entry mod18.ts:43:25 http +entry mod18.ts:44:23 http +entry mod18.ts:45:24 http +entry mod18.ts:46:23 http +entry mod18.ts:47:26 http +entry mod18.ts:48:25 http +entry mod18.ts:49:23 http +entry mod18.ts:4:22 http +entry mod18.ts:50:24 http +entry mod18.ts:51:23 http +entry mod18.ts:52:26 http +entry mod18.ts:53:25 http +entry mod18.ts:54:23 http +entry mod18.ts:55:24 http +entry mod18.ts:56:23 http +entry mod18.ts:57:26 http +entry mod18.ts:58:25 http +entry mod18.ts:59:23 http +entry mod18.ts:5:23 http +entry mod18.ts:60:24 http +entry mod18.ts:61:23 http +entry mod18.ts:62:26 http +entry mod18.ts:63:25 http +entry mod18.ts:64:23 http +entry mod18.ts:65:24 http +entry mod18.ts:66:23 http +entry mod18.ts:67:26 http +entry mod18.ts:68:25 http +entry mod18.ts:69:23 http +entry mod18.ts:6:22 http +entry mod18.ts:70:24 http +entry mod18.ts:71:23 http +entry mod18.ts:72:26 http +entry mod18.ts:73:25 http +entry mod18.ts:74:23 http +entry mod18.ts:75:24 http +entry mod18.ts:76:23 http +entry mod18.ts:77:26 http +entry mod18.ts:78:25 http +entry mod18.ts:79:23 http +entry mod18.ts:7:25 http +entry mod18.ts:80:24 http +entry mod18.ts:81:23 http +entry mod18.ts:82:26 http +entry mod18.ts:83:25 http +entry mod18.ts:84:23 http +entry mod18.ts:85:24 http +entry mod18.ts:86:23 http +entry mod18.ts:87:26 http +entry mod18.ts:88:25 http +entry mod18.ts:89:23 http +entry mod18.ts:8:24 http +entry mod18.ts:90:24 http +entry mod18.ts:91:23 http +entry mod18.ts:92:26 http +entry mod18.ts:93:25 http +entry mod18.ts:94:23 http +entry mod18.ts:95:24 http +entry mod18.ts:96:23 http +entry mod18.ts:97:26 http +entry mod18.ts:98:25 http +entry mod18.ts:99:23 http +entry mod18.ts:9:22 http +entry mod19.ts:100:24 http +entry mod19.ts:101:23 http +entry mod19.ts:102:26 http +entry mod19.ts:103:25 http +entry mod19.ts:10:23 http +entry mod19.ts:11:22 http +entry mod19.ts:12:25 http +entry mod19.ts:13:24 http +entry mod19.ts:14:23 http +entry mod19.ts:15:24 http +entry mod19.ts:16:23 http +entry mod19.ts:17:26 http +entry mod19.ts:18:25 http +entry mod19.ts:19:23 http +entry mod19.ts:20:24 http +entry mod19.ts:21:23 http +entry mod19.ts:22:26 http +entry mod19.ts:23:25 http +entry mod19.ts:24:23 http +entry mod19.ts:25:24 http +entry mod19.ts:26:23 http +entry mod19.ts:27:26 http +entry mod19.ts:28:25 http +entry mod19.ts:29:23 http +entry mod19.ts:30:24 http +entry mod19.ts:31:23 http +entry mod19.ts:32:26 http +entry mod19.ts:33:25 http +entry mod19.ts:34:23 http +entry mod19.ts:35:24 http +entry mod19.ts:36:23 http +entry mod19.ts:37:26 http +entry mod19.ts:38:25 http +entry mod19.ts:39:23 http +entry mod19.ts:40:24 http +entry mod19.ts:41:23 http +entry mod19.ts:42:26 http +entry mod19.ts:43:25 http +entry mod19.ts:44:23 http +entry mod19.ts:45:24 http +entry mod19.ts:46:23 http +entry mod19.ts:47:26 http +entry mod19.ts:48:25 http +entry mod19.ts:49:23 http +entry mod19.ts:4:22 http +entry mod19.ts:50:24 http +entry mod19.ts:51:23 http +entry mod19.ts:52:26 http +entry mod19.ts:53:25 http +entry mod19.ts:54:23 http +entry mod19.ts:55:24 http +entry mod19.ts:56:23 http +entry mod19.ts:57:26 http +entry mod19.ts:58:25 http +entry mod19.ts:59:23 http +entry mod19.ts:5:23 http +entry mod19.ts:60:24 http +entry mod19.ts:61:23 http +entry mod19.ts:62:26 http +entry mod19.ts:63:25 http +entry mod19.ts:64:23 http +entry mod19.ts:65:24 http +entry mod19.ts:66:23 http +entry mod19.ts:67:26 http +entry mod19.ts:68:25 http +entry mod19.ts:69:23 http +entry mod19.ts:6:22 http +entry mod19.ts:70:24 http +entry mod19.ts:71:23 http +entry mod19.ts:72:26 http +entry mod19.ts:73:25 http +entry mod19.ts:74:23 http +entry mod19.ts:75:24 http +entry mod19.ts:76:23 http +entry mod19.ts:77:26 http +entry mod19.ts:78:25 http +entry mod19.ts:79:23 http +entry mod19.ts:7:25 http +entry mod19.ts:80:24 http +entry mod19.ts:81:23 http +entry mod19.ts:82:26 http +entry mod19.ts:83:25 http +entry mod19.ts:84:23 http +entry mod19.ts:85:24 http +entry mod19.ts:86:23 http +entry mod19.ts:87:26 http +entry mod19.ts:88:25 http +entry mod19.ts:89:23 http +entry mod19.ts:8:24 http +entry mod19.ts:90:24 http +entry mod19.ts:91:23 http +entry mod19.ts:92:26 http +entry mod19.ts:93:25 http +entry mod19.ts:94:23 http +entry mod19.ts:95:24 http +entry mod19.ts:96:23 http +entry mod19.ts:97:26 http +entry mod19.ts:98:25 http +entry mod19.ts:99:23 http +entry mod19.ts:9:22 http +entry mod2.ts:100:23 http +entry mod2.ts:101:22 http +entry mod2.ts:102:25 http +entry mod2.ts:103:24 http +entry mod2.ts:10:22 http +entry mod2.ts:11:21 http +entry mod2.ts:12:24 http +entry mod2.ts:13:23 http +entry mod2.ts:14:22 http +entry mod2.ts:15:23 http +entry mod2.ts:16:22 http +entry mod2.ts:17:25 http +entry mod2.ts:18:24 http +entry mod2.ts:19:22 http +entry mod2.ts:20:23 http +entry mod2.ts:21:22 http +entry mod2.ts:22:25 http +entry mod2.ts:23:24 http +entry mod2.ts:24:22 http +entry mod2.ts:25:23 http +entry mod2.ts:26:22 http +entry mod2.ts:27:25 http +entry mod2.ts:28:24 http +entry mod2.ts:29:22 http +entry mod2.ts:30:23 http +entry mod2.ts:31:22 http +entry mod2.ts:32:25 http +entry mod2.ts:33:24 http +entry mod2.ts:34:22 http +entry mod2.ts:35:23 http +entry mod2.ts:36:22 http +entry mod2.ts:37:25 http +entry mod2.ts:38:24 http +entry mod2.ts:39:22 http +entry mod2.ts:40:23 http +entry mod2.ts:41:22 http +entry mod2.ts:42:25 http +entry mod2.ts:43:24 http +entry mod2.ts:44:22 http +entry mod2.ts:45:23 http +entry mod2.ts:46:22 http +entry mod2.ts:47:25 http +entry mod2.ts:48:24 http +entry mod2.ts:49:22 http +entry mod2.ts:4:21 http +entry mod2.ts:50:23 http +entry mod2.ts:51:22 http +entry mod2.ts:52:25 http +entry mod2.ts:53:24 http +entry mod2.ts:54:22 http +entry mod2.ts:55:23 http +entry mod2.ts:56:22 http +entry mod2.ts:57:25 http +entry mod2.ts:58:24 http +entry mod2.ts:59:22 http +entry mod2.ts:5:22 http +entry mod2.ts:60:23 http +entry mod2.ts:61:22 http +entry mod2.ts:62:25 http +entry mod2.ts:63:24 http +entry mod2.ts:64:22 http +entry mod2.ts:65:23 http +entry mod2.ts:66:22 http +entry mod2.ts:67:25 http +entry mod2.ts:68:24 http +entry mod2.ts:69:22 http +entry mod2.ts:6:21 http +entry mod2.ts:70:23 http +entry mod2.ts:71:22 http +entry mod2.ts:72:25 http +entry mod2.ts:73:24 http +entry mod2.ts:74:22 http +entry mod2.ts:75:23 http +entry mod2.ts:76:22 http +entry mod2.ts:77:25 http +entry mod2.ts:78:24 http +entry mod2.ts:79:22 http +entry mod2.ts:7:24 http +entry mod2.ts:80:23 http +entry mod2.ts:81:22 http +entry mod2.ts:82:25 http +entry mod2.ts:83:24 http +entry mod2.ts:84:22 http +entry mod2.ts:85:23 http +entry mod2.ts:86:22 http +entry mod2.ts:87:25 http +entry mod2.ts:88:24 http +entry mod2.ts:89:22 http +entry mod2.ts:8:23 http +entry mod2.ts:90:23 http +entry mod2.ts:91:22 http +entry mod2.ts:92:25 http +entry mod2.ts:93:24 http +entry mod2.ts:94:22 http +entry mod2.ts:95:23 http +entry mod2.ts:96:22 http +entry mod2.ts:97:25 http +entry mod2.ts:98:24 http +entry mod2.ts:99:22 http +entry mod2.ts:9:21 http +entry mod3.ts:100:23 http +entry mod3.ts:101:22 http +entry mod3.ts:102:25 http +entry mod3.ts:103:24 http +entry mod3.ts:10:22 http +entry mod3.ts:11:21 http +entry mod3.ts:12:24 http +entry mod3.ts:13:23 http +entry mod3.ts:14:22 http +entry mod3.ts:15:23 http +entry mod3.ts:16:22 http +entry mod3.ts:17:25 http +entry mod3.ts:18:24 http +entry mod3.ts:19:22 http +entry mod3.ts:20:23 http +entry mod3.ts:21:22 http +entry mod3.ts:22:25 http +entry mod3.ts:23:24 http +entry mod3.ts:24:22 http +entry mod3.ts:25:23 http +entry mod3.ts:26:22 http +entry mod3.ts:27:25 http +entry mod3.ts:28:24 http +entry mod3.ts:29:22 http +entry mod3.ts:30:23 http +entry mod3.ts:31:22 http +entry mod3.ts:32:25 http +entry mod3.ts:33:24 http +entry mod3.ts:34:22 http +entry mod3.ts:35:23 http +entry mod3.ts:36:22 http +entry mod3.ts:37:25 http +entry mod3.ts:38:24 http +entry mod3.ts:39:22 http +entry mod3.ts:40:23 http +entry mod3.ts:41:22 http +entry mod3.ts:42:25 http +entry mod3.ts:43:24 http +entry mod3.ts:44:22 http +entry mod3.ts:45:23 http +entry mod3.ts:46:22 http +entry mod3.ts:47:25 http +entry mod3.ts:48:24 http +entry mod3.ts:49:22 http +entry mod3.ts:4:21 http +entry mod3.ts:50:23 http +entry mod3.ts:51:22 http +entry mod3.ts:52:25 http +entry mod3.ts:53:24 http +entry mod3.ts:54:22 http +entry mod3.ts:55:23 http +entry mod3.ts:56:22 http +entry mod3.ts:57:25 http +entry mod3.ts:58:24 http +entry mod3.ts:59:22 http +entry mod3.ts:5:22 http +entry mod3.ts:60:23 http +entry mod3.ts:61:22 http +entry mod3.ts:62:25 http +entry mod3.ts:63:24 http +entry mod3.ts:64:22 http +entry mod3.ts:65:23 http +entry mod3.ts:66:22 http +entry mod3.ts:67:25 http +entry mod3.ts:68:24 http +entry mod3.ts:69:22 http +entry mod3.ts:6:21 http +entry mod3.ts:70:23 http +entry mod3.ts:71:22 http +entry mod3.ts:72:25 http +entry mod3.ts:73:24 http +entry mod3.ts:74:22 http +entry mod3.ts:75:23 http +entry mod3.ts:76:22 http +entry mod3.ts:77:25 http +entry mod3.ts:78:24 http +entry mod3.ts:79:22 http +entry mod3.ts:7:24 http +entry mod3.ts:80:23 http +entry mod3.ts:81:22 http +entry mod3.ts:82:25 http +entry mod3.ts:83:24 http +entry mod3.ts:84:22 http +entry mod3.ts:85:23 http +entry mod3.ts:86:22 http +entry mod3.ts:87:25 http +entry mod3.ts:88:24 http +entry mod3.ts:89:22 http +entry mod3.ts:8:23 http +entry mod3.ts:90:23 http +entry mod3.ts:91:22 http +entry mod3.ts:92:25 http +entry mod3.ts:93:24 http +entry mod3.ts:94:22 http +entry mod3.ts:95:23 http +entry mod3.ts:96:22 http +entry mod3.ts:97:25 http +entry mod3.ts:98:24 http +entry mod3.ts:99:22 http +entry mod3.ts:9:21 http +entry mod4.ts:100:23 http +entry mod4.ts:101:22 http +entry mod4.ts:102:25 http +entry mod4.ts:103:24 http +entry mod4.ts:10:22 http +entry mod4.ts:11:21 http +entry mod4.ts:12:24 http +entry mod4.ts:13:23 http +entry mod4.ts:14:22 http +entry mod4.ts:15:23 http +entry mod4.ts:16:22 http +entry mod4.ts:17:25 http +entry mod4.ts:18:24 http +entry mod4.ts:19:22 http +entry mod4.ts:20:23 http +entry mod4.ts:21:22 http +entry mod4.ts:22:25 http +entry mod4.ts:23:24 http +entry mod4.ts:24:22 http +entry mod4.ts:25:23 http +entry mod4.ts:26:22 http +entry mod4.ts:27:25 http +entry mod4.ts:28:24 http +entry mod4.ts:29:22 http +entry mod4.ts:30:23 http +entry mod4.ts:31:22 http +entry mod4.ts:32:25 http +entry mod4.ts:33:24 http +entry mod4.ts:34:22 http +entry mod4.ts:35:23 http +entry mod4.ts:36:22 http +entry mod4.ts:37:25 http +entry mod4.ts:38:24 http +entry mod4.ts:39:22 http +entry mod4.ts:40:23 http +entry mod4.ts:41:22 http +entry mod4.ts:42:25 http +entry mod4.ts:43:24 http +entry mod4.ts:44:22 http +entry mod4.ts:45:23 http +entry mod4.ts:46:22 http +entry mod4.ts:47:25 http +entry mod4.ts:48:24 http +entry mod4.ts:49:22 http +entry mod4.ts:4:21 http +entry mod4.ts:50:23 http +entry mod4.ts:51:22 http +entry mod4.ts:52:25 http +entry mod4.ts:53:24 http +entry mod4.ts:54:22 http +entry mod4.ts:55:23 http +entry mod4.ts:56:22 http +entry mod4.ts:57:25 http +entry mod4.ts:58:24 http +entry mod4.ts:59:22 http +entry mod4.ts:5:22 http +entry mod4.ts:60:23 http +entry mod4.ts:61:22 http +entry mod4.ts:62:25 http +entry mod4.ts:63:24 http +entry mod4.ts:64:22 http +entry mod4.ts:65:23 http +entry mod4.ts:66:22 http +entry mod4.ts:67:25 http +entry mod4.ts:68:24 http +entry mod4.ts:69:22 http +entry mod4.ts:6:21 http +entry mod4.ts:70:23 http +entry mod4.ts:71:22 http +entry mod4.ts:72:25 http +entry mod4.ts:73:24 http +entry mod4.ts:74:22 http +entry mod4.ts:75:23 http +entry mod4.ts:76:22 http +entry mod4.ts:77:25 http +entry mod4.ts:78:24 http +entry mod4.ts:79:22 http +entry mod4.ts:7:24 http +entry mod4.ts:80:23 http +entry mod4.ts:81:22 http +entry mod4.ts:82:25 http +entry mod4.ts:83:24 http +entry mod4.ts:84:22 http +entry mod4.ts:85:23 http +entry mod4.ts:86:22 http +entry mod4.ts:87:25 http +entry mod4.ts:88:24 http +entry mod4.ts:89:22 http +entry mod4.ts:8:23 http +entry mod4.ts:90:23 http +entry mod4.ts:91:22 http +entry mod4.ts:92:25 http +entry mod4.ts:93:24 http +entry mod4.ts:94:22 http +entry mod4.ts:95:23 http +entry mod4.ts:96:22 http +entry mod4.ts:97:25 http +entry mod4.ts:98:24 http +entry mod4.ts:99:22 http +entry mod4.ts:9:21 http +entry mod5.ts:100:23 http +entry mod5.ts:101:22 http +entry mod5.ts:102:25 http +entry mod5.ts:103:24 http +entry mod5.ts:10:22 http +entry mod5.ts:11:21 http +entry mod5.ts:12:24 http +entry mod5.ts:13:23 http +entry mod5.ts:14:22 http +entry mod5.ts:15:23 http +entry mod5.ts:16:22 http +entry mod5.ts:17:25 http +entry mod5.ts:18:24 http +entry mod5.ts:19:22 http +entry mod5.ts:20:23 http +entry mod5.ts:21:22 http +entry mod5.ts:22:25 http +entry mod5.ts:23:24 http +entry mod5.ts:24:22 http +entry mod5.ts:25:23 http +entry mod5.ts:26:22 http +entry mod5.ts:27:25 http +entry mod5.ts:28:24 http +entry mod5.ts:29:22 http +entry mod5.ts:30:23 http +entry mod5.ts:31:22 http +entry mod5.ts:32:25 http +entry mod5.ts:33:24 http +entry mod5.ts:34:22 http +entry mod5.ts:35:23 http +entry mod5.ts:36:22 http +entry mod5.ts:37:25 http +entry mod5.ts:38:24 http +entry mod5.ts:39:22 http +entry mod5.ts:40:23 http +entry mod5.ts:41:22 http +entry mod5.ts:42:25 http +entry mod5.ts:43:24 http +entry mod5.ts:44:22 http +entry mod5.ts:45:23 http +entry mod5.ts:46:22 http +entry mod5.ts:47:25 http +entry mod5.ts:48:24 http +entry mod5.ts:49:22 http +entry mod5.ts:4:21 http +entry mod5.ts:50:23 http +entry mod5.ts:51:22 http +entry mod5.ts:52:25 http +entry mod5.ts:53:24 http +entry mod5.ts:54:22 http +entry mod5.ts:55:23 http +entry mod5.ts:56:22 http +entry mod5.ts:57:25 http +entry mod5.ts:58:24 http +entry mod5.ts:59:22 http +entry mod5.ts:5:22 http +entry mod5.ts:60:23 http +entry mod5.ts:61:22 http +entry mod5.ts:62:25 http +entry mod5.ts:63:24 http +entry mod5.ts:64:22 http +entry mod5.ts:65:23 http +entry mod5.ts:66:22 http +entry mod5.ts:67:25 http +entry mod5.ts:68:24 http +entry mod5.ts:69:22 http +entry mod5.ts:6:21 http +entry mod5.ts:70:23 http +entry mod5.ts:71:22 http +entry mod5.ts:72:25 http +entry mod5.ts:73:24 http +entry mod5.ts:74:22 http +entry mod5.ts:75:23 http +entry mod5.ts:76:22 http +entry mod5.ts:77:25 http +entry mod5.ts:78:24 http +entry mod5.ts:79:22 http +entry mod5.ts:7:24 http +entry mod5.ts:80:23 http +entry mod5.ts:81:22 http +entry mod5.ts:82:25 http +entry mod5.ts:83:24 http +entry mod5.ts:84:22 http +entry mod5.ts:85:23 http +entry mod5.ts:86:22 http +entry mod5.ts:87:25 http +entry mod5.ts:88:24 http +entry mod5.ts:89:22 http +entry mod5.ts:8:23 http +entry mod5.ts:90:23 http +entry mod5.ts:91:22 http +entry mod5.ts:92:25 http +entry mod5.ts:93:24 http +entry mod5.ts:94:22 http +entry mod5.ts:95:23 http +entry mod5.ts:96:22 http +entry mod5.ts:97:25 http +entry mod5.ts:98:24 http +entry mod5.ts:99:22 http +entry mod5.ts:9:21 http +entry mod6.ts:100:23 http +entry mod6.ts:101:22 http +entry mod6.ts:102:25 http +entry mod6.ts:103:24 http +entry mod6.ts:10:22 http +entry mod6.ts:11:21 http +entry mod6.ts:12:24 http +entry mod6.ts:13:23 http +entry mod6.ts:14:22 http +entry mod6.ts:15:23 http +entry mod6.ts:16:22 http +entry mod6.ts:17:25 http +entry mod6.ts:18:24 http +entry mod6.ts:19:22 http +entry mod6.ts:20:23 http +entry mod6.ts:21:22 http +entry mod6.ts:22:25 http +entry mod6.ts:23:24 http +entry mod6.ts:24:22 http +entry mod6.ts:25:23 http +entry mod6.ts:26:22 http +entry mod6.ts:27:25 http +entry mod6.ts:28:24 http +entry mod6.ts:29:22 http +entry mod6.ts:30:23 http +entry mod6.ts:31:22 http +entry mod6.ts:32:25 http +entry mod6.ts:33:24 http +entry mod6.ts:34:22 http +entry mod6.ts:35:23 http +entry mod6.ts:36:22 http +entry mod6.ts:37:25 http +entry mod6.ts:38:24 http +entry mod6.ts:39:22 http +entry mod6.ts:40:23 http +entry mod6.ts:41:22 http +entry mod6.ts:42:25 http +entry mod6.ts:43:24 http +entry mod6.ts:44:22 http +entry mod6.ts:45:23 http +entry mod6.ts:46:22 http +entry mod6.ts:47:25 http +entry mod6.ts:48:24 http +entry mod6.ts:49:22 http +entry mod6.ts:4:21 http +entry mod6.ts:50:23 http +entry mod6.ts:51:22 http +entry mod6.ts:52:25 http +entry mod6.ts:53:24 http +entry mod6.ts:54:22 http +entry mod6.ts:55:23 http +entry mod6.ts:56:22 http +entry mod6.ts:57:25 http +entry mod6.ts:58:24 http +entry mod6.ts:59:22 http +entry mod6.ts:5:22 http +entry mod6.ts:60:23 http +entry mod6.ts:61:22 http +entry mod6.ts:62:25 http +entry mod6.ts:63:24 http +entry mod6.ts:64:22 http +entry mod6.ts:65:23 http +entry mod6.ts:66:22 http +entry mod6.ts:67:25 http +entry mod6.ts:68:24 http +entry mod6.ts:69:22 http +entry mod6.ts:6:21 http +entry mod6.ts:70:23 http +entry mod6.ts:71:22 http +entry mod6.ts:72:25 http +entry mod6.ts:73:24 http +entry mod6.ts:74:22 http +entry mod6.ts:75:23 http +entry mod6.ts:76:22 http +entry mod6.ts:77:25 http +entry mod6.ts:78:24 http +entry mod6.ts:79:22 http +entry mod6.ts:7:24 http +entry mod6.ts:80:23 http +entry mod6.ts:81:22 http +entry mod6.ts:82:25 http +entry mod6.ts:83:24 http +entry mod6.ts:84:22 http +entry mod6.ts:85:23 http +entry mod6.ts:86:22 http +entry mod6.ts:87:25 http +entry mod6.ts:88:24 http +entry mod6.ts:89:22 http +entry mod6.ts:8:23 http +entry mod6.ts:90:23 http +entry mod6.ts:91:22 http +entry mod6.ts:92:25 http +entry mod6.ts:93:24 http +entry mod6.ts:94:22 http +entry mod6.ts:95:23 http +entry mod6.ts:96:22 http +entry mod6.ts:97:25 http +entry mod6.ts:98:24 http +entry mod6.ts:99:22 http +entry mod6.ts:9:21 http +entry mod7.ts:100:23 http +entry mod7.ts:101:22 http +entry mod7.ts:102:25 http +entry mod7.ts:103:24 http +entry mod7.ts:10:22 http +entry mod7.ts:11:21 http +entry mod7.ts:12:24 http +entry mod7.ts:13:23 http +entry mod7.ts:14:22 http +entry mod7.ts:15:23 http +entry mod7.ts:16:22 http +entry mod7.ts:17:25 http +entry mod7.ts:18:24 http +entry mod7.ts:19:22 http +entry mod7.ts:20:23 http +entry mod7.ts:21:22 http +entry mod7.ts:22:25 http +entry mod7.ts:23:24 http +entry mod7.ts:24:22 http +entry mod7.ts:25:23 http +entry mod7.ts:26:22 http +entry mod7.ts:27:25 http +entry mod7.ts:28:24 http +entry mod7.ts:29:22 http +entry mod7.ts:30:23 http +entry mod7.ts:31:22 http +entry mod7.ts:32:25 http +entry mod7.ts:33:24 http +entry mod7.ts:34:22 http +entry mod7.ts:35:23 http +entry mod7.ts:36:22 http +entry mod7.ts:37:25 http +entry mod7.ts:38:24 http +entry mod7.ts:39:22 http +entry mod7.ts:40:23 http +entry mod7.ts:41:22 http +entry mod7.ts:42:25 http +entry mod7.ts:43:24 http +entry mod7.ts:44:22 http +entry mod7.ts:45:23 http +entry mod7.ts:46:22 http +entry mod7.ts:47:25 http +entry mod7.ts:48:24 http +entry mod7.ts:49:22 http +entry mod7.ts:4:21 http +entry mod7.ts:50:23 http +entry mod7.ts:51:22 http +entry mod7.ts:52:25 http +entry mod7.ts:53:24 http +entry mod7.ts:54:22 http +entry mod7.ts:55:23 http +entry mod7.ts:56:22 http +entry mod7.ts:57:25 http +entry mod7.ts:58:24 http +entry mod7.ts:59:22 http +entry mod7.ts:5:22 http +entry mod7.ts:60:23 http +entry mod7.ts:61:22 http +entry mod7.ts:62:25 http +entry mod7.ts:63:24 http +entry mod7.ts:64:22 http +entry mod7.ts:65:23 http +entry mod7.ts:66:22 http +entry mod7.ts:67:25 http +entry mod7.ts:68:24 http +entry mod7.ts:69:22 http +entry mod7.ts:6:21 http +entry mod7.ts:70:23 http +entry mod7.ts:71:22 http +entry mod7.ts:72:25 http +entry mod7.ts:73:24 http +entry mod7.ts:74:22 http +entry mod7.ts:75:23 http +entry mod7.ts:76:22 http +entry mod7.ts:77:25 http +entry mod7.ts:78:24 http +entry mod7.ts:79:22 http +entry mod7.ts:7:24 http +entry mod7.ts:80:23 http +entry mod7.ts:81:22 http +entry mod7.ts:82:25 http +entry mod7.ts:83:24 http +entry mod7.ts:84:22 http +entry mod7.ts:85:23 http +entry mod7.ts:86:22 http +entry mod7.ts:87:25 http +entry mod7.ts:88:24 http +entry mod7.ts:89:22 http +entry mod7.ts:8:23 http +entry mod7.ts:90:23 http +entry mod7.ts:91:22 http +entry mod7.ts:92:25 http +entry mod7.ts:93:24 http +entry mod7.ts:94:22 http +entry mod7.ts:95:23 http +entry mod7.ts:96:22 http +entry mod7.ts:97:25 http +entry mod7.ts:98:24 http +entry mod7.ts:99:22 http +entry mod7.ts:9:21 http +entry mod8.ts:100:23 http +entry mod8.ts:101:22 http +entry mod8.ts:102:25 http +entry mod8.ts:103:24 http +entry mod8.ts:10:22 http +entry mod8.ts:11:21 http +entry mod8.ts:12:24 http +entry mod8.ts:13:23 http +entry mod8.ts:14:22 http +entry mod8.ts:15:23 http +entry mod8.ts:16:22 http +entry mod8.ts:17:25 http +entry mod8.ts:18:24 http +entry mod8.ts:19:22 http +entry mod8.ts:20:23 http +entry mod8.ts:21:22 http +entry mod8.ts:22:25 http +entry mod8.ts:23:24 http +entry mod8.ts:24:22 http +entry mod8.ts:25:23 http +entry mod8.ts:26:22 http +entry mod8.ts:27:25 http +entry mod8.ts:28:24 http +entry mod8.ts:29:22 http +entry mod8.ts:30:23 http +entry mod8.ts:31:22 http +entry mod8.ts:32:25 http +entry mod8.ts:33:24 http +entry mod8.ts:34:22 http +entry mod8.ts:35:23 http +entry mod8.ts:36:22 http +entry mod8.ts:37:25 http +entry mod8.ts:38:24 http +entry mod8.ts:39:22 http +entry mod8.ts:40:23 http +entry mod8.ts:41:22 http +entry mod8.ts:42:25 http +entry mod8.ts:43:24 http +entry mod8.ts:44:22 http +entry mod8.ts:45:23 http +entry mod8.ts:46:22 http +entry mod8.ts:47:25 http +entry mod8.ts:48:24 http +entry mod8.ts:49:22 http +entry mod8.ts:4:21 http +entry mod8.ts:50:23 http +entry mod8.ts:51:22 http +entry mod8.ts:52:25 http +entry mod8.ts:53:24 http +entry mod8.ts:54:22 http +entry mod8.ts:55:23 http +entry mod8.ts:56:22 http +entry mod8.ts:57:25 http +entry mod8.ts:58:24 http +entry mod8.ts:59:22 http +entry mod8.ts:5:22 http +entry mod8.ts:60:23 http +entry mod8.ts:61:22 http +entry mod8.ts:62:25 http +entry mod8.ts:63:24 http +entry mod8.ts:64:22 http +entry mod8.ts:65:23 http +entry mod8.ts:66:22 http +entry mod8.ts:67:25 http +entry mod8.ts:68:24 http +entry mod8.ts:69:22 http +entry mod8.ts:6:21 http +entry mod8.ts:70:23 http +entry mod8.ts:71:22 http +entry mod8.ts:72:25 http +entry mod8.ts:73:24 http +entry mod8.ts:74:22 http +entry mod8.ts:75:23 http +entry mod8.ts:76:22 http +entry mod8.ts:77:25 http +entry mod8.ts:78:24 http +entry mod8.ts:79:22 http +entry mod8.ts:7:24 http +entry mod8.ts:80:23 http +entry mod8.ts:81:22 http +entry mod8.ts:82:25 http +entry mod8.ts:83:24 http +entry mod8.ts:84:22 http +entry mod8.ts:85:23 http +entry mod8.ts:86:22 http +entry mod8.ts:87:25 http +entry mod8.ts:88:24 http +entry mod8.ts:89:22 http +entry mod8.ts:8:23 http +entry mod8.ts:90:23 http +entry mod8.ts:91:22 http +entry mod8.ts:92:25 http +entry mod8.ts:93:24 http +entry mod8.ts:94:22 http +entry mod8.ts:95:23 http +entry mod8.ts:96:22 http +entry mod8.ts:97:25 http +entry mod8.ts:98:24 http +entry mod8.ts:99:22 http +entry mod8.ts:9:21 http +entry mod9.ts:100:23 http +entry mod9.ts:101:22 http +entry mod9.ts:102:25 http +entry mod9.ts:103:24 http +entry mod9.ts:10:22 http +entry mod9.ts:11:21 http +entry mod9.ts:12:24 http +entry mod9.ts:13:23 http +entry mod9.ts:14:22 http +entry mod9.ts:15:23 http +entry mod9.ts:16:22 http +entry mod9.ts:17:25 http +entry mod9.ts:18:24 http +entry mod9.ts:19:22 http +entry mod9.ts:20:23 http +entry mod9.ts:21:22 http +entry mod9.ts:22:25 http +entry mod9.ts:23:24 http +entry mod9.ts:24:22 http +entry mod9.ts:25:23 http +entry mod9.ts:26:22 http +entry mod9.ts:27:25 http +entry mod9.ts:28:24 http +entry mod9.ts:29:22 http +entry mod9.ts:30:23 http +entry mod9.ts:31:22 http +entry mod9.ts:32:25 http +entry mod9.ts:33:24 http +entry mod9.ts:34:22 http +entry mod9.ts:35:23 http +entry mod9.ts:36:22 http +entry mod9.ts:37:25 http +entry mod9.ts:38:24 http +entry mod9.ts:39:22 http +entry mod9.ts:40:23 http +entry mod9.ts:41:22 http +entry mod9.ts:42:25 http +entry mod9.ts:43:24 http +entry mod9.ts:44:22 http +entry mod9.ts:45:23 http +entry mod9.ts:46:22 http +entry mod9.ts:47:25 http +entry mod9.ts:48:24 http +entry mod9.ts:49:22 http +entry mod9.ts:4:21 http +entry mod9.ts:50:23 http +entry mod9.ts:51:22 http +entry mod9.ts:52:25 http +entry mod9.ts:53:24 http +entry mod9.ts:54:22 http +entry mod9.ts:55:23 http +entry mod9.ts:56:22 http +entry mod9.ts:57:25 http +entry mod9.ts:58:24 http +entry mod9.ts:59:22 http +entry mod9.ts:5:22 http +entry mod9.ts:60:23 http +entry mod9.ts:61:22 http +entry mod9.ts:62:25 http +entry mod9.ts:63:24 http +entry mod9.ts:64:22 http +entry mod9.ts:65:23 http +entry mod9.ts:66:22 http +entry mod9.ts:67:25 http +entry mod9.ts:68:24 http +entry mod9.ts:69:22 http +entry mod9.ts:6:21 http +entry mod9.ts:70:23 http +entry mod9.ts:71:22 http +entry mod9.ts:72:25 http +entry mod9.ts:73:24 http +entry mod9.ts:74:22 http +entry mod9.ts:75:23 http +entry mod9.ts:76:22 http +entry mod9.ts:77:25 http +entry mod9.ts:78:24 http +entry mod9.ts:79:22 http +entry mod9.ts:7:24 http +entry mod9.ts:80:23 http +entry mod9.ts:81:22 http +entry mod9.ts:82:25 http +entry mod9.ts:83:24 http +entry mod9.ts:84:22 http +entry mod9.ts:85:23 http +entry mod9.ts:86:22 http +entry mod9.ts:87:25 http +entry mod9.ts:88:24 http +entry mod9.ts:89:22 http +entry mod9.ts:8:23 http +entry mod9.ts:90:23 http +entry mod9.ts:91:22 http +entry mod9.ts:92:25 http +entry mod9.ts:93:24 http +entry mod9.ts:94:22 http +entry mod9.ts:95:23 http +entry mod9.ts:96:22 http +entry mod9.ts:97:25 http +entry mod9.ts:98:24 http +entry mod9.ts:99:22 http +entry mod9.ts:9:21 http diff --git a/graph/test/typescript/hono/expected/scale/routes-2k.tsv b/graph/test/typescript/hono/expected/scale/routes-2k.tsv new file mode 100644 index 000000000..f2909148f --- /dev/null +++ b/graph/test/typescript/hono/expected/scale/routes-2k.tsv @@ -0,0 +1,4023 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: reviewed by count and endpoints: 2,000 routes over 20 mounted modules, first /m0/res0/:id, last PATCH /m19/res99/:id; runtime agrees on all +# census: route_mount_literal, verb_literal_path (scale: 2,000 routes; generated by tools/gen-scale.mjs) +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route GET /m0/res0/:id mod0.ts:4:21 index.ts:24:13 0 +route POST /m0/res1/:id mod0.ts:5:22 index.ts:24:13 1 +route PUT /m0/res2/:id mod0.ts:6:21 index.ts:24:13 2 +route DELETE /m0/res3/:id mod0.ts:7:24 index.ts:24:13 3 +route PATCH /m0/res4/:id mod0.ts:8:23 index.ts:24:13 4 +route GET /m0/res5/:id mod0.ts:9:21 index.ts:24:13 5 +route POST /m0/res6/:id mod0.ts:10:22 index.ts:24:13 6 +route PUT /m0/res7/:id mod0.ts:11:21 index.ts:24:13 7 +route DELETE /m0/res8/:id mod0.ts:12:24 index.ts:24:13 8 +route PATCH /m0/res9/:id mod0.ts:13:23 index.ts:24:13 9 +route GET /m0/res10/:id mod0.ts:14:22 index.ts:24:13 10 +route POST /m0/res11/:id mod0.ts:15:23 index.ts:24:13 11 +route PUT /m0/res12/:id mod0.ts:16:22 index.ts:24:13 12 +route DELETE /m0/res13/:id mod0.ts:17:25 index.ts:24:13 13 +route PATCH /m0/res14/:id mod0.ts:18:24 index.ts:24:13 14 +route GET /m0/res15/:id mod0.ts:19:22 index.ts:24:13 15 +route POST /m0/res16/:id mod0.ts:20:23 index.ts:24:13 16 +route PUT /m0/res17/:id mod0.ts:21:22 index.ts:24:13 17 +route DELETE /m0/res18/:id mod0.ts:22:25 index.ts:24:13 18 +route PATCH /m0/res19/:id mod0.ts:23:24 index.ts:24:13 19 +route GET /m0/res20/:id mod0.ts:24:22 index.ts:24:13 20 +route POST /m0/res21/:id mod0.ts:25:23 index.ts:24:13 21 +route PUT /m0/res22/:id mod0.ts:26:22 index.ts:24:13 22 +route DELETE /m0/res23/:id mod0.ts:27:25 index.ts:24:13 23 +route PATCH /m0/res24/:id mod0.ts:28:24 index.ts:24:13 24 +route GET /m0/res25/:id mod0.ts:29:22 index.ts:24:13 25 +route POST /m0/res26/:id mod0.ts:30:23 index.ts:24:13 26 +route PUT /m0/res27/:id mod0.ts:31:22 index.ts:24:13 27 +route DELETE /m0/res28/:id mod0.ts:32:25 index.ts:24:13 28 +route PATCH /m0/res29/:id mod0.ts:33:24 index.ts:24:13 29 +route GET /m0/res30/:id mod0.ts:34:22 index.ts:24:13 30 +route POST /m0/res31/:id mod0.ts:35:23 index.ts:24:13 31 +route PUT /m0/res32/:id mod0.ts:36:22 index.ts:24:13 32 +route DELETE /m0/res33/:id mod0.ts:37:25 index.ts:24:13 33 +route PATCH /m0/res34/:id mod0.ts:38:24 index.ts:24:13 34 +route GET /m0/res35/:id mod0.ts:39:22 index.ts:24:13 35 +route POST /m0/res36/:id mod0.ts:40:23 index.ts:24:13 36 +route PUT /m0/res37/:id mod0.ts:41:22 index.ts:24:13 37 +route DELETE /m0/res38/:id mod0.ts:42:25 index.ts:24:13 38 +route PATCH /m0/res39/:id mod0.ts:43:24 index.ts:24:13 39 +route GET /m0/res40/:id mod0.ts:44:22 index.ts:24:13 40 +route POST /m0/res41/:id mod0.ts:45:23 index.ts:24:13 41 +route PUT /m0/res42/:id mod0.ts:46:22 index.ts:24:13 42 +route DELETE /m0/res43/:id mod0.ts:47:25 index.ts:24:13 43 +route PATCH /m0/res44/:id mod0.ts:48:24 index.ts:24:13 44 +route GET /m0/res45/:id mod0.ts:49:22 index.ts:24:13 45 +route POST /m0/res46/:id mod0.ts:50:23 index.ts:24:13 46 +route PUT /m0/res47/:id mod0.ts:51:22 index.ts:24:13 47 +route DELETE /m0/res48/:id mod0.ts:52:25 index.ts:24:13 48 +route PATCH /m0/res49/:id mod0.ts:53:24 index.ts:24:13 49 +route GET /m0/res50/:id mod0.ts:54:22 index.ts:24:13 50 +route POST /m0/res51/:id mod0.ts:55:23 index.ts:24:13 51 +route PUT /m0/res52/:id mod0.ts:56:22 index.ts:24:13 52 +route DELETE /m0/res53/:id mod0.ts:57:25 index.ts:24:13 53 +route PATCH /m0/res54/:id mod0.ts:58:24 index.ts:24:13 54 +route GET /m0/res55/:id mod0.ts:59:22 index.ts:24:13 55 +route POST /m0/res56/:id mod0.ts:60:23 index.ts:24:13 56 +route PUT /m0/res57/:id mod0.ts:61:22 index.ts:24:13 57 +route DELETE /m0/res58/:id mod0.ts:62:25 index.ts:24:13 58 +route PATCH /m0/res59/:id mod0.ts:63:24 index.ts:24:13 59 +route GET /m0/res60/:id mod0.ts:64:22 index.ts:24:13 60 +route POST /m0/res61/:id mod0.ts:65:23 index.ts:24:13 61 +route PUT /m0/res62/:id mod0.ts:66:22 index.ts:24:13 62 +route DELETE /m0/res63/:id mod0.ts:67:25 index.ts:24:13 63 +route PATCH /m0/res64/:id mod0.ts:68:24 index.ts:24:13 64 +route GET /m0/res65/:id mod0.ts:69:22 index.ts:24:13 65 +route POST /m0/res66/:id mod0.ts:70:23 index.ts:24:13 66 +route PUT /m0/res67/:id mod0.ts:71:22 index.ts:24:13 67 +route DELETE /m0/res68/:id mod0.ts:72:25 index.ts:24:13 68 +route PATCH /m0/res69/:id mod0.ts:73:24 index.ts:24:13 69 +route GET /m0/res70/:id mod0.ts:74:22 index.ts:24:13 70 +route POST /m0/res71/:id mod0.ts:75:23 index.ts:24:13 71 +route PUT /m0/res72/:id mod0.ts:76:22 index.ts:24:13 72 +route DELETE /m0/res73/:id mod0.ts:77:25 index.ts:24:13 73 +route PATCH /m0/res74/:id mod0.ts:78:24 index.ts:24:13 74 +route GET /m0/res75/:id mod0.ts:79:22 index.ts:24:13 75 +route POST /m0/res76/:id mod0.ts:80:23 index.ts:24:13 76 +route PUT /m0/res77/:id mod0.ts:81:22 index.ts:24:13 77 +route DELETE /m0/res78/:id mod0.ts:82:25 index.ts:24:13 78 +route PATCH /m0/res79/:id mod0.ts:83:24 index.ts:24:13 79 +route GET /m0/res80/:id mod0.ts:84:22 index.ts:24:13 80 +route POST /m0/res81/:id mod0.ts:85:23 index.ts:24:13 81 +route PUT /m0/res82/:id mod0.ts:86:22 index.ts:24:13 82 +route DELETE /m0/res83/:id mod0.ts:87:25 index.ts:24:13 83 +route PATCH /m0/res84/:id mod0.ts:88:24 index.ts:24:13 84 +route GET /m0/res85/:id mod0.ts:89:22 index.ts:24:13 85 +route POST /m0/res86/:id mod0.ts:90:23 index.ts:24:13 86 +route PUT /m0/res87/:id mod0.ts:91:22 index.ts:24:13 87 +route DELETE /m0/res88/:id mod0.ts:92:25 index.ts:24:13 88 +route PATCH /m0/res89/:id mod0.ts:93:24 index.ts:24:13 89 +route GET /m0/res90/:id mod0.ts:94:22 index.ts:24:13 90 +route POST /m0/res91/:id mod0.ts:95:23 index.ts:24:13 91 +route PUT /m0/res92/:id mod0.ts:96:22 index.ts:24:13 92 +route DELETE /m0/res93/:id mod0.ts:97:25 index.ts:24:13 93 +route PATCH /m0/res94/:id mod0.ts:98:24 index.ts:24:13 94 +route GET /m0/res95/:id mod0.ts:99:22 index.ts:24:13 95 +route POST /m0/res96/:id mod0.ts:100:23 index.ts:24:13 96 +route PUT /m0/res97/:id mod0.ts:101:22 index.ts:24:13 97 +route DELETE /m0/res98/:id mod0.ts:102:25 index.ts:24:13 98 +route PATCH /m0/res99/:id mod0.ts:103:24 index.ts:24:13 99 +route GET /m1/res0/:id mod1.ts:4:21 index.ts:24:13 100 +route POST /m1/res1/:id mod1.ts:5:22 index.ts:24:13 101 +route PUT /m1/res2/:id mod1.ts:6:21 index.ts:24:13 102 +route DELETE /m1/res3/:id mod1.ts:7:24 index.ts:24:13 103 +route PATCH /m1/res4/:id mod1.ts:8:23 index.ts:24:13 104 +route GET /m1/res5/:id mod1.ts:9:21 index.ts:24:13 105 +route POST /m1/res6/:id mod1.ts:10:22 index.ts:24:13 106 +route PUT /m1/res7/:id mod1.ts:11:21 index.ts:24:13 107 +route DELETE /m1/res8/:id mod1.ts:12:24 index.ts:24:13 108 +route PATCH /m1/res9/:id mod1.ts:13:23 index.ts:24:13 109 +route GET /m1/res10/:id mod1.ts:14:22 index.ts:24:13 110 +route POST /m1/res11/:id mod1.ts:15:23 index.ts:24:13 111 +route PUT /m1/res12/:id mod1.ts:16:22 index.ts:24:13 112 +route DELETE /m1/res13/:id mod1.ts:17:25 index.ts:24:13 113 +route PATCH /m1/res14/:id mod1.ts:18:24 index.ts:24:13 114 +route GET /m1/res15/:id mod1.ts:19:22 index.ts:24:13 115 +route POST /m1/res16/:id mod1.ts:20:23 index.ts:24:13 116 +route PUT /m1/res17/:id mod1.ts:21:22 index.ts:24:13 117 +route DELETE /m1/res18/:id mod1.ts:22:25 index.ts:24:13 118 +route PATCH /m1/res19/:id mod1.ts:23:24 index.ts:24:13 119 +route GET /m1/res20/:id mod1.ts:24:22 index.ts:24:13 120 +route POST /m1/res21/:id mod1.ts:25:23 index.ts:24:13 121 +route PUT /m1/res22/:id mod1.ts:26:22 index.ts:24:13 122 +route DELETE /m1/res23/:id mod1.ts:27:25 index.ts:24:13 123 +route PATCH /m1/res24/:id mod1.ts:28:24 index.ts:24:13 124 +route GET /m1/res25/:id mod1.ts:29:22 index.ts:24:13 125 +route POST /m1/res26/:id mod1.ts:30:23 index.ts:24:13 126 +route PUT /m1/res27/:id mod1.ts:31:22 index.ts:24:13 127 +route DELETE /m1/res28/:id mod1.ts:32:25 index.ts:24:13 128 +route PATCH /m1/res29/:id mod1.ts:33:24 index.ts:24:13 129 +route GET /m1/res30/:id mod1.ts:34:22 index.ts:24:13 130 +route POST /m1/res31/:id mod1.ts:35:23 index.ts:24:13 131 +route PUT /m1/res32/:id mod1.ts:36:22 index.ts:24:13 132 +route DELETE /m1/res33/:id mod1.ts:37:25 index.ts:24:13 133 +route PATCH /m1/res34/:id mod1.ts:38:24 index.ts:24:13 134 +route GET /m1/res35/:id mod1.ts:39:22 index.ts:24:13 135 +route POST /m1/res36/:id mod1.ts:40:23 index.ts:24:13 136 +route PUT /m1/res37/:id mod1.ts:41:22 index.ts:24:13 137 +route DELETE /m1/res38/:id mod1.ts:42:25 index.ts:24:13 138 +route PATCH /m1/res39/:id mod1.ts:43:24 index.ts:24:13 139 +route GET /m1/res40/:id mod1.ts:44:22 index.ts:24:13 140 +route POST /m1/res41/:id mod1.ts:45:23 index.ts:24:13 141 +route PUT /m1/res42/:id mod1.ts:46:22 index.ts:24:13 142 +route DELETE /m1/res43/:id mod1.ts:47:25 index.ts:24:13 143 +route PATCH /m1/res44/:id mod1.ts:48:24 index.ts:24:13 144 +route GET /m1/res45/:id mod1.ts:49:22 index.ts:24:13 145 +route POST /m1/res46/:id mod1.ts:50:23 index.ts:24:13 146 +route PUT /m1/res47/:id mod1.ts:51:22 index.ts:24:13 147 +route DELETE /m1/res48/:id mod1.ts:52:25 index.ts:24:13 148 +route PATCH /m1/res49/:id mod1.ts:53:24 index.ts:24:13 149 +route GET /m1/res50/:id mod1.ts:54:22 index.ts:24:13 150 +route POST /m1/res51/:id mod1.ts:55:23 index.ts:24:13 151 +route PUT /m1/res52/:id mod1.ts:56:22 index.ts:24:13 152 +route DELETE /m1/res53/:id mod1.ts:57:25 index.ts:24:13 153 +route PATCH /m1/res54/:id mod1.ts:58:24 index.ts:24:13 154 +route GET /m1/res55/:id mod1.ts:59:22 index.ts:24:13 155 +route POST /m1/res56/:id mod1.ts:60:23 index.ts:24:13 156 +route PUT /m1/res57/:id mod1.ts:61:22 index.ts:24:13 157 +route DELETE /m1/res58/:id mod1.ts:62:25 index.ts:24:13 158 +route PATCH /m1/res59/:id mod1.ts:63:24 index.ts:24:13 159 +route GET /m1/res60/:id mod1.ts:64:22 index.ts:24:13 160 +route POST /m1/res61/:id mod1.ts:65:23 index.ts:24:13 161 +route PUT /m1/res62/:id mod1.ts:66:22 index.ts:24:13 162 +route DELETE /m1/res63/:id mod1.ts:67:25 index.ts:24:13 163 +route PATCH /m1/res64/:id mod1.ts:68:24 index.ts:24:13 164 +route GET /m1/res65/:id mod1.ts:69:22 index.ts:24:13 165 +route POST /m1/res66/:id mod1.ts:70:23 index.ts:24:13 166 +route PUT /m1/res67/:id mod1.ts:71:22 index.ts:24:13 167 +route DELETE /m1/res68/:id mod1.ts:72:25 index.ts:24:13 168 +route PATCH /m1/res69/:id mod1.ts:73:24 index.ts:24:13 169 +route GET /m1/res70/:id mod1.ts:74:22 index.ts:24:13 170 +route POST /m1/res71/:id mod1.ts:75:23 index.ts:24:13 171 +route PUT /m1/res72/:id mod1.ts:76:22 index.ts:24:13 172 +route DELETE /m1/res73/:id mod1.ts:77:25 index.ts:24:13 173 +route PATCH /m1/res74/:id mod1.ts:78:24 index.ts:24:13 174 +route GET /m1/res75/:id mod1.ts:79:22 index.ts:24:13 175 +route POST /m1/res76/:id mod1.ts:80:23 index.ts:24:13 176 +route PUT /m1/res77/:id mod1.ts:81:22 index.ts:24:13 177 +route DELETE /m1/res78/:id mod1.ts:82:25 index.ts:24:13 178 +route PATCH /m1/res79/:id mod1.ts:83:24 index.ts:24:13 179 +route GET /m1/res80/:id mod1.ts:84:22 index.ts:24:13 180 +route POST /m1/res81/:id mod1.ts:85:23 index.ts:24:13 181 +route PUT /m1/res82/:id mod1.ts:86:22 index.ts:24:13 182 +route DELETE /m1/res83/:id mod1.ts:87:25 index.ts:24:13 183 +route PATCH /m1/res84/:id mod1.ts:88:24 index.ts:24:13 184 +route GET /m1/res85/:id mod1.ts:89:22 index.ts:24:13 185 +route POST /m1/res86/:id mod1.ts:90:23 index.ts:24:13 186 +route PUT /m1/res87/:id mod1.ts:91:22 index.ts:24:13 187 +route DELETE /m1/res88/:id mod1.ts:92:25 index.ts:24:13 188 +route PATCH /m1/res89/:id mod1.ts:93:24 index.ts:24:13 189 +route GET /m1/res90/:id mod1.ts:94:22 index.ts:24:13 190 +route POST /m1/res91/:id mod1.ts:95:23 index.ts:24:13 191 +route PUT /m1/res92/:id mod1.ts:96:22 index.ts:24:13 192 +route DELETE /m1/res93/:id mod1.ts:97:25 index.ts:24:13 193 +route PATCH /m1/res94/:id mod1.ts:98:24 index.ts:24:13 194 +route GET /m1/res95/:id mod1.ts:99:22 index.ts:24:13 195 +route POST /m1/res96/:id mod1.ts:100:23 index.ts:24:13 196 +route PUT /m1/res97/:id mod1.ts:101:22 index.ts:24:13 197 +route DELETE /m1/res98/:id mod1.ts:102:25 index.ts:24:13 198 +route PATCH /m1/res99/:id mod1.ts:103:24 index.ts:24:13 199 +route GET /m2/res0/:id mod2.ts:4:21 index.ts:24:13 200 +route POST /m2/res1/:id mod2.ts:5:22 index.ts:24:13 201 +route PUT /m2/res2/:id mod2.ts:6:21 index.ts:24:13 202 +route DELETE /m2/res3/:id mod2.ts:7:24 index.ts:24:13 203 +route PATCH /m2/res4/:id mod2.ts:8:23 index.ts:24:13 204 +route GET /m2/res5/:id mod2.ts:9:21 index.ts:24:13 205 +route POST /m2/res6/:id mod2.ts:10:22 index.ts:24:13 206 +route PUT /m2/res7/:id mod2.ts:11:21 index.ts:24:13 207 +route DELETE /m2/res8/:id mod2.ts:12:24 index.ts:24:13 208 +route PATCH /m2/res9/:id mod2.ts:13:23 index.ts:24:13 209 +route GET /m2/res10/:id mod2.ts:14:22 index.ts:24:13 210 +route POST /m2/res11/:id mod2.ts:15:23 index.ts:24:13 211 +route PUT /m2/res12/:id mod2.ts:16:22 index.ts:24:13 212 +route DELETE /m2/res13/:id mod2.ts:17:25 index.ts:24:13 213 +route PATCH /m2/res14/:id mod2.ts:18:24 index.ts:24:13 214 +route GET /m2/res15/:id mod2.ts:19:22 index.ts:24:13 215 +route POST /m2/res16/:id mod2.ts:20:23 index.ts:24:13 216 +route PUT /m2/res17/:id mod2.ts:21:22 index.ts:24:13 217 +route DELETE /m2/res18/:id mod2.ts:22:25 index.ts:24:13 218 +route PATCH /m2/res19/:id mod2.ts:23:24 index.ts:24:13 219 +route GET /m2/res20/:id mod2.ts:24:22 index.ts:24:13 220 +route POST /m2/res21/:id mod2.ts:25:23 index.ts:24:13 221 +route PUT /m2/res22/:id mod2.ts:26:22 index.ts:24:13 222 +route DELETE /m2/res23/:id mod2.ts:27:25 index.ts:24:13 223 +route PATCH /m2/res24/:id mod2.ts:28:24 index.ts:24:13 224 +route GET /m2/res25/:id mod2.ts:29:22 index.ts:24:13 225 +route POST /m2/res26/:id mod2.ts:30:23 index.ts:24:13 226 +route PUT /m2/res27/:id mod2.ts:31:22 index.ts:24:13 227 +route DELETE /m2/res28/:id mod2.ts:32:25 index.ts:24:13 228 +route PATCH /m2/res29/:id mod2.ts:33:24 index.ts:24:13 229 +route GET /m2/res30/:id mod2.ts:34:22 index.ts:24:13 230 +route POST /m2/res31/:id mod2.ts:35:23 index.ts:24:13 231 +route PUT /m2/res32/:id mod2.ts:36:22 index.ts:24:13 232 +route DELETE /m2/res33/:id mod2.ts:37:25 index.ts:24:13 233 +route PATCH /m2/res34/:id mod2.ts:38:24 index.ts:24:13 234 +route GET /m2/res35/:id mod2.ts:39:22 index.ts:24:13 235 +route POST /m2/res36/:id mod2.ts:40:23 index.ts:24:13 236 +route PUT /m2/res37/:id mod2.ts:41:22 index.ts:24:13 237 +route DELETE /m2/res38/:id mod2.ts:42:25 index.ts:24:13 238 +route PATCH /m2/res39/:id mod2.ts:43:24 index.ts:24:13 239 +route GET /m2/res40/:id mod2.ts:44:22 index.ts:24:13 240 +route POST /m2/res41/:id mod2.ts:45:23 index.ts:24:13 241 +route PUT /m2/res42/:id mod2.ts:46:22 index.ts:24:13 242 +route DELETE /m2/res43/:id mod2.ts:47:25 index.ts:24:13 243 +route PATCH /m2/res44/:id mod2.ts:48:24 index.ts:24:13 244 +route GET /m2/res45/:id mod2.ts:49:22 index.ts:24:13 245 +route POST /m2/res46/:id mod2.ts:50:23 index.ts:24:13 246 +route PUT /m2/res47/:id mod2.ts:51:22 index.ts:24:13 247 +route DELETE /m2/res48/:id mod2.ts:52:25 index.ts:24:13 248 +route PATCH /m2/res49/:id mod2.ts:53:24 index.ts:24:13 249 +route GET /m2/res50/:id mod2.ts:54:22 index.ts:24:13 250 +route POST /m2/res51/:id mod2.ts:55:23 index.ts:24:13 251 +route PUT /m2/res52/:id mod2.ts:56:22 index.ts:24:13 252 +route DELETE /m2/res53/:id mod2.ts:57:25 index.ts:24:13 253 +route PATCH /m2/res54/:id mod2.ts:58:24 index.ts:24:13 254 +route GET /m2/res55/:id mod2.ts:59:22 index.ts:24:13 255 +route POST /m2/res56/:id mod2.ts:60:23 index.ts:24:13 256 +route PUT /m2/res57/:id mod2.ts:61:22 index.ts:24:13 257 +route DELETE /m2/res58/:id mod2.ts:62:25 index.ts:24:13 258 +route PATCH /m2/res59/:id mod2.ts:63:24 index.ts:24:13 259 +route GET /m2/res60/:id mod2.ts:64:22 index.ts:24:13 260 +route POST /m2/res61/:id mod2.ts:65:23 index.ts:24:13 261 +route PUT /m2/res62/:id mod2.ts:66:22 index.ts:24:13 262 +route DELETE /m2/res63/:id mod2.ts:67:25 index.ts:24:13 263 +route PATCH /m2/res64/:id mod2.ts:68:24 index.ts:24:13 264 +route GET /m2/res65/:id mod2.ts:69:22 index.ts:24:13 265 +route POST /m2/res66/:id mod2.ts:70:23 index.ts:24:13 266 +route PUT /m2/res67/:id mod2.ts:71:22 index.ts:24:13 267 +route DELETE /m2/res68/:id mod2.ts:72:25 index.ts:24:13 268 +route PATCH /m2/res69/:id mod2.ts:73:24 index.ts:24:13 269 +route GET /m2/res70/:id mod2.ts:74:22 index.ts:24:13 270 +route POST /m2/res71/:id mod2.ts:75:23 index.ts:24:13 271 +route PUT /m2/res72/:id mod2.ts:76:22 index.ts:24:13 272 +route DELETE /m2/res73/:id mod2.ts:77:25 index.ts:24:13 273 +route PATCH /m2/res74/:id mod2.ts:78:24 index.ts:24:13 274 +route GET /m2/res75/:id mod2.ts:79:22 index.ts:24:13 275 +route POST /m2/res76/:id mod2.ts:80:23 index.ts:24:13 276 +route PUT /m2/res77/:id mod2.ts:81:22 index.ts:24:13 277 +route DELETE /m2/res78/:id mod2.ts:82:25 index.ts:24:13 278 +route PATCH /m2/res79/:id mod2.ts:83:24 index.ts:24:13 279 +route GET /m2/res80/:id mod2.ts:84:22 index.ts:24:13 280 +route POST /m2/res81/:id mod2.ts:85:23 index.ts:24:13 281 +route PUT /m2/res82/:id mod2.ts:86:22 index.ts:24:13 282 +route DELETE /m2/res83/:id mod2.ts:87:25 index.ts:24:13 283 +route PATCH /m2/res84/:id mod2.ts:88:24 index.ts:24:13 284 +route GET /m2/res85/:id mod2.ts:89:22 index.ts:24:13 285 +route POST /m2/res86/:id mod2.ts:90:23 index.ts:24:13 286 +route PUT /m2/res87/:id mod2.ts:91:22 index.ts:24:13 287 +route DELETE /m2/res88/:id mod2.ts:92:25 index.ts:24:13 288 +route PATCH /m2/res89/:id mod2.ts:93:24 index.ts:24:13 289 +route GET /m2/res90/:id mod2.ts:94:22 index.ts:24:13 290 +route POST /m2/res91/:id mod2.ts:95:23 index.ts:24:13 291 +route PUT /m2/res92/:id mod2.ts:96:22 index.ts:24:13 292 +route DELETE /m2/res93/:id mod2.ts:97:25 index.ts:24:13 293 +route PATCH /m2/res94/:id mod2.ts:98:24 index.ts:24:13 294 +route GET /m2/res95/:id mod2.ts:99:22 index.ts:24:13 295 +route POST /m2/res96/:id mod2.ts:100:23 index.ts:24:13 296 +route PUT /m2/res97/:id mod2.ts:101:22 index.ts:24:13 297 +route DELETE /m2/res98/:id mod2.ts:102:25 index.ts:24:13 298 +route PATCH /m2/res99/:id mod2.ts:103:24 index.ts:24:13 299 +route GET /m3/res0/:id mod3.ts:4:21 index.ts:24:13 300 +route POST /m3/res1/:id mod3.ts:5:22 index.ts:24:13 301 +route PUT /m3/res2/:id mod3.ts:6:21 index.ts:24:13 302 +route DELETE /m3/res3/:id mod3.ts:7:24 index.ts:24:13 303 +route PATCH /m3/res4/:id mod3.ts:8:23 index.ts:24:13 304 +route GET /m3/res5/:id mod3.ts:9:21 index.ts:24:13 305 +route POST /m3/res6/:id mod3.ts:10:22 index.ts:24:13 306 +route PUT /m3/res7/:id mod3.ts:11:21 index.ts:24:13 307 +route DELETE /m3/res8/:id mod3.ts:12:24 index.ts:24:13 308 +route PATCH /m3/res9/:id mod3.ts:13:23 index.ts:24:13 309 +route GET /m3/res10/:id mod3.ts:14:22 index.ts:24:13 310 +route POST /m3/res11/:id mod3.ts:15:23 index.ts:24:13 311 +route PUT /m3/res12/:id mod3.ts:16:22 index.ts:24:13 312 +route DELETE /m3/res13/:id mod3.ts:17:25 index.ts:24:13 313 +route PATCH /m3/res14/:id mod3.ts:18:24 index.ts:24:13 314 +route GET /m3/res15/:id mod3.ts:19:22 index.ts:24:13 315 +route POST /m3/res16/:id mod3.ts:20:23 index.ts:24:13 316 +route PUT /m3/res17/:id mod3.ts:21:22 index.ts:24:13 317 +route DELETE /m3/res18/:id mod3.ts:22:25 index.ts:24:13 318 +route PATCH /m3/res19/:id mod3.ts:23:24 index.ts:24:13 319 +route GET /m3/res20/:id mod3.ts:24:22 index.ts:24:13 320 +route POST /m3/res21/:id mod3.ts:25:23 index.ts:24:13 321 +route PUT /m3/res22/:id mod3.ts:26:22 index.ts:24:13 322 +route DELETE /m3/res23/:id mod3.ts:27:25 index.ts:24:13 323 +route PATCH /m3/res24/:id mod3.ts:28:24 index.ts:24:13 324 +route GET /m3/res25/:id mod3.ts:29:22 index.ts:24:13 325 +route POST /m3/res26/:id mod3.ts:30:23 index.ts:24:13 326 +route PUT /m3/res27/:id mod3.ts:31:22 index.ts:24:13 327 +route DELETE /m3/res28/:id mod3.ts:32:25 index.ts:24:13 328 +route PATCH /m3/res29/:id mod3.ts:33:24 index.ts:24:13 329 +route GET /m3/res30/:id mod3.ts:34:22 index.ts:24:13 330 +route POST /m3/res31/:id mod3.ts:35:23 index.ts:24:13 331 +route PUT /m3/res32/:id mod3.ts:36:22 index.ts:24:13 332 +route DELETE /m3/res33/:id mod3.ts:37:25 index.ts:24:13 333 +route PATCH /m3/res34/:id mod3.ts:38:24 index.ts:24:13 334 +route GET /m3/res35/:id mod3.ts:39:22 index.ts:24:13 335 +route POST /m3/res36/:id mod3.ts:40:23 index.ts:24:13 336 +route PUT /m3/res37/:id mod3.ts:41:22 index.ts:24:13 337 +route DELETE /m3/res38/:id mod3.ts:42:25 index.ts:24:13 338 +route PATCH /m3/res39/:id mod3.ts:43:24 index.ts:24:13 339 +route GET /m3/res40/:id mod3.ts:44:22 index.ts:24:13 340 +route POST /m3/res41/:id mod3.ts:45:23 index.ts:24:13 341 +route PUT /m3/res42/:id mod3.ts:46:22 index.ts:24:13 342 +route DELETE /m3/res43/:id mod3.ts:47:25 index.ts:24:13 343 +route PATCH /m3/res44/:id mod3.ts:48:24 index.ts:24:13 344 +route GET /m3/res45/:id mod3.ts:49:22 index.ts:24:13 345 +route POST /m3/res46/:id mod3.ts:50:23 index.ts:24:13 346 +route PUT /m3/res47/:id mod3.ts:51:22 index.ts:24:13 347 +route DELETE /m3/res48/:id mod3.ts:52:25 index.ts:24:13 348 +route PATCH /m3/res49/:id mod3.ts:53:24 index.ts:24:13 349 +route GET /m3/res50/:id mod3.ts:54:22 index.ts:24:13 350 +route POST /m3/res51/:id mod3.ts:55:23 index.ts:24:13 351 +route PUT /m3/res52/:id mod3.ts:56:22 index.ts:24:13 352 +route DELETE /m3/res53/:id mod3.ts:57:25 index.ts:24:13 353 +route PATCH /m3/res54/:id mod3.ts:58:24 index.ts:24:13 354 +route GET /m3/res55/:id mod3.ts:59:22 index.ts:24:13 355 +route POST /m3/res56/:id mod3.ts:60:23 index.ts:24:13 356 +route PUT /m3/res57/:id mod3.ts:61:22 index.ts:24:13 357 +route DELETE /m3/res58/:id mod3.ts:62:25 index.ts:24:13 358 +route PATCH /m3/res59/:id mod3.ts:63:24 index.ts:24:13 359 +route GET /m3/res60/:id mod3.ts:64:22 index.ts:24:13 360 +route POST /m3/res61/:id mod3.ts:65:23 index.ts:24:13 361 +route PUT /m3/res62/:id mod3.ts:66:22 index.ts:24:13 362 +route DELETE /m3/res63/:id mod3.ts:67:25 index.ts:24:13 363 +route PATCH /m3/res64/:id mod3.ts:68:24 index.ts:24:13 364 +route GET /m3/res65/:id mod3.ts:69:22 index.ts:24:13 365 +route POST /m3/res66/:id mod3.ts:70:23 index.ts:24:13 366 +route PUT /m3/res67/:id mod3.ts:71:22 index.ts:24:13 367 +route DELETE /m3/res68/:id mod3.ts:72:25 index.ts:24:13 368 +route PATCH /m3/res69/:id mod3.ts:73:24 index.ts:24:13 369 +route GET /m3/res70/:id mod3.ts:74:22 index.ts:24:13 370 +route POST /m3/res71/:id mod3.ts:75:23 index.ts:24:13 371 +route PUT /m3/res72/:id mod3.ts:76:22 index.ts:24:13 372 +route DELETE /m3/res73/:id mod3.ts:77:25 index.ts:24:13 373 +route PATCH /m3/res74/:id mod3.ts:78:24 index.ts:24:13 374 +route GET /m3/res75/:id mod3.ts:79:22 index.ts:24:13 375 +route POST /m3/res76/:id mod3.ts:80:23 index.ts:24:13 376 +route PUT /m3/res77/:id mod3.ts:81:22 index.ts:24:13 377 +route DELETE /m3/res78/:id mod3.ts:82:25 index.ts:24:13 378 +route PATCH /m3/res79/:id mod3.ts:83:24 index.ts:24:13 379 +route GET /m3/res80/:id mod3.ts:84:22 index.ts:24:13 380 +route POST /m3/res81/:id mod3.ts:85:23 index.ts:24:13 381 +route PUT /m3/res82/:id mod3.ts:86:22 index.ts:24:13 382 +route DELETE /m3/res83/:id mod3.ts:87:25 index.ts:24:13 383 +route PATCH /m3/res84/:id mod3.ts:88:24 index.ts:24:13 384 +route GET /m3/res85/:id mod3.ts:89:22 index.ts:24:13 385 +route POST /m3/res86/:id mod3.ts:90:23 index.ts:24:13 386 +route PUT /m3/res87/:id mod3.ts:91:22 index.ts:24:13 387 +route DELETE /m3/res88/:id mod3.ts:92:25 index.ts:24:13 388 +route PATCH /m3/res89/:id mod3.ts:93:24 index.ts:24:13 389 +route GET /m3/res90/:id mod3.ts:94:22 index.ts:24:13 390 +route POST /m3/res91/:id mod3.ts:95:23 index.ts:24:13 391 +route PUT /m3/res92/:id mod3.ts:96:22 index.ts:24:13 392 +route DELETE /m3/res93/:id mod3.ts:97:25 index.ts:24:13 393 +route PATCH /m3/res94/:id mod3.ts:98:24 index.ts:24:13 394 +route GET /m3/res95/:id mod3.ts:99:22 index.ts:24:13 395 +route POST /m3/res96/:id mod3.ts:100:23 index.ts:24:13 396 +route PUT /m3/res97/:id mod3.ts:101:22 index.ts:24:13 397 +route DELETE /m3/res98/:id mod3.ts:102:25 index.ts:24:13 398 +route PATCH /m3/res99/:id mod3.ts:103:24 index.ts:24:13 399 +route GET /m4/res0/:id mod4.ts:4:21 index.ts:24:13 400 +route POST /m4/res1/:id mod4.ts:5:22 index.ts:24:13 401 +route PUT /m4/res2/:id mod4.ts:6:21 index.ts:24:13 402 +route DELETE /m4/res3/:id mod4.ts:7:24 index.ts:24:13 403 +route PATCH /m4/res4/:id mod4.ts:8:23 index.ts:24:13 404 +route GET /m4/res5/:id mod4.ts:9:21 index.ts:24:13 405 +route POST /m4/res6/:id mod4.ts:10:22 index.ts:24:13 406 +route PUT /m4/res7/:id mod4.ts:11:21 index.ts:24:13 407 +route DELETE /m4/res8/:id mod4.ts:12:24 index.ts:24:13 408 +route PATCH /m4/res9/:id mod4.ts:13:23 index.ts:24:13 409 +route GET /m4/res10/:id mod4.ts:14:22 index.ts:24:13 410 +route POST /m4/res11/:id mod4.ts:15:23 index.ts:24:13 411 +route PUT /m4/res12/:id mod4.ts:16:22 index.ts:24:13 412 +route DELETE /m4/res13/:id mod4.ts:17:25 index.ts:24:13 413 +route PATCH /m4/res14/:id mod4.ts:18:24 index.ts:24:13 414 +route GET /m4/res15/:id mod4.ts:19:22 index.ts:24:13 415 +route POST /m4/res16/:id mod4.ts:20:23 index.ts:24:13 416 +route PUT /m4/res17/:id mod4.ts:21:22 index.ts:24:13 417 +route DELETE /m4/res18/:id mod4.ts:22:25 index.ts:24:13 418 +route PATCH /m4/res19/:id mod4.ts:23:24 index.ts:24:13 419 +route GET /m4/res20/:id mod4.ts:24:22 index.ts:24:13 420 +route POST /m4/res21/:id mod4.ts:25:23 index.ts:24:13 421 +route PUT /m4/res22/:id mod4.ts:26:22 index.ts:24:13 422 +route DELETE /m4/res23/:id mod4.ts:27:25 index.ts:24:13 423 +route PATCH /m4/res24/:id mod4.ts:28:24 index.ts:24:13 424 +route GET /m4/res25/:id mod4.ts:29:22 index.ts:24:13 425 +route POST /m4/res26/:id mod4.ts:30:23 index.ts:24:13 426 +route PUT /m4/res27/:id mod4.ts:31:22 index.ts:24:13 427 +route DELETE /m4/res28/:id mod4.ts:32:25 index.ts:24:13 428 +route PATCH /m4/res29/:id mod4.ts:33:24 index.ts:24:13 429 +route GET /m4/res30/:id mod4.ts:34:22 index.ts:24:13 430 +route POST /m4/res31/:id mod4.ts:35:23 index.ts:24:13 431 +route PUT /m4/res32/:id mod4.ts:36:22 index.ts:24:13 432 +route DELETE /m4/res33/:id mod4.ts:37:25 index.ts:24:13 433 +route PATCH /m4/res34/:id mod4.ts:38:24 index.ts:24:13 434 +route GET /m4/res35/:id mod4.ts:39:22 index.ts:24:13 435 +route POST /m4/res36/:id mod4.ts:40:23 index.ts:24:13 436 +route PUT /m4/res37/:id mod4.ts:41:22 index.ts:24:13 437 +route DELETE /m4/res38/:id mod4.ts:42:25 index.ts:24:13 438 +route PATCH /m4/res39/:id mod4.ts:43:24 index.ts:24:13 439 +route GET /m4/res40/:id mod4.ts:44:22 index.ts:24:13 440 +route POST /m4/res41/:id mod4.ts:45:23 index.ts:24:13 441 +route PUT /m4/res42/:id mod4.ts:46:22 index.ts:24:13 442 +route DELETE /m4/res43/:id mod4.ts:47:25 index.ts:24:13 443 +route PATCH /m4/res44/:id mod4.ts:48:24 index.ts:24:13 444 +route GET /m4/res45/:id mod4.ts:49:22 index.ts:24:13 445 +route POST /m4/res46/:id mod4.ts:50:23 index.ts:24:13 446 +route PUT /m4/res47/:id mod4.ts:51:22 index.ts:24:13 447 +route DELETE /m4/res48/:id mod4.ts:52:25 index.ts:24:13 448 +route PATCH /m4/res49/:id mod4.ts:53:24 index.ts:24:13 449 +route GET /m4/res50/:id mod4.ts:54:22 index.ts:24:13 450 +route POST /m4/res51/:id mod4.ts:55:23 index.ts:24:13 451 +route PUT /m4/res52/:id mod4.ts:56:22 index.ts:24:13 452 +route DELETE /m4/res53/:id mod4.ts:57:25 index.ts:24:13 453 +route PATCH /m4/res54/:id mod4.ts:58:24 index.ts:24:13 454 +route GET /m4/res55/:id mod4.ts:59:22 index.ts:24:13 455 +route POST /m4/res56/:id mod4.ts:60:23 index.ts:24:13 456 +route PUT /m4/res57/:id mod4.ts:61:22 index.ts:24:13 457 +route DELETE /m4/res58/:id mod4.ts:62:25 index.ts:24:13 458 +route PATCH /m4/res59/:id mod4.ts:63:24 index.ts:24:13 459 +route GET /m4/res60/:id mod4.ts:64:22 index.ts:24:13 460 +route POST /m4/res61/:id mod4.ts:65:23 index.ts:24:13 461 +route PUT /m4/res62/:id mod4.ts:66:22 index.ts:24:13 462 +route DELETE /m4/res63/:id mod4.ts:67:25 index.ts:24:13 463 +route PATCH /m4/res64/:id mod4.ts:68:24 index.ts:24:13 464 +route GET /m4/res65/:id mod4.ts:69:22 index.ts:24:13 465 +route POST /m4/res66/:id mod4.ts:70:23 index.ts:24:13 466 +route PUT /m4/res67/:id mod4.ts:71:22 index.ts:24:13 467 +route DELETE /m4/res68/:id mod4.ts:72:25 index.ts:24:13 468 +route PATCH /m4/res69/:id mod4.ts:73:24 index.ts:24:13 469 +route GET /m4/res70/:id mod4.ts:74:22 index.ts:24:13 470 +route POST /m4/res71/:id mod4.ts:75:23 index.ts:24:13 471 +route PUT /m4/res72/:id mod4.ts:76:22 index.ts:24:13 472 +route DELETE /m4/res73/:id mod4.ts:77:25 index.ts:24:13 473 +route PATCH /m4/res74/:id mod4.ts:78:24 index.ts:24:13 474 +route GET /m4/res75/:id mod4.ts:79:22 index.ts:24:13 475 +route POST /m4/res76/:id mod4.ts:80:23 index.ts:24:13 476 +route PUT /m4/res77/:id mod4.ts:81:22 index.ts:24:13 477 +route DELETE /m4/res78/:id mod4.ts:82:25 index.ts:24:13 478 +route PATCH /m4/res79/:id mod4.ts:83:24 index.ts:24:13 479 +route GET /m4/res80/:id mod4.ts:84:22 index.ts:24:13 480 +route POST /m4/res81/:id mod4.ts:85:23 index.ts:24:13 481 +route PUT /m4/res82/:id mod4.ts:86:22 index.ts:24:13 482 +route DELETE /m4/res83/:id mod4.ts:87:25 index.ts:24:13 483 +route PATCH /m4/res84/:id mod4.ts:88:24 index.ts:24:13 484 +route GET /m4/res85/:id mod4.ts:89:22 index.ts:24:13 485 +route POST /m4/res86/:id mod4.ts:90:23 index.ts:24:13 486 +route PUT /m4/res87/:id mod4.ts:91:22 index.ts:24:13 487 +route DELETE /m4/res88/:id mod4.ts:92:25 index.ts:24:13 488 +route PATCH /m4/res89/:id mod4.ts:93:24 index.ts:24:13 489 +route GET /m4/res90/:id mod4.ts:94:22 index.ts:24:13 490 +route POST /m4/res91/:id mod4.ts:95:23 index.ts:24:13 491 +route PUT /m4/res92/:id mod4.ts:96:22 index.ts:24:13 492 +route DELETE /m4/res93/:id mod4.ts:97:25 index.ts:24:13 493 +route PATCH /m4/res94/:id mod4.ts:98:24 index.ts:24:13 494 +route GET /m4/res95/:id mod4.ts:99:22 index.ts:24:13 495 +route POST /m4/res96/:id mod4.ts:100:23 index.ts:24:13 496 +route PUT /m4/res97/:id mod4.ts:101:22 index.ts:24:13 497 +route DELETE /m4/res98/:id mod4.ts:102:25 index.ts:24:13 498 +route PATCH /m4/res99/:id mod4.ts:103:24 index.ts:24:13 499 +route GET /m5/res0/:id mod5.ts:4:21 index.ts:24:13 500 +route POST /m5/res1/:id mod5.ts:5:22 index.ts:24:13 501 +route PUT /m5/res2/:id mod5.ts:6:21 index.ts:24:13 502 +route DELETE /m5/res3/:id mod5.ts:7:24 index.ts:24:13 503 +route PATCH /m5/res4/:id mod5.ts:8:23 index.ts:24:13 504 +route GET /m5/res5/:id mod5.ts:9:21 index.ts:24:13 505 +route POST /m5/res6/:id mod5.ts:10:22 index.ts:24:13 506 +route PUT /m5/res7/:id mod5.ts:11:21 index.ts:24:13 507 +route DELETE /m5/res8/:id mod5.ts:12:24 index.ts:24:13 508 +route PATCH /m5/res9/:id mod5.ts:13:23 index.ts:24:13 509 +route GET /m5/res10/:id mod5.ts:14:22 index.ts:24:13 510 +route POST /m5/res11/:id mod5.ts:15:23 index.ts:24:13 511 +route PUT /m5/res12/:id mod5.ts:16:22 index.ts:24:13 512 +route DELETE /m5/res13/:id mod5.ts:17:25 index.ts:24:13 513 +route PATCH /m5/res14/:id mod5.ts:18:24 index.ts:24:13 514 +route GET /m5/res15/:id mod5.ts:19:22 index.ts:24:13 515 +route POST /m5/res16/:id mod5.ts:20:23 index.ts:24:13 516 +route PUT /m5/res17/:id mod5.ts:21:22 index.ts:24:13 517 +route DELETE /m5/res18/:id mod5.ts:22:25 index.ts:24:13 518 +route PATCH /m5/res19/:id mod5.ts:23:24 index.ts:24:13 519 +route GET /m5/res20/:id mod5.ts:24:22 index.ts:24:13 520 +route POST /m5/res21/:id mod5.ts:25:23 index.ts:24:13 521 +route PUT /m5/res22/:id mod5.ts:26:22 index.ts:24:13 522 +route DELETE /m5/res23/:id mod5.ts:27:25 index.ts:24:13 523 +route PATCH /m5/res24/:id mod5.ts:28:24 index.ts:24:13 524 +route GET /m5/res25/:id mod5.ts:29:22 index.ts:24:13 525 +route POST /m5/res26/:id mod5.ts:30:23 index.ts:24:13 526 +route PUT /m5/res27/:id mod5.ts:31:22 index.ts:24:13 527 +route DELETE /m5/res28/:id mod5.ts:32:25 index.ts:24:13 528 +route PATCH /m5/res29/:id mod5.ts:33:24 index.ts:24:13 529 +route GET /m5/res30/:id mod5.ts:34:22 index.ts:24:13 530 +route POST /m5/res31/:id mod5.ts:35:23 index.ts:24:13 531 +route PUT /m5/res32/:id mod5.ts:36:22 index.ts:24:13 532 +route DELETE /m5/res33/:id mod5.ts:37:25 index.ts:24:13 533 +route PATCH /m5/res34/:id mod5.ts:38:24 index.ts:24:13 534 +route GET /m5/res35/:id mod5.ts:39:22 index.ts:24:13 535 +route POST /m5/res36/:id mod5.ts:40:23 index.ts:24:13 536 +route PUT /m5/res37/:id mod5.ts:41:22 index.ts:24:13 537 +route DELETE /m5/res38/:id mod5.ts:42:25 index.ts:24:13 538 +route PATCH /m5/res39/:id mod5.ts:43:24 index.ts:24:13 539 +route GET /m5/res40/:id mod5.ts:44:22 index.ts:24:13 540 +route POST /m5/res41/:id mod5.ts:45:23 index.ts:24:13 541 +route PUT /m5/res42/:id mod5.ts:46:22 index.ts:24:13 542 +route DELETE /m5/res43/:id mod5.ts:47:25 index.ts:24:13 543 +route PATCH /m5/res44/:id mod5.ts:48:24 index.ts:24:13 544 +route GET /m5/res45/:id mod5.ts:49:22 index.ts:24:13 545 +route POST /m5/res46/:id mod5.ts:50:23 index.ts:24:13 546 +route PUT /m5/res47/:id mod5.ts:51:22 index.ts:24:13 547 +route DELETE /m5/res48/:id mod5.ts:52:25 index.ts:24:13 548 +route PATCH /m5/res49/:id mod5.ts:53:24 index.ts:24:13 549 +route GET /m5/res50/:id mod5.ts:54:22 index.ts:24:13 550 +route POST /m5/res51/:id mod5.ts:55:23 index.ts:24:13 551 +route PUT /m5/res52/:id mod5.ts:56:22 index.ts:24:13 552 +route DELETE /m5/res53/:id mod5.ts:57:25 index.ts:24:13 553 +route PATCH /m5/res54/:id mod5.ts:58:24 index.ts:24:13 554 +route GET /m5/res55/:id mod5.ts:59:22 index.ts:24:13 555 +route POST /m5/res56/:id mod5.ts:60:23 index.ts:24:13 556 +route PUT /m5/res57/:id mod5.ts:61:22 index.ts:24:13 557 +route DELETE /m5/res58/:id mod5.ts:62:25 index.ts:24:13 558 +route PATCH /m5/res59/:id mod5.ts:63:24 index.ts:24:13 559 +route GET /m5/res60/:id mod5.ts:64:22 index.ts:24:13 560 +route POST /m5/res61/:id mod5.ts:65:23 index.ts:24:13 561 +route PUT /m5/res62/:id mod5.ts:66:22 index.ts:24:13 562 +route DELETE /m5/res63/:id mod5.ts:67:25 index.ts:24:13 563 +route PATCH /m5/res64/:id mod5.ts:68:24 index.ts:24:13 564 +route GET /m5/res65/:id mod5.ts:69:22 index.ts:24:13 565 +route POST /m5/res66/:id mod5.ts:70:23 index.ts:24:13 566 +route PUT /m5/res67/:id mod5.ts:71:22 index.ts:24:13 567 +route DELETE /m5/res68/:id mod5.ts:72:25 index.ts:24:13 568 +route PATCH /m5/res69/:id mod5.ts:73:24 index.ts:24:13 569 +route GET /m5/res70/:id mod5.ts:74:22 index.ts:24:13 570 +route POST /m5/res71/:id mod5.ts:75:23 index.ts:24:13 571 +route PUT /m5/res72/:id mod5.ts:76:22 index.ts:24:13 572 +route DELETE /m5/res73/:id mod5.ts:77:25 index.ts:24:13 573 +route PATCH /m5/res74/:id mod5.ts:78:24 index.ts:24:13 574 +route GET /m5/res75/:id mod5.ts:79:22 index.ts:24:13 575 +route POST /m5/res76/:id mod5.ts:80:23 index.ts:24:13 576 +route PUT /m5/res77/:id mod5.ts:81:22 index.ts:24:13 577 +route DELETE /m5/res78/:id mod5.ts:82:25 index.ts:24:13 578 +route PATCH /m5/res79/:id mod5.ts:83:24 index.ts:24:13 579 +route GET /m5/res80/:id mod5.ts:84:22 index.ts:24:13 580 +route POST /m5/res81/:id mod5.ts:85:23 index.ts:24:13 581 +route PUT /m5/res82/:id mod5.ts:86:22 index.ts:24:13 582 +route DELETE /m5/res83/:id mod5.ts:87:25 index.ts:24:13 583 +route PATCH /m5/res84/:id mod5.ts:88:24 index.ts:24:13 584 +route GET /m5/res85/:id mod5.ts:89:22 index.ts:24:13 585 +route POST /m5/res86/:id mod5.ts:90:23 index.ts:24:13 586 +route PUT /m5/res87/:id mod5.ts:91:22 index.ts:24:13 587 +route DELETE /m5/res88/:id mod5.ts:92:25 index.ts:24:13 588 +route PATCH /m5/res89/:id mod5.ts:93:24 index.ts:24:13 589 +route GET /m5/res90/:id mod5.ts:94:22 index.ts:24:13 590 +route POST /m5/res91/:id mod5.ts:95:23 index.ts:24:13 591 +route PUT /m5/res92/:id mod5.ts:96:22 index.ts:24:13 592 +route DELETE /m5/res93/:id mod5.ts:97:25 index.ts:24:13 593 +route PATCH /m5/res94/:id mod5.ts:98:24 index.ts:24:13 594 +route GET /m5/res95/:id mod5.ts:99:22 index.ts:24:13 595 +route POST /m5/res96/:id mod5.ts:100:23 index.ts:24:13 596 +route PUT /m5/res97/:id mod5.ts:101:22 index.ts:24:13 597 +route DELETE /m5/res98/:id mod5.ts:102:25 index.ts:24:13 598 +route PATCH /m5/res99/:id mod5.ts:103:24 index.ts:24:13 599 +route GET /m6/res0/:id mod6.ts:4:21 index.ts:24:13 600 +route POST /m6/res1/:id mod6.ts:5:22 index.ts:24:13 601 +route PUT /m6/res2/:id mod6.ts:6:21 index.ts:24:13 602 +route DELETE /m6/res3/:id mod6.ts:7:24 index.ts:24:13 603 +route PATCH /m6/res4/:id mod6.ts:8:23 index.ts:24:13 604 +route GET /m6/res5/:id mod6.ts:9:21 index.ts:24:13 605 +route POST /m6/res6/:id mod6.ts:10:22 index.ts:24:13 606 +route PUT /m6/res7/:id mod6.ts:11:21 index.ts:24:13 607 +route DELETE /m6/res8/:id mod6.ts:12:24 index.ts:24:13 608 +route PATCH /m6/res9/:id mod6.ts:13:23 index.ts:24:13 609 +route GET /m6/res10/:id mod6.ts:14:22 index.ts:24:13 610 +route POST /m6/res11/:id mod6.ts:15:23 index.ts:24:13 611 +route PUT /m6/res12/:id mod6.ts:16:22 index.ts:24:13 612 +route DELETE /m6/res13/:id mod6.ts:17:25 index.ts:24:13 613 +route PATCH /m6/res14/:id mod6.ts:18:24 index.ts:24:13 614 +route GET /m6/res15/:id mod6.ts:19:22 index.ts:24:13 615 +route POST /m6/res16/:id mod6.ts:20:23 index.ts:24:13 616 +route PUT /m6/res17/:id mod6.ts:21:22 index.ts:24:13 617 +route DELETE /m6/res18/:id mod6.ts:22:25 index.ts:24:13 618 +route PATCH /m6/res19/:id mod6.ts:23:24 index.ts:24:13 619 +route GET /m6/res20/:id mod6.ts:24:22 index.ts:24:13 620 +route POST /m6/res21/:id mod6.ts:25:23 index.ts:24:13 621 +route PUT /m6/res22/:id mod6.ts:26:22 index.ts:24:13 622 +route DELETE /m6/res23/:id mod6.ts:27:25 index.ts:24:13 623 +route PATCH /m6/res24/:id mod6.ts:28:24 index.ts:24:13 624 +route GET /m6/res25/:id mod6.ts:29:22 index.ts:24:13 625 +route POST /m6/res26/:id mod6.ts:30:23 index.ts:24:13 626 +route PUT /m6/res27/:id mod6.ts:31:22 index.ts:24:13 627 +route DELETE /m6/res28/:id mod6.ts:32:25 index.ts:24:13 628 +route PATCH /m6/res29/:id mod6.ts:33:24 index.ts:24:13 629 +route GET /m6/res30/:id mod6.ts:34:22 index.ts:24:13 630 +route POST /m6/res31/:id mod6.ts:35:23 index.ts:24:13 631 +route PUT /m6/res32/:id mod6.ts:36:22 index.ts:24:13 632 +route DELETE /m6/res33/:id mod6.ts:37:25 index.ts:24:13 633 +route PATCH /m6/res34/:id mod6.ts:38:24 index.ts:24:13 634 +route GET /m6/res35/:id mod6.ts:39:22 index.ts:24:13 635 +route POST /m6/res36/:id mod6.ts:40:23 index.ts:24:13 636 +route PUT /m6/res37/:id mod6.ts:41:22 index.ts:24:13 637 +route DELETE /m6/res38/:id mod6.ts:42:25 index.ts:24:13 638 +route PATCH /m6/res39/:id mod6.ts:43:24 index.ts:24:13 639 +route GET /m6/res40/:id mod6.ts:44:22 index.ts:24:13 640 +route POST /m6/res41/:id mod6.ts:45:23 index.ts:24:13 641 +route PUT /m6/res42/:id mod6.ts:46:22 index.ts:24:13 642 +route DELETE /m6/res43/:id mod6.ts:47:25 index.ts:24:13 643 +route PATCH /m6/res44/:id mod6.ts:48:24 index.ts:24:13 644 +route GET /m6/res45/:id mod6.ts:49:22 index.ts:24:13 645 +route POST /m6/res46/:id mod6.ts:50:23 index.ts:24:13 646 +route PUT /m6/res47/:id mod6.ts:51:22 index.ts:24:13 647 +route DELETE /m6/res48/:id mod6.ts:52:25 index.ts:24:13 648 +route PATCH /m6/res49/:id mod6.ts:53:24 index.ts:24:13 649 +route GET /m6/res50/:id mod6.ts:54:22 index.ts:24:13 650 +route POST /m6/res51/:id mod6.ts:55:23 index.ts:24:13 651 +route PUT /m6/res52/:id mod6.ts:56:22 index.ts:24:13 652 +route DELETE /m6/res53/:id mod6.ts:57:25 index.ts:24:13 653 +route PATCH /m6/res54/:id mod6.ts:58:24 index.ts:24:13 654 +route GET /m6/res55/:id mod6.ts:59:22 index.ts:24:13 655 +route POST /m6/res56/:id mod6.ts:60:23 index.ts:24:13 656 +route PUT /m6/res57/:id mod6.ts:61:22 index.ts:24:13 657 +route DELETE /m6/res58/:id mod6.ts:62:25 index.ts:24:13 658 +route PATCH /m6/res59/:id mod6.ts:63:24 index.ts:24:13 659 +route GET /m6/res60/:id mod6.ts:64:22 index.ts:24:13 660 +route POST /m6/res61/:id mod6.ts:65:23 index.ts:24:13 661 +route PUT /m6/res62/:id mod6.ts:66:22 index.ts:24:13 662 +route DELETE /m6/res63/:id mod6.ts:67:25 index.ts:24:13 663 +route PATCH /m6/res64/:id mod6.ts:68:24 index.ts:24:13 664 +route GET /m6/res65/:id mod6.ts:69:22 index.ts:24:13 665 +route POST /m6/res66/:id mod6.ts:70:23 index.ts:24:13 666 +route PUT /m6/res67/:id mod6.ts:71:22 index.ts:24:13 667 +route DELETE /m6/res68/:id mod6.ts:72:25 index.ts:24:13 668 +route PATCH /m6/res69/:id mod6.ts:73:24 index.ts:24:13 669 +route GET /m6/res70/:id mod6.ts:74:22 index.ts:24:13 670 +route POST /m6/res71/:id mod6.ts:75:23 index.ts:24:13 671 +route PUT /m6/res72/:id mod6.ts:76:22 index.ts:24:13 672 +route DELETE /m6/res73/:id mod6.ts:77:25 index.ts:24:13 673 +route PATCH /m6/res74/:id mod6.ts:78:24 index.ts:24:13 674 +route GET /m6/res75/:id mod6.ts:79:22 index.ts:24:13 675 +route POST /m6/res76/:id mod6.ts:80:23 index.ts:24:13 676 +route PUT /m6/res77/:id mod6.ts:81:22 index.ts:24:13 677 +route DELETE /m6/res78/:id mod6.ts:82:25 index.ts:24:13 678 +route PATCH /m6/res79/:id mod6.ts:83:24 index.ts:24:13 679 +route GET /m6/res80/:id mod6.ts:84:22 index.ts:24:13 680 +route POST /m6/res81/:id mod6.ts:85:23 index.ts:24:13 681 +route PUT /m6/res82/:id mod6.ts:86:22 index.ts:24:13 682 +route DELETE /m6/res83/:id mod6.ts:87:25 index.ts:24:13 683 +route PATCH /m6/res84/:id mod6.ts:88:24 index.ts:24:13 684 +route GET /m6/res85/:id mod6.ts:89:22 index.ts:24:13 685 +route POST /m6/res86/:id mod6.ts:90:23 index.ts:24:13 686 +route PUT /m6/res87/:id mod6.ts:91:22 index.ts:24:13 687 +route DELETE /m6/res88/:id mod6.ts:92:25 index.ts:24:13 688 +route PATCH /m6/res89/:id mod6.ts:93:24 index.ts:24:13 689 +route GET /m6/res90/:id mod6.ts:94:22 index.ts:24:13 690 +route POST /m6/res91/:id mod6.ts:95:23 index.ts:24:13 691 +route PUT /m6/res92/:id mod6.ts:96:22 index.ts:24:13 692 +route DELETE /m6/res93/:id mod6.ts:97:25 index.ts:24:13 693 +route PATCH /m6/res94/:id mod6.ts:98:24 index.ts:24:13 694 +route GET /m6/res95/:id mod6.ts:99:22 index.ts:24:13 695 +route POST /m6/res96/:id mod6.ts:100:23 index.ts:24:13 696 +route PUT /m6/res97/:id mod6.ts:101:22 index.ts:24:13 697 +route DELETE /m6/res98/:id mod6.ts:102:25 index.ts:24:13 698 +route PATCH /m6/res99/:id mod6.ts:103:24 index.ts:24:13 699 +route GET /m7/res0/:id mod7.ts:4:21 index.ts:24:13 700 +route POST /m7/res1/:id mod7.ts:5:22 index.ts:24:13 701 +route PUT /m7/res2/:id mod7.ts:6:21 index.ts:24:13 702 +route DELETE /m7/res3/:id mod7.ts:7:24 index.ts:24:13 703 +route PATCH /m7/res4/:id mod7.ts:8:23 index.ts:24:13 704 +route GET /m7/res5/:id mod7.ts:9:21 index.ts:24:13 705 +route POST /m7/res6/:id mod7.ts:10:22 index.ts:24:13 706 +route PUT /m7/res7/:id mod7.ts:11:21 index.ts:24:13 707 +route DELETE /m7/res8/:id mod7.ts:12:24 index.ts:24:13 708 +route PATCH /m7/res9/:id mod7.ts:13:23 index.ts:24:13 709 +route GET /m7/res10/:id mod7.ts:14:22 index.ts:24:13 710 +route POST /m7/res11/:id mod7.ts:15:23 index.ts:24:13 711 +route PUT /m7/res12/:id mod7.ts:16:22 index.ts:24:13 712 +route DELETE /m7/res13/:id mod7.ts:17:25 index.ts:24:13 713 +route PATCH /m7/res14/:id mod7.ts:18:24 index.ts:24:13 714 +route GET /m7/res15/:id mod7.ts:19:22 index.ts:24:13 715 +route POST /m7/res16/:id mod7.ts:20:23 index.ts:24:13 716 +route PUT /m7/res17/:id mod7.ts:21:22 index.ts:24:13 717 +route DELETE /m7/res18/:id mod7.ts:22:25 index.ts:24:13 718 +route PATCH /m7/res19/:id mod7.ts:23:24 index.ts:24:13 719 +route GET /m7/res20/:id mod7.ts:24:22 index.ts:24:13 720 +route POST /m7/res21/:id mod7.ts:25:23 index.ts:24:13 721 +route PUT /m7/res22/:id mod7.ts:26:22 index.ts:24:13 722 +route DELETE /m7/res23/:id mod7.ts:27:25 index.ts:24:13 723 +route PATCH /m7/res24/:id mod7.ts:28:24 index.ts:24:13 724 +route GET /m7/res25/:id mod7.ts:29:22 index.ts:24:13 725 +route POST /m7/res26/:id mod7.ts:30:23 index.ts:24:13 726 +route PUT /m7/res27/:id mod7.ts:31:22 index.ts:24:13 727 +route DELETE /m7/res28/:id mod7.ts:32:25 index.ts:24:13 728 +route PATCH /m7/res29/:id mod7.ts:33:24 index.ts:24:13 729 +route GET /m7/res30/:id mod7.ts:34:22 index.ts:24:13 730 +route POST /m7/res31/:id mod7.ts:35:23 index.ts:24:13 731 +route PUT /m7/res32/:id mod7.ts:36:22 index.ts:24:13 732 +route DELETE /m7/res33/:id mod7.ts:37:25 index.ts:24:13 733 +route PATCH /m7/res34/:id mod7.ts:38:24 index.ts:24:13 734 +route GET /m7/res35/:id mod7.ts:39:22 index.ts:24:13 735 +route POST /m7/res36/:id mod7.ts:40:23 index.ts:24:13 736 +route PUT /m7/res37/:id mod7.ts:41:22 index.ts:24:13 737 +route DELETE /m7/res38/:id mod7.ts:42:25 index.ts:24:13 738 +route PATCH /m7/res39/:id mod7.ts:43:24 index.ts:24:13 739 +route GET /m7/res40/:id mod7.ts:44:22 index.ts:24:13 740 +route POST /m7/res41/:id mod7.ts:45:23 index.ts:24:13 741 +route PUT /m7/res42/:id mod7.ts:46:22 index.ts:24:13 742 +route DELETE /m7/res43/:id mod7.ts:47:25 index.ts:24:13 743 +route PATCH /m7/res44/:id mod7.ts:48:24 index.ts:24:13 744 +route GET /m7/res45/:id mod7.ts:49:22 index.ts:24:13 745 +route POST /m7/res46/:id mod7.ts:50:23 index.ts:24:13 746 +route PUT /m7/res47/:id mod7.ts:51:22 index.ts:24:13 747 +route DELETE /m7/res48/:id mod7.ts:52:25 index.ts:24:13 748 +route PATCH /m7/res49/:id mod7.ts:53:24 index.ts:24:13 749 +route GET /m7/res50/:id mod7.ts:54:22 index.ts:24:13 750 +route POST /m7/res51/:id mod7.ts:55:23 index.ts:24:13 751 +route PUT /m7/res52/:id mod7.ts:56:22 index.ts:24:13 752 +route DELETE /m7/res53/:id mod7.ts:57:25 index.ts:24:13 753 +route PATCH /m7/res54/:id mod7.ts:58:24 index.ts:24:13 754 +route GET /m7/res55/:id mod7.ts:59:22 index.ts:24:13 755 +route POST /m7/res56/:id mod7.ts:60:23 index.ts:24:13 756 +route PUT /m7/res57/:id mod7.ts:61:22 index.ts:24:13 757 +route DELETE /m7/res58/:id mod7.ts:62:25 index.ts:24:13 758 +route PATCH /m7/res59/:id mod7.ts:63:24 index.ts:24:13 759 +route GET /m7/res60/:id mod7.ts:64:22 index.ts:24:13 760 +route POST /m7/res61/:id mod7.ts:65:23 index.ts:24:13 761 +route PUT /m7/res62/:id mod7.ts:66:22 index.ts:24:13 762 +route DELETE /m7/res63/:id mod7.ts:67:25 index.ts:24:13 763 +route PATCH /m7/res64/:id mod7.ts:68:24 index.ts:24:13 764 +route GET /m7/res65/:id mod7.ts:69:22 index.ts:24:13 765 +route POST /m7/res66/:id mod7.ts:70:23 index.ts:24:13 766 +route PUT /m7/res67/:id mod7.ts:71:22 index.ts:24:13 767 +route DELETE /m7/res68/:id mod7.ts:72:25 index.ts:24:13 768 +route PATCH /m7/res69/:id mod7.ts:73:24 index.ts:24:13 769 +route GET /m7/res70/:id mod7.ts:74:22 index.ts:24:13 770 +route POST /m7/res71/:id mod7.ts:75:23 index.ts:24:13 771 +route PUT /m7/res72/:id mod7.ts:76:22 index.ts:24:13 772 +route DELETE /m7/res73/:id mod7.ts:77:25 index.ts:24:13 773 +route PATCH /m7/res74/:id mod7.ts:78:24 index.ts:24:13 774 +route GET /m7/res75/:id mod7.ts:79:22 index.ts:24:13 775 +route POST /m7/res76/:id mod7.ts:80:23 index.ts:24:13 776 +route PUT /m7/res77/:id mod7.ts:81:22 index.ts:24:13 777 +route DELETE /m7/res78/:id mod7.ts:82:25 index.ts:24:13 778 +route PATCH /m7/res79/:id mod7.ts:83:24 index.ts:24:13 779 +route GET /m7/res80/:id mod7.ts:84:22 index.ts:24:13 780 +route POST /m7/res81/:id mod7.ts:85:23 index.ts:24:13 781 +route PUT /m7/res82/:id mod7.ts:86:22 index.ts:24:13 782 +route DELETE /m7/res83/:id mod7.ts:87:25 index.ts:24:13 783 +route PATCH /m7/res84/:id mod7.ts:88:24 index.ts:24:13 784 +route GET /m7/res85/:id mod7.ts:89:22 index.ts:24:13 785 +route POST /m7/res86/:id mod7.ts:90:23 index.ts:24:13 786 +route PUT /m7/res87/:id mod7.ts:91:22 index.ts:24:13 787 +route DELETE /m7/res88/:id mod7.ts:92:25 index.ts:24:13 788 +route PATCH /m7/res89/:id mod7.ts:93:24 index.ts:24:13 789 +route GET /m7/res90/:id mod7.ts:94:22 index.ts:24:13 790 +route POST /m7/res91/:id mod7.ts:95:23 index.ts:24:13 791 +route PUT /m7/res92/:id mod7.ts:96:22 index.ts:24:13 792 +route DELETE /m7/res93/:id mod7.ts:97:25 index.ts:24:13 793 +route PATCH /m7/res94/:id mod7.ts:98:24 index.ts:24:13 794 +route GET /m7/res95/:id mod7.ts:99:22 index.ts:24:13 795 +route POST /m7/res96/:id mod7.ts:100:23 index.ts:24:13 796 +route PUT /m7/res97/:id mod7.ts:101:22 index.ts:24:13 797 +route DELETE /m7/res98/:id mod7.ts:102:25 index.ts:24:13 798 +route PATCH /m7/res99/:id mod7.ts:103:24 index.ts:24:13 799 +route GET /m8/res0/:id mod8.ts:4:21 index.ts:24:13 800 +route POST /m8/res1/:id mod8.ts:5:22 index.ts:24:13 801 +route PUT /m8/res2/:id mod8.ts:6:21 index.ts:24:13 802 +route DELETE /m8/res3/:id mod8.ts:7:24 index.ts:24:13 803 +route PATCH /m8/res4/:id mod8.ts:8:23 index.ts:24:13 804 +route GET /m8/res5/:id mod8.ts:9:21 index.ts:24:13 805 +route POST /m8/res6/:id mod8.ts:10:22 index.ts:24:13 806 +route PUT /m8/res7/:id mod8.ts:11:21 index.ts:24:13 807 +route DELETE /m8/res8/:id mod8.ts:12:24 index.ts:24:13 808 +route PATCH /m8/res9/:id mod8.ts:13:23 index.ts:24:13 809 +route GET /m8/res10/:id mod8.ts:14:22 index.ts:24:13 810 +route POST /m8/res11/:id mod8.ts:15:23 index.ts:24:13 811 +route PUT /m8/res12/:id mod8.ts:16:22 index.ts:24:13 812 +route DELETE /m8/res13/:id mod8.ts:17:25 index.ts:24:13 813 +route PATCH /m8/res14/:id mod8.ts:18:24 index.ts:24:13 814 +route GET /m8/res15/:id mod8.ts:19:22 index.ts:24:13 815 +route POST /m8/res16/:id mod8.ts:20:23 index.ts:24:13 816 +route PUT /m8/res17/:id mod8.ts:21:22 index.ts:24:13 817 +route DELETE /m8/res18/:id mod8.ts:22:25 index.ts:24:13 818 +route PATCH /m8/res19/:id mod8.ts:23:24 index.ts:24:13 819 +route GET /m8/res20/:id mod8.ts:24:22 index.ts:24:13 820 +route POST /m8/res21/:id mod8.ts:25:23 index.ts:24:13 821 +route PUT /m8/res22/:id mod8.ts:26:22 index.ts:24:13 822 +route DELETE /m8/res23/:id mod8.ts:27:25 index.ts:24:13 823 +route PATCH /m8/res24/:id mod8.ts:28:24 index.ts:24:13 824 +route GET /m8/res25/:id mod8.ts:29:22 index.ts:24:13 825 +route POST /m8/res26/:id mod8.ts:30:23 index.ts:24:13 826 +route PUT /m8/res27/:id mod8.ts:31:22 index.ts:24:13 827 +route DELETE /m8/res28/:id mod8.ts:32:25 index.ts:24:13 828 +route PATCH /m8/res29/:id mod8.ts:33:24 index.ts:24:13 829 +route GET /m8/res30/:id mod8.ts:34:22 index.ts:24:13 830 +route POST /m8/res31/:id mod8.ts:35:23 index.ts:24:13 831 +route PUT /m8/res32/:id mod8.ts:36:22 index.ts:24:13 832 +route DELETE /m8/res33/:id mod8.ts:37:25 index.ts:24:13 833 +route PATCH /m8/res34/:id mod8.ts:38:24 index.ts:24:13 834 +route GET /m8/res35/:id mod8.ts:39:22 index.ts:24:13 835 +route POST /m8/res36/:id mod8.ts:40:23 index.ts:24:13 836 +route PUT /m8/res37/:id mod8.ts:41:22 index.ts:24:13 837 +route DELETE /m8/res38/:id mod8.ts:42:25 index.ts:24:13 838 +route PATCH /m8/res39/:id mod8.ts:43:24 index.ts:24:13 839 +route GET /m8/res40/:id mod8.ts:44:22 index.ts:24:13 840 +route POST /m8/res41/:id mod8.ts:45:23 index.ts:24:13 841 +route PUT /m8/res42/:id mod8.ts:46:22 index.ts:24:13 842 +route DELETE /m8/res43/:id mod8.ts:47:25 index.ts:24:13 843 +route PATCH /m8/res44/:id mod8.ts:48:24 index.ts:24:13 844 +route GET /m8/res45/:id mod8.ts:49:22 index.ts:24:13 845 +route POST /m8/res46/:id mod8.ts:50:23 index.ts:24:13 846 +route PUT /m8/res47/:id mod8.ts:51:22 index.ts:24:13 847 +route DELETE /m8/res48/:id mod8.ts:52:25 index.ts:24:13 848 +route PATCH /m8/res49/:id mod8.ts:53:24 index.ts:24:13 849 +route GET /m8/res50/:id mod8.ts:54:22 index.ts:24:13 850 +route POST /m8/res51/:id mod8.ts:55:23 index.ts:24:13 851 +route PUT /m8/res52/:id mod8.ts:56:22 index.ts:24:13 852 +route DELETE /m8/res53/:id mod8.ts:57:25 index.ts:24:13 853 +route PATCH /m8/res54/:id mod8.ts:58:24 index.ts:24:13 854 +route GET /m8/res55/:id mod8.ts:59:22 index.ts:24:13 855 +route POST /m8/res56/:id mod8.ts:60:23 index.ts:24:13 856 +route PUT /m8/res57/:id mod8.ts:61:22 index.ts:24:13 857 +route DELETE /m8/res58/:id mod8.ts:62:25 index.ts:24:13 858 +route PATCH /m8/res59/:id mod8.ts:63:24 index.ts:24:13 859 +route GET /m8/res60/:id mod8.ts:64:22 index.ts:24:13 860 +route POST /m8/res61/:id mod8.ts:65:23 index.ts:24:13 861 +route PUT /m8/res62/:id mod8.ts:66:22 index.ts:24:13 862 +route DELETE /m8/res63/:id mod8.ts:67:25 index.ts:24:13 863 +route PATCH /m8/res64/:id mod8.ts:68:24 index.ts:24:13 864 +route GET /m8/res65/:id mod8.ts:69:22 index.ts:24:13 865 +route POST /m8/res66/:id mod8.ts:70:23 index.ts:24:13 866 +route PUT /m8/res67/:id mod8.ts:71:22 index.ts:24:13 867 +route DELETE /m8/res68/:id mod8.ts:72:25 index.ts:24:13 868 +route PATCH /m8/res69/:id mod8.ts:73:24 index.ts:24:13 869 +route GET /m8/res70/:id mod8.ts:74:22 index.ts:24:13 870 +route POST /m8/res71/:id mod8.ts:75:23 index.ts:24:13 871 +route PUT /m8/res72/:id mod8.ts:76:22 index.ts:24:13 872 +route DELETE /m8/res73/:id mod8.ts:77:25 index.ts:24:13 873 +route PATCH /m8/res74/:id mod8.ts:78:24 index.ts:24:13 874 +route GET /m8/res75/:id mod8.ts:79:22 index.ts:24:13 875 +route POST /m8/res76/:id mod8.ts:80:23 index.ts:24:13 876 +route PUT /m8/res77/:id mod8.ts:81:22 index.ts:24:13 877 +route DELETE /m8/res78/:id mod8.ts:82:25 index.ts:24:13 878 +route PATCH /m8/res79/:id mod8.ts:83:24 index.ts:24:13 879 +route GET /m8/res80/:id mod8.ts:84:22 index.ts:24:13 880 +route POST /m8/res81/:id mod8.ts:85:23 index.ts:24:13 881 +route PUT /m8/res82/:id mod8.ts:86:22 index.ts:24:13 882 +route DELETE /m8/res83/:id mod8.ts:87:25 index.ts:24:13 883 +route PATCH /m8/res84/:id mod8.ts:88:24 index.ts:24:13 884 +route GET /m8/res85/:id mod8.ts:89:22 index.ts:24:13 885 +route POST /m8/res86/:id mod8.ts:90:23 index.ts:24:13 886 +route PUT /m8/res87/:id mod8.ts:91:22 index.ts:24:13 887 +route DELETE /m8/res88/:id mod8.ts:92:25 index.ts:24:13 888 +route PATCH /m8/res89/:id mod8.ts:93:24 index.ts:24:13 889 +route GET /m8/res90/:id mod8.ts:94:22 index.ts:24:13 890 +route POST /m8/res91/:id mod8.ts:95:23 index.ts:24:13 891 +route PUT /m8/res92/:id mod8.ts:96:22 index.ts:24:13 892 +route DELETE /m8/res93/:id mod8.ts:97:25 index.ts:24:13 893 +route PATCH /m8/res94/:id mod8.ts:98:24 index.ts:24:13 894 +route GET /m8/res95/:id mod8.ts:99:22 index.ts:24:13 895 +route POST /m8/res96/:id mod8.ts:100:23 index.ts:24:13 896 +route PUT /m8/res97/:id mod8.ts:101:22 index.ts:24:13 897 +route DELETE /m8/res98/:id mod8.ts:102:25 index.ts:24:13 898 +route PATCH /m8/res99/:id mod8.ts:103:24 index.ts:24:13 899 +route GET /m9/res0/:id mod9.ts:4:21 index.ts:24:13 900 +route POST /m9/res1/:id mod9.ts:5:22 index.ts:24:13 901 +route PUT /m9/res2/:id mod9.ts:6:21 index.ts:24:13 902 +route DELETE /m9/res3/:id mod9.ts:7:24 index.ts:24:13 903 +route PATCH /m9/res4/:id mod9.ts:8:23 index.ts:24:13 904 +route GET /m9/res5/:id mod9.ts:9:21 index.ts:24:13 905 +route POST /m9/res6/:id mod9.ts:10:22 index.ts:24:13 906 +route PUT /m9/res7/:id mod9.ts:11:21 index.ts:24:13 907 +route DELETE /m9/res8/:id mod9.ts:12:24 index.ts:24:13 908 +route PATCH /m9/res9/:id mod9.ts:13:23 index.ts:24:13 909 +route GET /m9/res10/:id mod9.ts:14:22 index.ts:24:13 910 +route POST /m9/res11/:id mod9.ts:15:23 index.ts:24:13 911 +route PUT /m9/res12/:id mod9.ts:16:22 index.ts:24:13 912 +route DELETE /m9/res13/:id mod9.ts:17:25 index.ts:24:13 913 +route PATCH /m9/res14/:id mod9.ts:18:24 index.ts:24:13 914 +route GET /m9/res15/:id mod9.ts:19:22 index.ts:24:13 915 +route POST /m9/res16/:id mod9.ts:20:23 index.ts:24:13 916 +route PUT /m9/res17/:id mod9.ts:21:22 index.ts:24:13 917 +route DELETE /m9/res18/:id mod9.ts:22:25 index.ts:24:13 918 +route PATCH /m9/res19/:id mod9.ts:23:24 index.ts:24:13 919 +route GET /m9/res20/:id mod9.ts:24:22 index.ts:24:13 920 +route POST /m9/res21/:id mod9.ts:25:23 index.ts:24:13 921 +route PUT /m9/res22/:id mod9.ts:26:22 index.ts:24:13 922 +route DELETE /m9/res23/:id mod9.ts:27:25 index.ts:24:13 923 +route PATCH /m9/res24/:id mod9.ts:28:24 index.ts:24:13 924 +route GET /m9/res25/:id mod9.ts:29:22 index.ts:24:13 925 +route POST /m9/res26/:id mod9.ts:30:23 index.ts:24:13 926 +route PUT /m9/res27/:id mod9.ts:31:22 index.ts:24:13 927 +route DELETE /m9/res28/:id mod9.ts:32:25 index.ts:24:13 928 +route PATCH /m9/res29/:id mod9.ts:33:24 index.ts:24:13 929 +route GET /m9/res30/:id mod9.ts:34:22 index.ts:24:13 930 +route POST /m9/res31/:id mod9.ts:35:23 index.ts:24:13 931 +route PUT /m9/res32/:id mod9.ts:36:22 index.ts:24:13 932 +route DELETE /m9/res33/:id mod9.ts:37:25 index.ts:24:13 933 +route PATCH /m9/res34/:id mod9.ts:38:24 index.ts:24:13 934 +route GET /m9/res35/:id mod9.ts:39:22 index.ts:24:13 935 +route POST /m9/res36/:id mod9.ts:40:23 index.ts:24:13 936 +route PUT /m9/res37/:id mod9.ts:41:22 index.ts:24:13 937 +route DELETE /m9/res38/:id mod9.ts:42:25 index.ts:24:13 938 +route PATCH /m9/res39/:id mod9.ts:43:24 index.ts:24:13 939 +route GET /m9/res40/:id mod9.ts:44:22 index.ts:24:13 940 +route POST /m9/res41/:id mod9.ts:45:23 index.ts:24:13 941 +route PUT /m9/res42/:id mod9.ts:46:22 index.ts:24:13 942 +route DELETE /m9/res43/:id mod9.ts:47:25 index.ts:24:13 943 +route PATCH /m9/res44/:id mod9.ts:48:24 index.ts:24:13 944 +route GET /m9/res45/:id mod9.ts:49:22 index.ts:24:13 945 +route POST /m9/res46/:id mod9.ts:50:23 index.ts:24:13 946 +route PUT /m9/res47/:id mod9.ts:51:22 index.ts:24:13 947 +route DELETE /m9/res48/:id mod9.ts:52:25 index.ts:24:13 948 +route PATCH /m9/res49/:id mod9.ts:53:24 index.ts:24:13 949 +route GET /m9/res50/:id mod9.ts:54:22 index.ts:24:13 950 +route POST /m9/res51/:id mod9.ts:55:23 index.ts:24:13 951 +route PUT /m9/res52/:id mod9.ts:56:22 index.ts:24:13 952 +route DELETE /m9/res53/:id mod9.ts:57:25 index.ts:24:13 953 +route PATCH /m9/res54/:id mod9.ts:58:24 index.ts:24:13 954 +route GET /m9/res55/:id mod9.ts:59:22 index.ts:24:13 955 +route POST /m9/res56/:id mod9.ts:60:23 index.ts:24:13 956 +route PUT /m9/res57/:id mod9.ts:61:22 index.ts:24:13 957 +route DELETE /m9/res58/:id mod9.ts:62:25 index.ts:24:13 958 +route PATCH /m9/res59/:id mod9.ts:63:24 index.ts:24:13 959 +route GET /m9/res60/:id mod9.ts:64:22 index.ts:24:13 960 +route POST /m9/res61/:id mod9.ts:65:23 index.ts:24:13 961 +route PUT /m9/res62/:id mod9.ts:66:22 index.ts:24:13 962 +route DELETE /m9/res63/:id mod9.ts:67:25 index.ts:24:13 963 +route PATCH /m9/res64/:id mod9.ts:68:24 index.ts:24:13 964 +route GET /m9/res65/:id mod9.ts:69:22 index.ts:24:13 965 +route POST /m9/res66/:id mod9.ts:70:23 index.ts:24:13 966 +route PUT /m9/res67/:id mod9.ts:71:22 index.ts:24:13 967 +route DELETE /m9/res68/:id mod9.ts:72:25 index.ts:24:13 968 +route PATCH /m9/res69/:id mod9.ts:73:24 index.ts:24:13 969 +route GET /m9/res70/:id mod9.ts:74:22 index.ts:24:13 970 +route POST /m9/res71/:id mod9.ts:75:23 index.ts:24:13 971 +route PUT /m9/res72/:id mod9.ts:76:22 index.ts:24:13 972 +route DELETE /m9/res73/:id mod9.ts:77:25 index.ts:24:13 973 +route PATCH /m9/res74/:id mod9.ts:78:24 index.ts:24:13 974 +route GET /m9/res75/:id mod9.ts:79:22 index.ts:24:13 975 +route POST /m9/res76/:id mod9.ts:80:23 index.ts:24:13 976 +route PUT /m9/res77/:id mod9.ts:81:22 index.ts:24:13 977 +route DELETE /m9/res78/:id mod9.ts:82:25 index.ts:24:13 978 +route PATCH /m9/res79/:id mod9.ts:83:24 index.ts:24:13 979 +route GET /m9/res80/:id mod9.ts:84:22 index.ts:24:13 980 +route POST /m9/res81/:id mod9.ts:85:23 index.ts:24:13 981 +route PUT /m9/res82/:id mod9.ts:86:22 index.ts:24:13 982 +route DELETE /m9/res83/:id mod9.ts:87:25 index.ts:24:13 983 +route PATCH /m9/res84/:id mod9.ts:88:24 index.ts:24:13 984 +route GET /m9/res85/:id mod9.ts:89:22 index.ts:24:13 985 +route POST /m9/res86/:id mod9.ts:90:23 index.ts:24:13 986 +route PUT /m9/res87/:id mod9.ts:91:22 index.ts:24:13 987 +route DELETE /m9/res88/:id mod9.ts:92:25 index.ts:24:13 988 +route PATCH /m9/res89/:id mod9.ts:93:24 index.ts:24:13 989 +route GET /m9/res90/:id mod9.ts:94:22 index.ts:24:13 990 +route POST /m9/res91/:id mod9.ts:95:23 index.ts:24:13 991 +route PUT /m9/res92/:id mod9.ts:96:22 index.ts:24:13 992 +route DELETE /m9/res93/:id mod9.ts:97:25 index.ts:24:13 993 +route PATCH /m9/res94/:id mod9.ts:98:24 index.ts:24:13 994 +route GET /m9/res95/:id mod9.ts:99:22 index.ts:24:13 995 +route POST /m9/res96/:id mod9.ts:100:23 index.ts:24:13 996 +route PUT /m9/res97/:id mod9.ts:101:22 index.ts:24:13 997 +route DELETE /m9/res98/:id mod9.ts:102:25 index.ts:24:13 998 +route PATCH /m9/res99/:id mod9.ts:103:24 index.ts:24:13 999 +route GET /m10/res0/:id mod10.ts:4:22 index.ts:24:13 1000 +route POST /m10/res1/:id mod10.ts:5:23 index.ts:24:13 1001 +route PUT /m10/res2/:id mod10.ts:6:22 index.ts:24:13 1002 +route DELETE /m10/res3/:id mod10.ts:7:25 index.ts:24:13 1003 +route PATCH /m10/res4/:id mod10.ts:8:24 index.ts:24:13 1004 +route GET /m10/res5/:id mod10.ts:9:22 index.ts:24:13 1005 +route POST /m10/res6/:id mod10.ts:10:23 index.ts:24:13 1006 +route PUT /m10/res7/:id mod10.ts:11:22 index.ts:24:13 1007 +route DELETE /m10/res8/:id mod10.ts:12:25 index.ts:24:13 1008 +route PATCH /m10/res9/:id mod10.ts:13:24 index.ts:24:13 1009 +route GET /m10/res10/:id mod10.ts:14:23 index.ts:24:13 1010 +route POST /m10/res11/:id mod10.ts:15:24 index.ts:24:13 1011 +route PUT /m10/res12/:id mod10.ts:16:23 index.ts:24:13 1012 +route DELETE /m10/res13/:id mod10.ts:17:26 index.ts:24:13 1013 +route PATCH /m10/res14/:id mod10.ts:18:25 index.ts:24:13 1014 +route GET /m10/res15/:id mod10.ts:19:23 index.ts:24:13 1015 +route POST /m10/res16/:id mod10.ts:20:24 index.ts:24:13 1016 +route PUT /m10/res17/:id mod10.ts:21:23 index.ts:24:13 1017 +route DELETE /m10/res18/:id mod10.ts:22:26 index.ts:24:13 1018 +route PATCH /m10/res19/:id mod10.ts:23:25 index.ts:24:13 1019 +route GET /m10/res20/:id mod10.ts:24:23 index.ts:24:13 1020 +route POST /m10/res21/:id mod10.ts:25:24 index.ts:24:13 1021 +route PUT /m10/res22/:id mod10.ts:26:23 index.ts:24:13 1022 +route DELETE /m10/res23/:id mod10.ts:27:26 index.ts:24:13 1023 +route PATCH /m10/res24/:id mod10.ts:28:25 index.ts:24:13 1024 +route GET /m10/res25/:id mod10.ts:29:23 index.ts:24:13 1025 +route POST /m10/res26/:id mod10.ts:30:24 index.ts:24:13 1026 +route PUT /m10/res27/:id mod10.ts:31:23 index.ts:24:13 1027 +route DELETE /m10/res28/:id mod10.ts:32:26 index.ts:24:13 1028 +route PATCH /m10/res29/:id mod10.ts:33:25 index.ts:24:13 1029 +route GET /m10/res30/:id mod10.ts:34:23 index.ts:24:13 1030 +route POST /m10/res31/:id mod10.ts:35:24 index.ts:24:13 1031 +route PUT /m10/res32/:id mod10.ts:36:23 index.ts:24:13 1032 +route DELETE /m10/res33/:id mod10.ts:37:26 index.ts:24:13 1033 +route PATCH /m10/res34/:id mod10.ts:38:25 index.ts:24:13 1034 +route GET /m10/res35/:id mod10.ts:39:23 index.ts:24:13 1035 +route POST /m10/res36/:id mod10.ts:40:24 index.ts:24:13 1036 +route PUT /m10/res37/:id mod10.ts:41:23 index.ts:24:13 1037 +route DELETE /m10/res38/:id mod10.ts:42:26 index.ts:24:13 1038 +route PATCH /m10/res39/:id mod10.ts:43:25 index.ts:24:13 1039 +route GET /m10/res40/:id mod10.ts:44:23 index.ts:24:13 1040 +route POST /m10/res41/:id mod10.ts:45:24 index.ts:24:13 1041 +route PUT /m10/res42/:id mod10.ts:46:23 index.ts:24:13 1042 +route DELETE /m10/res43/:id mod10.ts:47:26 index.ts:24:13 1043 +route PATCH /m10/res44/:id mod10.ts:48:25 index.ts:24:13 1044 +route GET /m10/res45/:id mod10.ts:49:23 index.ts:24:13 1045 +route POST /m10/res46/:id mod10.ts:50:24 index.ts:24:13 1046 +route PUT /m10/res47/:id mod10.ts:51:23 index.ts:24:13 1047 +route DELETE /m10/res48/:id mod10.ts:52:26 index.ts:24:13 1048 +route PATCH /m10/res49/:id mod10.ts:53:25 index.ts:24:13 1049 +route GET /m10/res50/:id mod10.ts:54:23 index.ts:24:13 1050 +route POST /m10/res51/:id mod10.ts:55:24 index.ts:24:13 1051 +route PUT /m10/res52/:id mod10.ts:56:23 index.ts:24:13 1052 +route DELETE /m10/res53/:id mod10.ts:57:26 index.ts:24:13 1053 +route PATCH /m10/res54/:id mod10.ts:58:25 index.ts:24:13 1054 +route GET /m10/res55/:id mod10.ts:59:23 index.ts:24:13 1055 +route POST /m10/res56/:id mod10.ts:60:24 index.ts:24:13 1056 +route PUT /m10/res57/:id mod10.ts:61:23 index.ts:24:13 1057 +route DELETE /m10/res58/:id mod10.ts:62:26 index.ts:24:13 1058 +route PATCH /m10/res59/:id mod10.ts:63:25 index.ts:24:13 1059 +route GET /m10/res60/:id mod10.ts:64:23 index.ts:24:13 1060 +route POST /m10/res61/:id mod10.ts:65:24 index.ts:24:13 1061 +route PUT /m10/res62/:id mod10.ts:66:23 index.ts:24:13 1062 +route DELETE /m10/res63/:id mod10.ts:67:26 index.ts:24:13 1063 +route PATCH /m10/res64/:id mod10.ts:68:25 index.ts:24:13 1064 +route GET /m10/res65/:id mod10.ts:69:23 index.ts:24:13 1065 +route POST /m10/res66/:id mod10.ts:70:24 index.ts:24:13 1066 +route PUT /m10/res67/:id mod10.ts:71:23 index.ts:24:13 1067 +route DELETE /m10/res68/:id mod10.ts:72:26 index.ts:24:13 1068 +route PATCH /m10/res69/:id mod10.ts:73:25 index.ts:24:13 1069 +route GET /m10/res70/:id mod10.ts:74:23 index.ts:24:13 1070 +route POST /m10/res71/:id mod10.ts:75:24 index.ts:24:13 1071 +route PUT /m10/res72/:id mod10.ts:76:23 index.ts:24:13 1072 +route DELETE /m10/res73/:id mod10.ts:77:26 index.ts:24:13 1073 +route PATCH /m10/res74/:id mod10.ts:78:25 index.ts:24:13 1074 +route GET /m10/res75/:id mod10.ts:79:23 index.ts:24:13 1075 +route POST /m10/res76/:id mod10.ts:80:24 index.ts:24:13 1076 +route PUT /m10/res77/:id mod10.ts:81:23 index.ts:24:13 1077 +route DELETE /m10/res78/:id mod10.ts:82:26 index.ts:24:13 1078 +route PATCH /m10/res79/:id mod10.ts:83:25 index.ts:24:13 1079 +route GET /m10/res80/:id mod10.ts:84:23 index.ts:24:13 1080 +route POST /m10/res81/:id mod10.ts:85:24 index.ts:24:13 1081 +route PUT /m10/res82/:id mod10.ts:86:23 index.ts:24:13 1082 +route DELETE /m10/res83/:id mod10.ts:87:26 index.ts:24:13 1083 +route PATCH /m10/res84/:id mod10.ts:88:25 index.ts:24:13 1084 +route GET /m10/res85/:id mod10.ts:89:23 index.ts:24:13 1085 +route POST /m10/res86/:id mod10.ts:90:24 index.ts:24:13 1086 +route PUT /m10/res87/:id mod10.ts:91:23 index.ts:24:13 1087 +route DELETE /m10/res88/:id mod10.ts:92:26 index.ts:24:13 1088 +route PATCH /m10/res89/:id mod10.ts:93:25 index.ts:24:13 1089 +route GET /m10/res90/:id mod10.ts:94:23 index.ts:24:13 1090 +route POST /m10/res91/:id mod10.ts:95:24 index.ts:24:13 1091 +route PUT /m10/res92/:id mod10.ts:96:23 index.ts:24:13 1092 +route DELETE /m10/res93/:id mod10.ts:97:26 index.ts:24:13 1093 +route PATCH /m10/res94/:id mod10.ts:98:25 index.ts:24:13 1094 +route GET /m10/res95/:id mod10.ts:99:23 index.ts:24:13 1095 +route POST /m10/res96/:id mod10.ts:100:24 index.ts:24:13 1096 +route PUT /m10/res97/:id mod10.ts:101:23 index.ts:24:13 1097 +route DELETE /m10/res98/:id mod10.ts:102:26 index.ts:24:13 1098 +route PATCH /m10/res99/:id mod10.ts:103:25 index.ts:24:13 1099 +route GET /m11/res0/:id mod11.ts:4:22 index.ts:24:13 1100 +route POST /m11/res1/:id mod11.ts:5:23 index.ts:24:13 1101 +route PUT /m11/res2/:id mod11.ts:6:22 index.ts:24:13 1102 +route DELETE /m11/res3/:id mod11.ts:7:25 index.ts:24:13 1103 +route PATCH /m11/res4/:id mod11.ts:8:24 index.ts:24:13 1104 +route GET /m11/res5/:id mod11.ts:9:22 index.ts:24:13 1105 +route POST /m11/res6/:id mod11.ts:10:23 index.ts:24:13 1106 +route PUT /m11/res7/:id mod11.ts:11:22 index.ts:24:13 1107 +route DELETE /m11/res8/:id mod11.ts:12:25 index.ts:24:13 1108 +route PATCH /m11/res9/:id mod11.ts:13:24 index.ts:24:13 1109 +route GET /m11/res10/:id mod11.ts:14:23 index.ts:24:13 1110 +route POST /m11/res11/:id mod11.ts:15:24 index.ts:24:13 1111 +route PUT /m11/res12/:id mod11.ts:16:23 index.ts:24:13 1112 +route DELETE /m11/res13/:id mod11.ts:17:26 index.ts:24:13 1113 +route PATCH /m11/res14/:id mod11.ts:18:25 index.ts:24:13 1114 +route GET /m11/res15/:id mod11.ts:19:23 index.ts:24:13 1115 +route POST /m11/res16/:id mod11.ts:20:24 index.ts:24:13 1116 +route PUT /m11/res17/:id mod11.ts:21:23 index.ts:24:13 1117 +route DELETE /m11/res18/:id mod11.ts:22:26 index.ts:24:13 1118 +route PATCH /m11/res19/:id mod11.ts:23:25 index.ts:24:13 1119 +route GET /m11/res20/:id mod11.ts:24:23 index.ts:24:13 1120 +route POST /m11/res21/:id mod11.ts:25:24 index.ts:24:13 1121 +route PUT /m11/res22/:id mod11.ts:26:23 index.ts:24:13 1122 +route DELETE /m11/res23/:id mod11.ts:27:26 index.ts:24:13 1123 +route PATCH /m11/res24/:id mod11.ts:28:25 index.ts:24:13 1124 +route GET /m11/res25/:id mod11.ts:29:23 index.ts:24:13 1125 +route POST /m11/res26/:id mod11.ts:30:24 index.ts:24:13 1126 +route PUT /m11/res27/:id mod11.ts:31:23 index.ts:24:13 1127 +route DELETE /m11/res28/:id mod11.ts:32:26 index.ts:24:13 1128 +route PATCH /m11/res29/:id mod11.ts:33:25 index.ts:24:13 1129 +route GET /m11/res30/:id mod11.ts:34:23 index.ts:24:13 1130 +route POST /m11/res31/:id mod11.ts:35:24 index.ts:24:13 1131 +route PUT /m11/res32/:id mod11.ts:36:23 index.ts:24:13 1132 +route DELETE /m11/res33/:id mod11.ts:37:26 index.ts:24:13 1133 +route PATCH /m11/res34/:id mod11.ts:38:25 index.ts:24:13 1134 +route GET /m11/res35/:id mod11.ts:39:23 index.ts:24:13 1135 +route POST /m11/res36/:id mod11.ts:40:24 index.ts:24:13 1136 +route PUT /m11/res37/:id mod11.ts:41:23 index.ts:24:13 1137 +route DELETE /m11/res38/:id mod11.ts:42:26 index.ts:24:13 1138 +route PATCH /m11/res39/:id mod11.ts:43:25 index.ts:24:13 1139 +route GET /m11/res40/:id mod11.ts:44:23 index.ts:24:13 1140 +route POST /m11/res41/:id mod11.ts:45:24 index.ts:24:13 1141 +route PUT /m11/res42/:id mod11.ts:46:23 index.ts:24:13 1142 +route DELETE /m11/res43/:id mod11.ts:47:26 index.ts:24:13 1143 +route PATCH /m11/res44/:id mod11.ts:48:25 index.ts:24:13 1144 +route GET /m11/res45/:id mod11.ts:49:23 index.ts:24:13 1145 +route POST /m11/res46/:id mod11.ts:50:24 index.ts:24:13 1146 +route PUT /m11/res47/:id mod11.ts:51:23 index.ts:24:13 1147 +route DELETE /m11/res48/:id mod11.ts:52:26 index.ts:24:13 1148 +route PATCH /m11/res49/:id mod11.ts:53:25 index.ts:24:13 1149 +route GET /m11/res50/:id mod11.ts:54:23 index.ts:24:13 1150 +route POST /m11/res51/:id mod11.ts:55:24 index.ts:24:13 1151 +route PUT /m11/res52/:id mod11.ts:56:23 index.ts:24:13 1152 +route DELETE /m11/res53/:id mod11.ts:57:26 index.ts:24:13 1153 +route PATCH /m11/res54/:id mod11.ts:58:25 index.ts:24:13 1154 +route GET /m11/res55/:id mod11.ts:59:23 index.ts:24:13 1155 +route POST /m11/res56/:id mod11.ts:60:24 index.ts:24:13 1156 +route PUT /m11/res57/:id mod11.ts:61:23 index.ts:24:13 1157 +route DELETE /m11/res58/:id mod11.ts:62:26 index.ts:24:13 1158 +route PATCH /m11/res59/:id mod11.ts:63:25 index.ts:24:13 1159 +route GET /m11/res60/:id mod11.ts:64:23 index.ts:24:13 1160 +route POST /m11/res61/:id mod11.ts:65:24 index.ts:24:13 1161 +route PUT /m11/res62/:id mod11.ts:66:23 index.ts:24:13 1162 +route DELETE /m11/res63/:id mod11.ts:67:26 index.ts:24:13 1163 +route PATCH /m11/res64/:id mod11.ts:68:25 index.ts:24:13 1164 +route GET /m11/res65/:id mod11.ts:69:23 index.ts:24:13 1165 +route POST /m11/res66/:id mod11.ts:70:24 index.ts:24:13 1166 +route PUT /m11/res67/:id mod11.ts:71:23 index.ts:24:13 1167 +route DELETE /m11/res68/:id mod11.ts:72:26 index.ts:24:13 1168 +route PATCH /m11/res69/:id mod11.ts:73:25 index.ts:24:13 1169 +route GET /m11/res70/:id mod11.ts:74:23 index.ts:24:13 1170 +route POST /m11/res71/:id mod11.ts:75:24 index.ts:24:13 1171 +route PUT /m11/res72/:id mod11.ts:76:23 index.ts:24:13 1172 +route DELETE /m11/res73/:id mod11.ts:77:26 index.ts:24:13 1173 +route PATCH /m11/res74/:id mod11.ts:78:25 index.ts:24:13 1174 +route GET /m11/res75/:id mod11.ts:79:23 index.ts:24:13 1175 +route POST /m11/res76/:id mod11.ts:80:24 index.ts:24:13 1176 +route PUT /m11/res77/:id mod11.ts:81:23 index.ts:24:13 1177 +route DELETE /m11/res78/:id mod11.ts:82:26 index.ts:24:13 1178 +route PATCH /m11/res79/:id mod11.ts:83:25 index.ts:24:13 1179 +route GET /m11/res80/:id mod11.ts:84:23 index.ts:24:13 1180 +route POST /m11/res81/:id mod11.ts:85:24 index.ts:24:13 1181 +route PUT /m11/res82/:id mod11.ts:86:23 index.ts:24:13 1182 +route DELETE /m11/res83/:id mod11.ts:87:26 index.ts:24:13 1183 +route PATCH /m11/res84/:id mod11.ts:88:25 index.ts:24:13 1184 +route GET /m11/res85/:id mod11.ts:89:23 index.ts:24:13 1185 +route POST /m11/res86/:id mod11.ts:90:24 index.ts:24:13 1186 +route PUT /m11/res87/:id mod11.ts:91:23 index.ts:24:13 1187 +route DELETE /m11/res88/:id mod11.ts:92:26 index.ts:24:13 1188 +route PATCH /m11/res89/:id mod11.ts:93:25 index.ts:24:13 1189 +route GET /m11/res90/:id mod11.ts:94:23 index.ts:24:13 1190 +route POST /m11/res91/:id mod11.ts:95:24 index.ts:24:13 1191 +route PUT /m11/res92/:id mod11.ts:96:23 index.ts:24:13 1192 +route DELETE /m11/res93/:id mod11.ts:97:26 index.ts:24:13 1193 +route PATCH /m11/res94/:id mod11.ts:98:25 index.ts:24:13 1194 +route GET /m11/res95/:id mod11.ts:99:23 index.ts:24:13 1195 +route POST /m11/res96/:id mod11.ts:100:24 index.ts:24:13 1196 +route PUT /m11/res97/:id mod11.ts:101:23 index.ts:24:13 1197 +route DELETE /m11/res98/:id mod11.ts:102:26 index.ts:24:13 1198 +route PATCH /m11/res99/:id mod11.ts:103:25 index.ts:24:13 1199 +route GET /m12/res0/:id mod12.ts:4:22 index.ts:24:13 1200 +route POST /m12/res1/:id mod12.ts:5:23 index.ts:24:13 1201 +route PUT /m12/res2/:id mod12.ts:6:22 index.ts:24:13 1202 +route DELETE /m12/res3/:id mod12.ts:7:25 index.ts:24:13 1203 +route PATCH /m12/res4/:id mod12.ts:8:24 index.ts:24:13 1204 +route GET /m12/res5/:id mod12.ts:9:22 index.ts:24:13 1205 +route POST /m12/res6/:id mod12.ts:10:23 index.ts:24:13 1206 +route PUT /m12/res7/:id mod12.ts:11:22 index.ts:24:13 1207 +route DELETE /m12/res8/:id mod12.ts:12:25 index.ts:24:13 1208 +route PATCH /m12/res9/:id mod12.ts:13:24 index.ts:24:13 1209 +route GET /m12/res10/:id mod12.ts:14:23 index.ts:24:13 1210 +route POST /m12/res11/:id mod12.ts:15:24 index.ts:24:13 1211 +route PUT /m12/res12/:id mod12.ts:16:23 index.ts:24:13 1212 +route DELETE /m12/res13/:id mod12.ts:17:26 index.ts:24:13 1213 +route PATCH /m12/res14/:id mod12.ts:18:25 index.ts:24:13 1214 +route GET /m12/res15/:id mod12.ts:19:23 index.ts:24:13 1215 +route POST /m12/res16/:id mod12.ts:20:24 index.ts:24:13 1216 +route PUT /m12/res17/:id mod12.ts:21:23 index.ts:24:13 1217 +route DELETE /m12/res18/:id mod12.ts:22:26 index.ts:24:13 1218 +route PATCH /m12/res19/:id mod12.ts:23:25 index.ts:24:13 1219 +route GET /m12/res20/:id mod12.ts:24:23 index.ts:24:13 1220 +route POST /m12/res21/:id mod12.ts:25:24 index.ts:24:13 1221 +route PUT /m12/res22/:id mod12.ts:26:23 index.ts:24:13 1222 +route DELETE /m12/res23/:id mod12.ts:27:26 index.ts:24:13 1223 +route PATCH /m12/res24/:id mod12.ts:28:25 index.ts:24:13 1224 +route GET /m12/res25/:id mod12.ts:29:23 index.ts:24:13 1225 +route POST /m12/res26/:id mod12.ts:30:24 index.ts:24:13 1226 +route PUT /m12/res27/:id mod12.ts:31:23 index.ts:24:13 1227 +route DELETE /m12/res28/:id mod12.ts:32:26 index.ts:24:13 1228 +route PATCH /m12/res29/:id mod12.ts:33:25 index.ts:24:13 1229 +route GET /m12/res30/:id mod12.ts:34:23 index.ts:24:13 1230 +route POST /m12/res31/:id mod12.ts:35:24 index.ts:24:13 1231 +route PUT /m12/res32/:id mod12.ts:36:23 index.ts:24:13 1232 +route DELETE /m12/res33/:id mod12.ts:37:26 index.ts:24:13 1233 +route PATCH /m12/res34/:id mod12.ts:38:25 index.ts:24:13 1234 +route GET /m12/res35/:id mod12.ts:39:23 index.ts:24:13 1235 +route POST /m12/res36/:id mod12.ts:40:24 index.ts:24:13 1236 +route PUT /m12/res37/:id mod12.ts:41:23 index.ts:24:13 1237 +route DELETE /m12/res38/:id mod12.ts:42:26 index.ts:24:13 1238 +route PATCH /m12/res39/:id mod12.ts:43:25 index.ts:24:13 1239 +route GET /m12/res40/:id mod12.ts:44:23 index.ts:24:13 1240 +route POST /m12/res41/:id mod12.ts:45:24 index.ts:24:13 1241 +route PUT /m12/res42/:id mod12.ts:46:23 index.ts:24:13 1242 +route DELETE /m12/res43/:id mod12.ts:47:26 index.ts:24:13 1243 +route PATCH /m12/res44/:id mod12.ts:48:25 index.ts:24:13 1244 +route GET /m12/res45/:id mod12.ts:49:23 index.ts:24:13 1245 +route POST /m12/res46/:id mod12.ts:50:24 index.ts:24:13 1246 +route PUT /m12/res47/:id mod12.ts:51:23 index.ts:24:13 1247 +route DELETE /m12/res48/:id mod12.ts:52:26 index.ts:24:13 1248 +route PATCH /m12/res49/:id mod12.ts:53:25 index.ts:24:13 1249 +route GET /m12/res50/:id mod12.ts:54:23 index.ts:24:13 1250 +route POST /m12/res51/:id mod12.ts:55:24 index.ts:24:13 1251 +route PUT /m12/res52/:id mod12.ts:56:23 index.ts:24:13 1252 +route DELETE /m12/res53/:id mod12.ts:57:26 index.ts:24:13 1253 +route PATCH /m12/res54/:id mod12.ts:58:25 index.ts:24:13 1254 +route GET /m12/res55/:id mod12.ts:59:23 index.ts:24:13 1255 +route POST /m12/res56/:id mod12.ts:60:24 index.ts:24:13 1256 +route PUT /m12/res57/:id mod12.ts:61:23 index.ts:24:13 1257 +route DELETE /m12/res58/:id mod12.ts:62:26 index.ts:24:13 1258 +route PATCH /m12/res59/:id mod12.ts:63:25 index.ts:24:13 1259 +route GET /m12/res60/:id mod12.ts:64:23 index.ts:24:13 1260 +route POST /m12/res61/:id mod12.ts:65:24 index.ts:24:13 1261 +route PUT /m12/res62/:id mod12.ts:66:23 index.ts:24:13 1262 +route DELETE /m12/res63/:id mod12.ts:67:26 index.ts:24:13 1263 +route PATCH /m12/res64/:id mod12.ts:68:25 index.ts:24:13 1264 +route GET /m12/res65/:id mod12.ts:69:23 index.ts:24:13 1265 +route POST /m12/res66/:id mod12.ts:70:24 index.ts:24:13 1266 +route PUT /m12/res67/:id mod12.ts:71:23 index.ts:24:13 1267 +route DELETE /m12/res68/:id mod12.ts:72:26 index.ts:24:13 1268 +route PATCH /m12/res69/:id mod12.ts:73:25 index.ts:24:13 1269 +route GET /m12/res70/:id mod12.ts:74:23 index.ts:24:13 1270 +route POST /m12/res71/:id mod12.ts:75:24 index.ts:24:13 1271 +route PUT /m12/res72/:id mod12.ts:76:23 index.ts:24:13 1272 +route DELETE /m12/res73/:id mod12.ts:77:26 index.ts:24:13 1273 +route PATCH /m12/res74/:id mod12.ts:78:25 index.ts:24:13 1274 +route GET /m12/res75/:id mod12.ts:79:23 index.ts:24:13 1275 +route POST /m12/res76/:id mod12.ts:80:24 index.ts:24:13 1276 +route PUT /m12/res77/:id mod12.ts:81:23 index.ts:24:13 1277 +route DELETE /m12/res78/:id mod12.ts:82:26 index.ts:24:13 1278 +route PATCH /m12/res79/:id mod12.ts:83:25 index.ts:24:13 1279 +route GET /m12/res80/:id mod12.ts:84:23 index.ts:24:13 1280 +route POST /m12/res81/:id mod12.ts:85:24 index.ts:24:13 1281 +route PUT /m12/res82/:id mod12.ts:86:23 index.ts:24:13 1282 +route DELETE /m12/res83/:id mod12.ts:87:26 index.ts:24:13 1283 +route PATCH /m12/res84/:id mod12.ts:88:25 index.ts:24:13 1284 +route GET /m12/res85/:id mod12.ts:89:23 index.ts:24:13 1285 +route POST /m12/res86/:id mod12.ts:90:24 index.ts:24:13 1286 +route PUT /m12/res87/:id mod12.ts:91:23 index.ts:24:13 1287 +route DELETE /m12/res88/:id mod12.ts:92:26 index.ts:24:13 1288 +route PATCH /m12/res89/:id mod12.ts:93:25 index.ts:24:13 1289 +route GET /m12/res90/:id mod12.ts:94:23 index.ts:24:13 1290 +route POST /m12/res91/:id mod12.ts:95:24 index.ts:24:13 1291 +route PUT /m12/res92/:id mod12.ts:96:23 index.ts:24:13 1292 +route DELETE /m12/res93/:id mod12.ts:97:26 index.ts:24:13 1293 +route PATCH /m12/res94/:id mod12.ts:98:25 index.ts:24:13 1294 +route GET /m12/res95/:id mod12.ts:99:23 index.ts:24:13 1295 +route POST /m12/res96/:id mod12.ts:100:24 index.ts:24:13 1296 +route PUT /m12/res97/:id mod12.ts:101:23 index.ts:24:13 1297 +route DELETE /m12/res98/:id mod12.ts:102:26 index.ts:24:13 1298 +route PATCH /m12/res99/:id mod12.ts:103:25 index.ts:24:13 1299 +route GET /m13/res0/:id mod13.ts:4:22 index.ts:24:13 1300 +route POST /m13/res1/:id mod13.ts:5:23 index.ts:24:13 1301 +route PUT /m13/res2/:id mod13.ts:6:22 index.ts:24:13 1302 +route DELETE /m13/res3/:id mod13.ts:7:25 index.ts:24:13 1303 +route PATCH /m13/res4/:id mod13.ts:8:24 index.ts:24:13 1304 +route GET /m13/res5/:id mod13.ts:9:22 index.ts:24:13 1305 +route POST /m13/res6/:id mod13.ts:10:23 index.ts:24:13 1306 +route PUT /m13/res7/:id mod13.ts:11:22 index.ts:24:13 1307 +route DELETE /m13/res8/:id mod13.ts:12:25 index.ts:24:13 1308 +route PATCH /m13/res9/:id mod13.ts:13:24 index.ts:24:13 1309 +route GET /m13/res10/:id mod13.ts:14:23 index.ts:24:13 1310 +route POST /m13/res11/:id mod13.ts:15:24 index.ts:24:13 1311 +route PUT /m13/res12/:id mod13.ts:16:23 index.ts:24:13 1312 +route DELETE /m13/res13/:id mod13.ts:17:26 index.ts:24:13 1313 +route PATCH /m13/res14/:id mod13.ts:18:25 index.ts:24:13 1314 +route GET /m13/res15/:id mod13.ts:19:23 index.ts:24:13 1315 +route POST /m13/res16/:id mod13.ts:20:24 index.ts:24:13 1316 +route PUT /m13/res17/:id mod13.ts:21:23 index.ts:24:13 1317 +route DELETE /m13/res18/:id mod13.ts:22:26 index.ts:24:13 1318 +route PATCH /m13/res19/:id mod13.ts:23:25 index.ts:24:13 1319 +route GET /m13/res20/:id mod13.ts:24:23 index.ts:24:13 1320 +route POST /m13/res21/:id mod13.ts:25:24 index.ts:24:13 1321 +route PUT /m13/res22/:id mod13.ts:26:23 index.ts:24:13 1322 +route DELETE /m13/res23/:id mod13.ts:27:26 index.ts:24:13 1323 +route PATCH /m13/res24/:id mod13.ts:28:25 index.ts:24:13 1324 +route GET /m13/res25/:id mod13.ts:29:23 index.ts:24:13 1325 +route POST /m13/res26/:id mod13.ts:30:24 index.ts:24:13 1326 +route PUT /m13/res27/:id mod13.ts:31:23 index.ts:24:13 1327 +route DELETE /m13/res28/:id mod13.ts:32:26 index.ts:24:13 1328 +route PATCH /m13/res29/:id mod13.ts:33:25 index.ts:24:13 1329 +route GET /m13/res30/:id mod13.ts:34:23 index.ts:24:13 1330 +route POST /m13/res31/:id mod13.ts:35:24 index.ts:24:13 1331 +route PUT /m13/res32/:id mod13.ts:36:23 index.ts:24:13 1332 +route DELETE /m13/res33/:id mod13.ts:37:26 index.ts:24:13 1333 +route PATCH /m13/res34/:id mod13.ts:38:25 index.ts:24:13 1334 +route GET /m13/res35/:id mod13.ts:39:23 index.ts:24:13 1335 +route POST /m13/res36/:id mod13.ts:40:24 index.ts:24:13 1336 +route PUT /m13/res37/:id mod13.ts:41:23 index.ts:24:13 1337 +route DELETE /m13/res38/:id mod13.ts:42:26 index.ts:24:13 1338 +route PATCH /m13/res39/:id mod13.ts:43:25 index.ts:24:13 1339 +route GET /m13/res40/:id mod13.ts:44:23 index.ts:24:13 1340 +route POST /m13/res41/:id mod13.ts:45:24 index.ts:24:13 1341 +route PUT /m13/res42/:id mod13.ts:46:23 index.ts:24:13 1342 +route DELETE /m13/res43/:id mod13.ts:47:26 index.ts:24:13 1343 +route PATCH /m13/res44/:id mod13.ts:48:25 index.ts:24:13 1344 +route GET /m13/res45/:id mod13.ts:49:23 index.ts:24:13 1345 +route POST /m13/res46/:id mod13.ts:50:24 index.ts:24:13 1346 +route PUT /m13/res47/:id mod13.ts:51:23 index.ts:24:13 1347 +route DELETE /m13/res48/:id mod13.ts:52:26 index.ts:24:13 1348 +route PATCH /m13/res49/:id mod13.ts:53:25 index.ts:24:13 1349 +route GET /m13/res50/:id mod13.ts:54:23 index.ts:24:13 1350 +route POST /m13/res51/:id mod13.ts:55:24 index.ts:24:13 1351 +route PUT /m13/res52/:id mod13.ts:56:23 index.ts:24:13 1352 +route DELETE /m13/res53/:id mod13.ts:57:26 index.ts:24:13 1353 +route PATCH /m13/res54/:id mod13.ts:58:25 index.ts:24:13 1354 +route GET /m13/res55/:id mod13.ts:59:23 index.ts:24:13 1355 +route POST /m13/res56/:id mod13.ts:60:24 index.ts:24:13 1356 +route PUT /m13/res57/:id mod13.ts:61:23 index.ts:24:13 1357 +route DELETE /m13/res58/:id mod13.ts:62:26 index.ts:24:13 1358 +route PATCH /m13/res59/:id mod13.ts:63:25 index.ts:24:13 1359 +route GET /m13/res60/:id mod13.ts:64:23 index.ts:24:13 1360 +route POST /m13/res61/:id mod13.ts:65:24 index.ts:24:13 1361 +route PUT /m13/res62/:id mod13.ts:66:23 index.ts:24:13 1362 +route DELETE /m13/res63/:id mod13.ts:67:26 index.ts:24:13 1363 +route PATCH /m13/res64/:id mod13.ts:68:25 index.ts:24:13 1364 +route GET /m13/res65/:id mod13.ts:69:23 index.ts:24:13 1365 +route POST /m13/res66/:id mod13.ts:70:24 index.ts:24:13 1366 +route PUT /m13/res67/:id mod13.ts:71:23 index.ts:24:13 1367 +route DELETE /m13/res68/:id mod13.ts:72:26 index.ts:24:13 1368 +route PATCH /m13/res69/:id mod13.ts:73:25 index.ts:24:13 1369 +route GET /m13/res70/:id mod13.ts:74:23 index.ts:24:13 1370 +route POST /m13/res71/:id mod13.ts:75:24 index.ts:24:13 1371 +route PUT /m13/res72/:id mod13.ts:76:23 index.ts:24:13 1372 +route DELETE /m13/res73/:id mod13.ts:77:26 index.ts:24:13 1373 +route PATCH /m13/res74/:id mod13.ts:78:25 index.ts:24:13 1374 +route GET /m13/res75/:id mod13.ts:79:23 index.ts:24:13 1375 +route POST /m13/res76/:id mod13.ts:80:24 index.ts:24:13 1376 +route PUT /m13/res77/:id mod13.ts:81:23 index.ts:24:13 1377 +route DELETE /m13/res78/:id mod13.ts:82:26 index.ts:24:13 1378 +route PATCH /m13/res79/:id mod13.ts:83:25 index.ts:24:13 1379 +route GET /m13/res80/:id mod13.ts:84:23 index.ts:24:13 1380 +route POST /m13/res81/:id mod13.ts:85:24 index.ts:24:13 1381 +route PUT /m13/res82/:id mod13.ts:86:23 index.ts:24:13 1382 +route DELETE /m13/res83/:id mod13.ts:87:26 index.ts:24:13 1383 +route PATCH /m13/res84/:id mod13.ts:88:25 index.ts:24:13 1384 +route GET /m13/res85/:id mod13.ts:89:23 index.ts:24:13 1385 +route POST /m13/res86/:id mod13.ts:90:24 index.ts:24:13 1386 +route PUT /m13/res87/:id mod13.ts:91:23 index.ts:24:13 1387 +route DELETE /m13/res88/:id mod13.ts:92:26 index.ts:24:13 1388 +route PATCH /m13/res89/:id mod13.ts:93:25 index.ts:24:13 1389 +route GET /m13/res90/:id mod13.ts:94:23 index.ts:24:13 1390 +route POST /m13/res91/:id mod13.ts:95:24 index.ts:24:13 1391 +route PUT /m13/res92/:id mod13.ts:96:23 index.ts:24:13 1392 +route DELETE /m13/res93/:id mod13.ts:97:26 index.ts:24:13 1393 +route PATCH /m13/res94/:id mod13.ts:98:25 index.ts:24:13 1394 +route GET /m13/res95/:id mod13.ts:99:23 index.ts:24:13 1395 +route POST /m13/res96/:id mod13.ts:100:24 index.ts:24:13 1396 +route PUT /m13/res97/:id mod13.ts:101:23 index.ts:24:13 1397 +route DELETE /m13/res98/:id mod13.ts:102:26 index.ts:24:13 1398 +route PATCH /m13/res99/:id mod13.ts:103:25 index.ts:24:13 1399 +route GET /m14/res0/:id mod14.ts:4:22 index.ts:24:13 1400 +route POST /m14/res1/:id mod14.ts:5:23 index.ts:24:13 1401 +route PUT /m14/res2/:id mod14.ts:6:22 index.ts:24:13 1402 +route DELETE /m14/res3/:id mod14.ts:7:25 index.ts:24:13 1403 +route PATCH /m14/res4/:id mod14.ts:8:24 index.ts:24:13 1404 +route GET /m14/res5/:id mod14.ts:9:22 index.ts:24:13 1405 +route POST /m14/res6/:id mod14.ts:10:23 index.ts:24:13 1406 +route PUT /m14/res7/:id mod14.ts:11:22 index.ts:24:13 1407 +route DELETE /m14/res8/:id mod14.ts:12:25 index.ts:24:13 1408 +route PATCH /m14/res9/:id mod14.ts:13:24 index.ts:24:13 1409 +route GET /m14/res10/:id mod14.ts:14:23 index.ts:24:13 1410 +route POST /m14/res11/:id mod14.ts:15:24 index.ts:24:13 1411 +route PUT /m14/res12/:id mod14.ts:16:23 index.ts:24:13 1412 +route DELETE /m14/res13/:id mod14.ts:17:26 index.ts:24:13 1413 +route PATCH /m14/res14/:id mod14.ts:18:25 index.ts:24:13 1414 +route GET /m14/res15/:id mod14.ts:19:23 index.ts:24:13 1415 +route POST /m14/res16/:id mod14.ts:20:24 index.ts:24:13 1416 +route PUT /m14/res17/:id mod14.ts:21:23 index.ts:24:13 1417 +route DELETE /m14/res18/:id mod14.ts:22:26 index.ts:24:13 1418 +route PATCH /m14/res19/:id mod14.ts:23:25 index.ts:24:13 1419 +route GET /m14/res20/:id mod14.ts:24:23 index.ts:24:13 1420 +route POST /m14/res21/:id mod14.ts:25:24 index.ts:24:13 1421 +route PUT /m14/res22/:id mod14.ts:26:23 index.ts:24:13 1422 +route DELETE /m14/res23/:id mod14.ts:27:26 index.ts:24:13 1423 +route PATCH /m14/res24/:id mod14.ts:28:25 index.ts:24:13 1424 +route GET /m14/res25/:id mod14.ts:29:23 index.ts:24:13 1425 +route POST /m14/res26/:id mod14.ts:30:24 index.ts:24:13 1426 +route PUT /m14/res27/:id mod14.ts:31:23 index.ts:24:13 1427 +route DELETE /m14/res28/:id mod14.ts:32:26 index.ts:24:13 1428 +route PATCH /m14/res29/:id mod14.ts:33:25 index.ts:24:13 1429 +route GET /m14/res30/:id mod14.ts:34:23 index.ts:24:13 1430 +route POST /m14/res31/:id mod14.ts:35:24 index.ts:24:13 1431 +route PUT /m14/res32/:id mod14.ts:36:23 index.ts:24:13 1432 +route DELETE /m14/res33/:id mod14.ts:37:26 index.ts:24:13 1433 +route PATCH /m14/res34/:id mod14.ts:38:25 index.ts:24:13 1434 +route GET /m14/res35/:id mod14.ts:39:23 index.ts:24:13 1435 +route POST /m14/res36/:id mod14.ts:40:24 index.ts:24:13 1436 +route PUT /m14/res37/:id mod14.ts:41:23 index.ts:24:13 1437 +route DELETE /m14/res38/:id mod14.ts:42:26 index.ts:24:13 1438 +route PATCH /m14/res39/:id mod14.ts:43:25 index.ts:24:13 1439 +route GET /m14/res40/:id mod14.ts:44:23 index.ts:24:13 1440 +route POST /m14/res41/:id mod14.ts:45:24 index.ts:24:13 1441 +route PUT /m14/res42/:id mod14.ts:46:23 index.ts:24:13 1442 +route DELETE /m14/res43/:id mod14.ts:47:26 index.ts:24:13 1443 +route PATCH /m14/res44/:id mod14.ts:48:25 index.ts:24:13 1444 +route GET /m14/res45/:id mod14.ts:49:23 index.ts:24:13 1445 +route POST /m14/res46/:id mod14.ts:50:24 index.ts:24:13 1446 +route PUT /m14/res47/:id mod14.ts:51:23 index.ts:24:13 1447 +route DELETE /m14/res48/:id mod14.ts:52:26 index.ts:24:13 1448 +route PATCH /m14/res49/:id mod14.ts:53:25 index.ts:24:13 1449 +route GET /m14/res50/:id mod14.ts:54:23 index.ts:24:13 1450 +route POST /m14/res51/:id mod14.ts:55:24 index.ts:24:13 1451 +route PUT /m14/res52/:id mod14.ts:56:23 index.ts:24:13 1452 +route DELETE /m14/res53/:id mod14.ts:57:26 index.ts:24:13 1453 +route PATCH /m14/res54/:id mod14.ts:58:25 index.ts:24:13 1454 +route GET /m14/res55/:id mod14.ts:59:23 index.ts:24:13 1455 +route POST /m14/res56/:id mod14.ts:60:24 index.ts:24:13 1456 +route PUT /m14/res57/:id mod14.ts:61:23 index.ts:24:13 1457 +route DELETE /m14/res58/:id mod14.ts:62:26 index.ts:24:13 1458 +route PATCH /m14/res59/:id mod14.ts:63:25 index.ts:24:13 1459 +route GET /m14/res60/:id mod14.ts:64:23 index.ts:24:13 1460 +route POST /m14/res61/:id mod14.ts:65:24 index.ts:24:13 1461 +route PUT /m14/res62/:id mod14.ts:66:23 index.ts:24:13 1462 +route DELETE /m14/res63/:id mod14.ts:67:26 index.ts:24:13 1463 +route PATCH /m14/res64/:id mod14.ts:68:25 index.ts:24:13 1464 +route GET /m14/res65/:id mod14.ts:69:23 index.ts:24:13 1465 +route POST /m14/res66/:id mod14.ts:70:24 index.ts:24:13 1466 +route PUT /m14/res67/:id mod14.ts:71:23 index.ts:24:13 1467 +route DELETE /m14/res68/:id mod14.ts:72:26 index.ts:24:13 1468 +route PATCH /m14/res69/:id mod14.ts:73:25 index.ts:24:13 1469 +route GET /m14/res70/:id mod14.ts:74:23 index.ts:24:13 1470 +route POST /m14/res71/:id mod14.ts:75:24 index.ts:24:13 1471 +route PUT /m14/res72/:id mod14.ts:76:23 index.ts:24:13 1472 +route DELETE /m14/res73/:id mod14.ts:77:26 index.ts:24:13 1473 +route PATCH /m14/res74/:id mod14.ts:78:25 index.ts:24:13 1474 +route GET /m14/res75/:id mod14.ts:79:23 index.ts:24:13 1475 +route POST /m14/res76/:id mod14.ts:80:24 index.ts:24:13 1476 +route PUT /m14/res77/:id mod14.ts:81:23 index.ts:24:13 1477 +route DELETE /m14/res78/:id mod14.ts:82:26 index.ts:24:13 1478 +route PATCH /m14/res79/:id mod14.ts:83:25 index.ts:24:13 1479 +route GET /m14/res80/:id mod14.ts:84:23 index.ts:24:13 1480 +route POST /m14/res81/:id mod14.ts:85:24 index.ts:24:13 1481 +route PUT /m14/res82/:id mod14.ts:86:23 index.ts:24:13 1482 +route DELETE /m14/res83/:id mod14.ts:87:26 index.ts:24:13 1483 +route PATCH /m14/res84/:id mod14.ts:88:25 index.ts:24:13 1484 +route GET /m14/res85/:id mod14.ts:89:23 index.ts:24:13 1485 +route POST /m14/res86/:id mod14.ts:90:24 index.ts:24:13 1486 +route PUT /m14/res87/:id mod14.ts:91:23 index.ts:24:13 1487 +route DELETE /m14/res88/:id mod14.ts:92:26 index.ts:24:13 1488 +route PATCH /m14/res89/:id mod14.ts:93:25 index.ts:24:13 1489 +route GET /m14/res90/:id mod14.ts:94:23 index.ts:24:13 1490 +route POST /m14/res91/:id mod14.ts:95:24 index.ts:24:13 1491 +route PUT /m14/res92/:id mod14.ts:96:23 index.ts:24:13 1492 +route DELETE /m14/res93/:id mod14.ts:97:26 index.ts:24:13 1493 +route PATCH /m14/res94/:id mod14.ts:98:25 index.ts:24:13 1494 +route GET /m14/res95/:id mod14.ts:99:23 index.ts:24:13 1495 +route POST /m14/res96/:id mod14.ts:100:24 index.ts:24:13 1496 +route PUT /m14/res97/:id mod14.ts:101:23 index.ts:24:13 1497 +route DELETE /m14/res98/:id mod14.ts:102:26 index.ts:24:13 1498 +route PATCH /m14/res99/:id mod14.ts:103:25 index.ts:24:13 1499 +route GET /m15/res0/:id mod15.ts:4:22 index.ts:24:13 1500 +route POST /m15/res1/:id mod15.ts:5:23 index.ts:24:13 1501 +route PUT /m15/res2/:id mod15.ts:6:22 index.ts:24:13 1502 +route DELETE /m15/res3/:id mod15.ts:7:25 index.ts:24:13 1503 +route PATCH /m15/res4/:id mod15.ts:8:24 index.ts:24:13 1504 +route GET /m15/res5/:id mod15.ts:9:22 index.ts:24:13 1505 +route POST /m15/res6/:id mod15.ts:10:23 index.ts:24:13 1506 +route PUT /m15/res7/:id mod15.ts:11:22 index.ts:24:13 1507 +route DELETE /m15/res8/:id mod15.ts:12:25 index.ts:24:13 1508 +route PATCH /m15/res9/:id mod15.ts:13:24 index.ts:24:13 1509 +route GET /m15/res10/:id mod15.ts:14:23 index.ts:24:13 1510 +route POST /m15/res11/:id mod15.ts:15:24 index.ts:24:13 1511 +route PUT /m15/res12/:id mod15.ts:16:23 index.ts:24:13 1512 +route DELETE /m15/res13/:id mod15.ts:17:26 index.ts:24:13 1513 +route PATCH /m15/res14/:id mod15.ts:18:25 index.ts:24:13 1514 +route GET /m15/res15/:id mod15.ts:19:23 index.ts:24:13 1515 +route POST /m15/res16/:id mod15.ts:20:24 index.ts:24:13 1516 +route PUT /m15/res17/:id mod15.ts:21:23 index.ts:24:13 1517 +route DELETE /m15/res18/:id mod15.ts:22:26 index.ts:24:13 1518 +route PATCH /m15/res19/:id mod15.ts:23:25 index.ts:24:13 1519 +route GET /m15/res20/:id mod15.ts:24:23 index.ts:24:13 1520 +route POST /m15/res21/:id mod15.ts:25:24 index.ts:24:13 1521 +route PUT /m15/res22/:id mod15.ts:26:23 index.ts:24:13 1522 +route DELETE /m15/res23/:id mod15.ts:27:26 index.ts:24:13 1523 +route PATCH /m15/res24/:id mod15.ts:28:25 index.ts:24:13 1524 +route GET /m15/res25/:id mod15.ts:29:23 index.ts:24:13 1525 +route POST /m15/res26/:id mod15.ts:30:24 index.ts:24:13 1526 +route PUT /m15/res27/:id mod15.ts:31:23 index.ts:24:13 1527 +route DELETE /m15/res28/:id mod15.ts:32:26 index.ts:24:13 1528 +route PATCH /m15/res29/:id mod15.ts:33:25 index.ts:24:13 1529 +route GET /m15/res30/:id mod15.ts:34:23 index.ts:24:13 1530 +route POST /m15/res31/:id mod15.ts:35:24 index.ts:24:13 1531 +route PUT /m15/res32/:id mod15.ts:36:23 index.ts:24:13 1532 +route DELETE /m15/res33/:id mod15.ts:37:26 index.ts:24:13 1533 +route PATCH /m15/res34/:id mod15.ts:38:25 index.ts:24:13 1534 +route GET /m15/res35/:id mod15.ts:39:23 index.ts:24:13 1535 +route POST /m15/res36/:id mod15.ts:40:24 index.ts:24:13 1536 +route PUT /m15/res37/:id mod15.ts:41:23 index.ts:24:13 1537 +route DELETE /m15/res38/:id mod15.ts:42:26 index.ts:24:13 1538 +route PATCH /m15/res39/:id mod15.ts:43:25 index.ts:24:13 1539 +route GET /m15/res40/:id mod15.ts:44:23 index.ts:24:13 1540 +route POST /m15/res41/:id mod15.ts:45:24 index.ts:24:13 1541 +route PUT /m15/res42/:id mod15.ts:46:23 index.ts:24:13 1542 +route DELETE /m15/res43/:id mod15.ts:47:26 index.ts:24:13 1543 +route PATCH /m15/res44/:id mod15.ts:48:25 index.ts:24:13 1544 +route GET /m15/res45/:id mod15.ts:49:23 index.ts:24:13 1545 +route POST /m15/res46/:id mod15.ts:50:24 index.ts:24:13 1546 +route PUT /m15/res47/:id mod15.ts:51:23 index.ts:24:13 1547 +route DELETE /m15/res48/:id mod15.ts:52:26 index.ts:24:13 1548 +route PATCH /m15/res49/:id mod15.ts:53:25 index.ts:24:13 1549 +route GET /m15/res50/:id mod15.ts:54:23 index.ts:24:13 1550 +route POST /m15/res51/:id mod15.ts:55:24 index.ts:24:13 1551 +route PUT /m15/res52/:id mod15.ts:56:23 index.ts:24:13 1552 +route DELETE /m15/res53/:id mod15.ts:57:26 index.ts:24:13 1553 +route PATCH /m15/res54/:id mod15.ts:58:25 index.ts:24:13 1554 +route GET /m15/res55/:id mod15.ts:59:23 index.ts:24:13 1555 +route POST /m15/res56/:id mod15.ts:60:24 index.ts:24:13 1556 +route PUT /m15/res57/:id mod15.ts:61:23 index.ts:24:13 1557 +route DELETE /m15/res58/:id mod15.ts:62:26 index.ts:24:13 1558 +route PATCH /m15/res59/:id mod15.ts:63:25 index.ts:24:13 1559 +route GET /m15/res60/:id mod15.ts:64:23 index.ts:24:13 1560 +route POST /m15/res61/:id mod15.ts:65:24 index.ts:24:13 1561 +route PUT /m15/res62/:id mod15.ts:66:23 index.ts:24:13 1562 +route DELETE /m15/res63/:id mod15.ts:67:26 index.ts:24:13 1563 +route PATCH /m15/res64/:id mod15.ts:68:25 index.ts:24:13 1564 +route GET /m15/res65/:id mod15.ts:69:23 index.ts:24:13 1565 +route POST /m15/res66/:id mod15.ts:70:24 index.ts:24:13 1566 +route PUT /m15/res67/:id mod15.ts:71:23 index.ts:24:13 1567 +route DELETE /m15/res68/:id mod15.ts:72:26 index.ts:24:13 1568 +route PATCH /m15/res69/:id mod15.ts:73:25 index.ts:24:13 1569 +route GET /m15/res70/:id mod15.ts:74:23 index.ts:24:13 1570 +route POST /m15/res71/:id mod15.ts:75:24 index.ts:24:13 1571 +route PUT /m15/res72/:id mod15.ts:76:23 index.ts:24:13 1572 +route DELETE /m15/res73/:id mod15.ts:77:26 index.ts:24:13 1573 +route PATCH /m15/res74/:id mod15.ts:78:25 index.ts:24:13 1574 +route GET /m15/res75/:id mod15.ts:79:23 index.ts:24:13 1575 +route POST /m15/res76/:id mod15.ts:80:24 index.ts:24:13 1576 +route PUT /m15/res77/:id mod15.ts:81:23 index.ts:24:13 1577 +route DELETE /m15/res78/:id mod15.ts:82:26 index.ts:24:13 1578 +route PATCH /m15/res79/:id mod15.ts:83:25 index.ts:24:13 1579 +route GET /m15/res80/:id mod15.ts:84:23 index.ts:24:13 1580 +route POST /m15/res81/:id mod15.ts:85:24 index.ts:24:13 1581 +route PUT /m15/res82/:id mod15.ts:86:23 index.ts:24:13 1582 +route DELETE /m15/res83/:id mod15.ts:87:26 index.ts:24:13 1583 +route PATCH /m15/res84/:id mod15.ts:88:25 index.ts:24:13 1584 +route GET /m15/res85/:id mod15.ts:89:23 index.ts:24:13 1585 +route POST /m15/res86/:id mod15.ts:90:24 index.ts:24:13 1586 +route PUT /m15/res87/:id mod15.ts:91:23 index.ts:24:13 1587 +route DELETE /m15/res88/:id mod15.ts:92:26 index.ts:24:13 1588 +route PATCH /m15/res89/:id mod15.ts:93:25 index.ts:24:13 1589 +route GET /m15/res90/:id mod15.ts:94:23 index.ts:24:13 1590 +route POST /m15/res91/:id mod15.ts:95:24 index.ts:24:13 1591 +route PUT /m15/res92/:id mod15.ts:96:23 index.ts:24:13 1592 +route DELETE /m15/res93/:id mod15.ts:97:26 index.ts:24:13 1593 +route PATCH /m15/res94/:id mod15.ts:98:25 index.ts:24:13 1594 +route GET /m15/res95/:id mod15.ts:99:23 index.ts:24:13 1595 +route POST /m15/res96/:id mod15.ts:100:24 index.ts:24:13 1596 +route PUT /m15/res97/:id mod15.ts:101:23 index.ts:24:13 1597 +route DELETE /m15/res98/:id mod15.ts:102:26 index.ts:24:13 1598 +route PATCH /m15/res99/:id mod15.ts:103:25 index.ts:24:13 1599 +route GET /m16/res0/:id mod16.ts:4:22 index.ts:24:13 1600 +route POST /m16/res1/:id mod16.ts:5:23 index.ts:24:13 1601 +route PUT /m16/res2/:id mod16.ts:6:22 index.ts:24:13 1602 +route DELETE /m16/res3/:id mod16.ts:7:25 index.ts:24:13 1603 +route PATCH /m16/res4/:id mod16.ts:8:24 index.ts:24:13 1604 +route GET /m16/res5/:id mod16.ts:9:22 index.ts:24:13 1605 +route POST /m16/res6/:id mod16.ts:10:23 index.ts:24:13 1606 +route PUT /m16/res7/:id mod16.ts:11:22 index.ts:24:13 1607 +route DELETE /m16/res8/:id mod16.ts:12:25 index.ts:24:13 1608 +route PATCH /m16/res9/:id mod16.ts:13:24 index.ts:24:13 1609 +route GET /m16/res10/:id mod16.ts:14:23 index.ts:24:13 1610 +route POST /m16/res11/:id mod16.ts:15:24 index.ts:24:13 1611 +route PUT /m16/res12/:id mod16.ts:16:23 index.ts:24:13 1612 +route DELETE /m16/res13/:id mod16.ts:17:26 index.ts:24:13 1613 +route PATCH /m16/res14/:id mod16.ts:18:25 index.ts:24:13 1614 +route GET /m16/res15/:id mod16.ts:19:23 index.ts:24:13 1615 +route POST /m16/res16/:id mod16.ts:20:24 index.ts:24:13 1616 +route PUT /m16/res17/:id mod16.ts:21:23 index.ts:24:13 1617 +route DELETE /m16/res18/:id mod16.ts:22:26 index.ts:24:13 1618 +route PATCH /m16/res19/:id mod16.ts:23:25 index.ts:24:13 1619 +route GET /m16/res20/:id mod16.ts:24:23 index.ts:24:13 1620 +route POST /m16/res21/:id mod16.ts:25:24 index.ts:24:13 1621 +route PUT /m16/res22/:id mod16.ts:26:23 index.ts:24:13 1622 +route DELETE /m16/res23/:id mod16.ts:27:26 index.ts:24:13 1623 +route PATCH /m16/res24/:id mod16.ts:28:25 index.ts:24:13 1624 +route GET /m16/res25/:id mod16.ts:29:23 index.ts:24:13 1625 +route POST /m16/res26/:id mod16.ts:30:24 index.ts:24:13 1626 +route PUT /m16/res27/:id mod16.ts:31:23 index.ts:24:13 1627 +route DELETE /m16/res28/:id mod16.ts:32:26 index.ts:24:13 1628 +route PATCH /m16/res29/:id mod16.ts:33:25 index.ts:24:13 1629 +route GET /m16/res30/:id mod16.ts:34:23 index.ts:24:13 1630 +route POST /m16/res31/:id mod16.ts:35:24 index.ts:24:13 1631 +route PUT /m16/res32/:id mod16.ts:36:23 index.ts:24:13 1632 +route DELETE /m16/res33/:id mod16.ts:37:26 index.ts:24:13 1633 +route PATCH /m16/res34/:id mod16.ts:38:25 index.ts:24:13 1634 +route GET /m16/res35/:id mod16.ts:39:23 index.ts:24:13 1635 +route POST /m16/res36/:id mod16.ts:40:24 index.ts:24:13 1636 +route PUT /m16/res37/:id mod16.ts:41:23 index.ts:24:13 1637 +route DELETE /m16/res38/:id mod16.ts:42:26 index.ts:24:13 1638 +route PATCH /m16/res39/:id mod16.ts:43:25 index.ts:24:13 1639 +route GET /m16/res40/:id mod16.ts:44:23 index.ts:24:13 1640 +route POST /m16/res41/:id mod16.ts:45:24 index.ts:24:13 1641 +route PUT /m16/res42/:id mod16.ts:46:23 index.ts:24:13 1642 +route DELETE /m16/res43/:id mod16.ts:47:26 index.ts:24:13 1643 +route PATCH /m16/res44/:id mod16.ts:48:25 index.ts:24:13 1644 +route GET /m16/res45/:id mod16.ts:49:23 index.ts:24:13 1645 +route POST /m16/res46/:id mod16.ts:50:24 index.ts:24:13 1646 +route PUT /m16/res47/:id mod16.ts:51:23 index.ts:24:13 1647 +route DELETE /m16/res48/:id mod16.ts:52:26 index.ts:24:13 1648 +route PATCH /m16/res49/:id mod16.ts:53:25 index.ts:24:13 1649 +route GET /m16/res50/:id mod16.ts:54:23 index.ts:24:13 1650 +route POST /m16/res51/:id mod16.ts:55:24 index.ts:24:13 1651 +route PUT /m16/res52/:id mod16.ts:56:23 index.ts:24:13 1652 +route DELETE /m16/res53/:id mod16.ts:57:26 index.ts:24:13 1653 +route PATCH /m16/res54/:id mod16.ts:58:25 index.ts:24:13 1654 +route GET /m16/res55/:id mod16.ts:59:23 index.ts:24:13 1655 +route POST /m16/res56/:id mod16.ts:60:24 index.ts:24:13 1656 +route PUT /m16/res57/:id mod16.ts:61:23 index.ts:24:13 1657 +route DELETE /m16/res58/:id mod16.ts:62:26 index.ts:24:13 1658 +route PATCH /m16/res59/:id mod16.ts:63:25 index.ts:24:13 1659 +route GET /m16/res60/:id mod16.ts:64:23 index.ts:24:13 1660 +route POST /m16/res61/:id mod16.ts:65:24 index.ts:24:13 1661 +route PUT /m16/res62/:id mod16.ts:66:23 index.ts:24:13 1662 +route DELETE /m16/res63/:id mod16.ts:67:26 index.ts:24:13 1663 +route PATCH /m16/res64/:id mod16.ts:68:25 index.ts:24:13 1664 +route GET /m16/res65/:id mod16.ts:69:23 index.ts:24:13 1665 +route POST /m16/res66/:id mod16.ts:70:24 index.ts:24:13 1666 +route PUT /m16/res67/:id mod16.ts:71:23 index.ts:24:13 1667 +route DELETE /m16/res68/:id mod16.ts:72:26 index.ts:24:13 1668 +route PATCH /m16/res69/:id mod16.ts:73:25 index.ts:24:13 1669 +route GET /m16/res70/:id mod16.ts:74:23 index.ts:24:13 1670 +route POST /m16/res71/:id mod16.ts:75:24 index.ts:24:13 1671 +route PUT /m16/res72/:id mod16.ts:76:23 index.ts:24:13 1672 +route DELETE /m16/res73/:id mod16.ts:77:26 index.ts:24:13 1673 +route PATCH /m16/res74/:id mod16.ts:78:25 index.ts:24:13 1674 +route GET /m16/res75/:id mod16.ts:79:23 index.ts:24:13 1675 +route POST /m16/res76/:id mod16.ts:80:24 index.ts:24:13 1676 +route PUT /m16/res77/:id mod16.ts:81:23 index.ts:24:13 1677 +route DELETE /m16/res78/:id mod16.ts:82:26 index.ts:24:13 1678 +route PATCH /m16/res79/:id mod16.ts:83:25 index.ts:24:13 1679 +route GET /m16/res80/:id mod16.ts:84:23 index.ts:24:13 1680 +route POST /m16/res81/:id mod16.ts:85:24 index.ts:24:13 1681 +route PUT /m16/res82/:id mod16.ts:86:23 index.ts:24:13 1682 +route DELETE /m16/res83/:id mod16.ts:87:26 index.ts:24:13 1683 +route PATCH /m16/res84/:id mod16.ts:88:25 index.ts:24:13 1684 +route GET /m16/res85/:id mod16.ts:89:23 index.ts:24:13 1685 +route POST /m16/res86/:id mod16.ts:90:24 index.ts:24:13 1686 +route PUT /m16/res87/:id mod16.ts:91:23 index.ts:24:13 1687 +route DELETE /m16/res88/:id mod16.ts:92:26 index.ts:24:13 1688 +route PATCH /m16/res89/:id mod16.ts:93:25 index.ts:24:13 1689 +route GET /m16/res90/:id mod16.ts:94:23 index.ts:24:13 1690 +route POST /m16/res91/:id mod16.ts:95:24 index.ts:24:13 1691 +route PUT /m16/res92/:id mod16.ts:96:23 index.ts:24:13 1692 +route DELETE /m16/res93/:id mod16.ts:97:26 index.ts:24:13 1693 +route PATCH /m16/res94/:id mod16.ts:98:25 index.ts:24:13 1694 +route GET /m16/res95/:id mod16.ts:99:23 index.ts:24:13 1695 +route POST /m16/res96/:id mod16.ts:100:24 index.ts:24:13 1696 +route PUT /m16/res97/:id mod16.ts:101:23 index.ts:24:13 1697 +route DELETE /m16/res98/:id mod16.ts:102:26 index.ts:24:13 1698 +route PATCH /m16/res99/:id mod16.ts:103:25 index.ts:24:13 1699 +route GET /m17/res0/:id mod17.ts:4:22 index.ts:24:13 1700 +route POST /m17/res1/:id mod17.ts:5:23 index.ts:24:13 1701 +route PUT /m17/res2/:id mod17.ts:6:22 index.ts:24:13 1702 +route DELETE /m17/res3/:id mod17.ts:7:25 index.ts:24:13 1703 +route PATCH /m17/res4/:id mod17.ts:8:24 index.ts:24:13 1704 +route GET /m17/res5/:id mod17.ts:9:22 index.ts:24:13 1705 +route POST /m17/res6/:id mod17.ts:10:23 index.ts:24:13 1706 +route PUT /m17/res7/:id mod17.ts:11:22 index.ts:24:13 1707 +route DELETE /m17/res8/:id mod17.ts:12:25 index.ts:24:13 1708 +route PATCH /m17/res9/:id mod17.ts:13:24 index.ts:24:13 1709 +route GET /m17/res10/:id mod17.ts:14:23 index.ts:24:13 1710 +route POST /m17/res11/:id mod17.ts:15:24 index.ts:24:13 1711 +route PUT /m17/res12/:id mod17.ts:16:23 index.ts:24:13 1712 +route DELETE /m17/res13/:id mod17.ts:17:26 index.ts:24:13 1713 +route PATCH /m17/res14/:id mod17.ts:18:25 index.ts:24:13 1714 +route GET /m17/res15/:id mod17.ts:19:23 index.ts:24:13 1715 +route POST /m17/res16/:id mod17.ts:20:24 index.ts:24:13 1716 +route PUT /m17/res17/:id mod17.ts:21:23 index.ts:24:13 1717 +route DELETE /m17/res18/:id mod17.ts:22:26 index.ts:24:13 1718 +route PATCH /m17/res19/:id mod17.ts:23:25 index.ts:24:13 1719 +route GET /m17/res20/:id mod17.ts:24:23 index.ts:24:13 1720 +route POST /m17/res21/:id mod17.ts:25:24 index.ts:24:13 1721 +route PUT /m17/res22/:id mod17.ts:26:23 index.ts:24:13 1722 +route DELETE /m17/res23/:id mod17.ts:27:26 index.ts:24:13 1723 +route PATCH /m17/res24/:id mod17.ts:28:25 index.ts:24:13 1724 +route GET /m17/res25/:id mod17.ts:29:23 index.ts:24:13 1725 +route POST /m17/res26/:id mod17.ts:30:24 index.ts:24:13 1726 +route PUT /m17/res27/:id mod17.ts:31:23 index.ts:24:13 1727 +route DELETE /m17/res28/:id mod17.ts:32:26 index.ts:24:13 1728 +route PATCH /m17/res29/:id mod17.ts:33:25 index.ts:24:13 1729 +route GET /m17/res30/:id mod17.ts:34:23 index.ts:24:13 1730 +route POST /m17/res31/:id mod17.ts:35:24 index.ts:24:13 1731 +route PUT /m17/res32/:id mod17.ts:36:23 index.ts:24:13 1732 +route DELETE /m17/res33/:id mod17.ts:37:26 index.ts:24:13 1733 +route PATCH /m17/res34/:id mod17.ts:38:25 index.ts:24:13 1734 +route GET /m17/res35/:id mod17.ts:39:23 index.ts:24:13 1735 +route POST /m17/res36/:id mod17.ts:40:24 index.ts:24:13 1736 +route PUT /m17/res37/:id mod17.ts:41:23 index.ts:24:13 1737 +route DELETE /m17/res38/:id mod17.ts:42:26 index.ts:24:13 1738 +route PATCH /m17/res39/:id mod17.ts:43:25 index.ts:24:13 1739 +route GET /m17/res40/:id mod17.ts:44:23 index.ts:24:13 1740 +route POST /m17/res41/:id mod17.ts:45:24 index.ts:24:13 1741 +route PUT /m17/res42/:id mod17.ts:46:23 index.ts:24:13 1742 +route DELETE /m17/res43/:id mod17.ts:47:26 index.ts:24:13 1743 +route PATCH /m17/res44/:id mod17.ts:48:25 index.ts:24:13 1744 +route GET /m17/res45/:id mod17.ts:49:23 index.ts:24:13 1745 +route POST /m17/res46/:id mod17.ts:50:24 index.ts:24:13 1746 +route PUT /m17/res47/:id mod17.ts:51:23 index.ts:24:13 1747 +route DELETE /m17/res48/:id mod17.ts:52:26 index.ts:24:13 1748 +route PATCH /m17/res49/:id mod17.ts:53:25 index.ts:24:13 1749 +route GET /m17/res50/:id mod17.ts:54:23 index.ts:24:13 1750 +route POST /m17/res51/:id mod17.ts:55:24 index.ts:24:13 1751 +route PUT /m17/res52/:id mod17.ts:56:23 index.ts:24:13 1752 +route DELETE /m17/res53/:id mod17.ts:57:26 index.ts:24:13 1753 +route PATCH /m17/res54/:id mod17.ts:58:25 index.ts:24:13 1754 +route GET /m17/res55/:id mod17.ts:59:23 index.ts:24:13 1755 +route POST /m17/res56/:id mod17.ts:60:24 index.ts:24:13 1756 +route PUT /m17/res57/:id mod17.ts:61:23 index.ts:24:13 1757 +route DELETE /m17/res58/:id mod17.ts:62:26 index.ts:24:13 1758 +route PATCH /m17/res59/:id mod17.ts:63:25 index.ts:24:13 1759 +route GET /m17/res60/:id mod17.ts:64:23 index.ts:24:13 1760 +route POST /m17/res61/:id mod17.ts:65:24 index.ts:24:13 1761 +route PUT /m17/res62/:id mod17.ts:66:23 index.ts:24:13 1762 +route DELETE /m17/res63/:id mod17.ts:67:26 index.ts:24:13 1763 +route PATCH /m17/res64/:id mod17.ts:68:25 index.ts:24:13 1764 +route GET /m17/res65/:id mod17.ts:69:23 index.ts:24:13 1765 +route POST /m17/res66/:id mod17.ts:70:24 index.ts:24:13 1766 +route PUT /m17/res67/:id mod17.ts:71:23 index.ts:24:13 1767 +route DELETE /m17/res68/:id mod17.ts:72:26 index.ts:24:13 1768 +route PATCH /m17/res69/:id mod17.ts:73:25 index.ts:24:13 1769 +route GET /m17/res70/:id mod17.ts:74:23 index.ts:24:13 1770 +route POST /m17/res71/:id mod17.ts:75:24 index.ts:24:13 1771 +route PUT /m17/res72/:id mod17.ts:76:23 index.ts:24:13 1772 +route DELETE /m17/res73/:id mod17.ts:77:26 index.ts:24:13 1773 +route PATCH /m17/res74/:id mod17.ts:78:25 index.ts:24:13 1774 +route GET /m17/res75/:id mod17.ts:79:23 index.ts:24:13 1775 +route POST /m17/res76/:id mod17.ts:80:24 index.ts:24:13 1776 +route PUT /m17/res77/:id mod17.ts:81:23 index.ts:24:13 1777 +route DELETE /m17/res78/:id mod17.ts:82:26 index.ts:24:13 1778 +route PATCH /m17/res79/:id mod17.ts:83:25 index.ts:24:13 1779 +route GET /m17/res80/:id mod17.ts:84:23 index.ts:24:13 1780 +route POST /m17/res81/:id mod17.ts:85:24 index.ts:24:13 1781 +route PUT /m17/res82/:id mod17.ts:86:23 index.ts:24:13 1782 +route DELETE /m17/res83/:id mod17.ts:87:26 index.ts:24:13 1783 +route PATCH /m17/res84/:id mod17.ts:88:25 index.ts:24:13 1784 +route GET /m17/res85/:id mod17.ts:89:23 index.ts:24:13 1785 +route POST /m17/res86/:id mod17.ts:90:24 index.ts:24:13 1786 +route PUT /m17/res87/:id mod17.ts:91:23 index.ts:24:13 1787 +route DELETE /m17/res88/:id mod17.ts:92:26 index.ts:24:13 1788 +route PATCH /m17/res89/:id mod17.ts:93:25 index.ts:24:13 1789 +route GET /m17/res90/:id mod17.ts:94:23 index.ts:24:13 1790 +route POST /m17/res91/:id mod17.ts:95:24 index.ts:24:13 1791 +route PUT /m17/res92/:id mod17.ts:96:23 index.ts:24:13 1792 +route DELETE /m17/res93/:id mod17.ts:97:26 index.ts:24:13 1793 +route PATCH /m17/res94/:id mod17.ts:98:25 index.ts:24:13 1794 +route GET /m17/res95/:id mod17.ts:99:23 index.ts:24:13 1795 +route POST /m17/res96/:id mod17.ts:100:24 index.ts:24:13 1796 +route PUT /m17/res97/:id mod17.ts:101:23 index.ts:24:13 1797 +route DELETE /m17/res98/:id mod17.ts:102:26 index.ts:24:13 1798 +route PATCH /m17/res99/:id mod17.ts:103:25 index.ts:24:13 1799 +route GET /m18/res0/:id mod18.ts:4:22 index.ts:24:13 1800 +route POST /m18/res1/:id mod18.ts:5:23 index.ts:24:13 1801 +route PUT /m18/res2/:id mod18.ts:6:22 index.ts:24:13 1802 +route DELETE /m18/res3/:id mod18.ts:7:25 index.ts:24:13 1803 +route PATCH /m18/res4/:id mod18.ts:8:24 index.ts:24:13 1804 +route GET /m18/res5/:id mod18.ts:9:22 index.ts:24:13 1805 +route POST /m18/res6/:id mod18.ts:10:23 index.ts:24:13 1806 +route PUT /m18/res7/:id mod18.ts:11:22 index.ts:24:13 1807 +route DELETE /m18/res8/:id mod18.ts:12:25 index.ts:24:13 1808 +route PATCH /m18/res9/:id mod18.ts:13:24 index.ts:24:13 1809 +route GET /m18/res10/:id mod18.ts:14:23 index.ts:24:13 1810 +route POST /m18/res11/:id mod18.ts:15:24 index.ts:24:13 1811 +route PUT /m18/res12/:id mod18.ts:16:23 index.ts:24:13 1812 +route DELETE /m18/res13/:id mod18.ts:17:26 index.ts:24:13 1813 +route PATCH /m18/res14/:id mod18.ts:18:25 index.ts:24:13 1814 +route GET /m18/res15/:id mod18.ts:19:23 index.ts:24:13 1815 +route POST /m18/res16/:id mod18.ts:20:24 index.ts:24:13 1816 +route PUT /m18/res17/:id mod18.ts:21:23 index.ts:24:13 1817 +route DELETE /m18/res18/:id mod18.ts:22:26 index.ts:24:13 1818 +route PATCH /m18/res19/:id mod18.ts:23:25 index.ts:24:13 1819 +route GET /m18/res20/:id mod18.ts:24:23 index.ts:24:13 1820 +route POST /m18/res21/:id mod18.ts:25:24 index.ts:24:13 1821 +route PUT /m18/res22/:id mod18.ts:26:23 index.ts:24:13 1822 +route DELETE /m18/res23/:id mod18.ts:27:26 index.ts:24:13 1823 +route PATCH /m18/res24/:id mod18.ts:28:25 index.ts:24:13 1824 +route GET /m18/res25/:id mod18.ts:29:23 index.ts:24:13 1825 +route POST /m18/res26/:id mod18.ts:30:24 index.ts:24:13 1826 +route PUT /m18/res27/:id mod18.ts:31:23 index.ts:24:13 1827 +route DELETE /m18/res28/:id mod18.ts:32:26 index.ts:24:13 1828 +route PATCH /m18/res29/:id mod18.ts:33:25 index.ts:24:13 1829 +route GET /m18/res30/:id mod18.ts:34:23 index.ts:24:13 1830 +route POST /m18/res31/:id mod18.ts:35:24 index.ts:24:13 1831 +route PUT /m18/res32/:id mod18.ts:36:23 index.ts:24:13 1832 +route DELETE /m18/res33/:id mod18.ts:37:26 index.ts:24:13 1833 +route PATCH /m18/res34/:id mod18.ts:38:25 index.ts:24:13 1834 +route GET /m18/res35/:id mod18.ts:39:23 index.ts:24:13 1835 +route POST /m18/res36/:id mod18.ts:40:24 index.ts:24:13 1836 +route PUT /m18/res37/:id mod18.ts:41:23 index.ts:24:13 1837 +route DELETE /m18/res38/:id mod18.ts:42:26 index.ts:24:13 1838 +route PATCH /m18/res39/:id mod18.ts:43:25 index.ts:24:13 1839 +route GET /m18/res40/:id mod18.ts:44:23 index.ts:24:13 1840 +route POST /m18/res41/:id mod18.ts:45:24 index.ts:24:13 1841 +route PUT /m18/res42/:id mod18.ts:46:23 index.ts:24:13 1842 +route DELETE /m18/res43/:id mod18.ts:47:26 index.ts:24:13 1843 +route PATCH /m18/res44/:id mod18.ts:48:25 index.ts:24:13 1844 +route GET /m18/res45/:id mod18.ts:49:23 index.ts:24:13 1845 +route POST /m18/res46/:id mod18.ts:50:24 index.ts:24:13 1846 +route PUT /m18/res47/:id mod18.ts:51:23 index.ts:24:13 1847 +route DELETE /m18/res48/:id mod18.ts:52:26 index.ts:24:13 1848 +route PATCH /m18/res49/:id mod18.ts:53:25 index.ts:24:13 1849 +route GET /m18/res50/:id mod18.ts:54:23 index.ts:24:13 1850 +route POST /m18/res51/:id mod18.ts:55:24 index.ts:24:13 1851 +route PUT /m18/res52/:id mod18.ts:56:23 index.ts:24:13 1852 +route DELETE /m18/res53/:id mod18.ts:57:26 index.ts:24:13 1853 +route PATCH /m18/res54/:id mod18.ts:58:25 index.ts:24:13 1854 +route GET /m18/res55/:id mod18.ts:59:23 index.ts:24:13 1855 +route POST /m18/res56/:id mod18.ts:60:24 index.ts:24:13 1856 +route PUT /m18/res57/:id mod18.ts:61:23 index.ts:24:13 1857 +route DELETE /m18/res58/:id mod18.ts:62:26 index.ts:24:13 1858 +route PATCH /m18/res59/:id mod18.ts:63:25 index.ts:24:13 1859 +route GET /m18/res60/:id mod18.ts:64:23 index.ts:24:13 1860 +route POST /m18/res61/:id mod18.ts:65:24 index.ts:24:13 1861 +route PUT /m18/res62/:id mod18.ts:66:23 index.ts:24:13 1862 +route DELETE /m18/res63/:id mod18.ts:67:26 index.ts:24:13 1863 +route PATCH /m18/res64/:id mod18.ts:68:25 index.ts:24:13 1864 +route GET /m18/res65/:id mod18.ts:69:23 index.ts:24:13 1865 +route POST /m18/res66/:id mod18.ts:70:24 index.ts:24:13 1866 +route PUT /m18/res67/:id mod18.ts:71:23 index.ts:24:13 1867 +route DELETE /m18/res68/:id mod18.ts:72:26 index.ts:24:13 1868 +route PATCH /m18/res69/:id mod18.ts:73:25 index.ts:24:13 1869 +route GET /m18/res70/:id mod18.ts:74:23 index.ts:24:13 1870 +route POST /m18/res71/:id mod18.ts:75:24 index.ts:24:13 1871 +route PUT /m18/res72/:id mod18.ts:76:23 index.ts:24:13 1872 +route DELETE /m18/res73/:id mod18.ts:77:26 index.ts:24:13 1873 +route PATCH /m18/res74/:id mod18.ts:78:25 index.ts:24:13 1874 +route GET /m18/res75/:id mod18.ts:79:23 index.ts:24:13 1875 +route POST /m18/res76/:id mod18.ts:80:24 index.ts:24:13 1876 +route PUT /m18/res77/:id mod18.ts:81:23 index.ts:24:13 1877 +route DELETE /m18/res78/:id mod18.ts:82:26 index.ts:24:13 1878 +route PATCH /m18/res79/:id mod18.ts:83:25 index.ts:24:13 1879 +route GET /m18/res80/:id mod18.ts:84:23 index.ts:24:13 1880 +route POST /m18/res81/:id mod18.ts:85:24 index.ts:24:13 1881 +route PUT /m18/res82/:id mod18.ts:86:23 index.ts:24:13 1882 +route DELETE /m18/res83/:id mod18.ts:87:26 index.ts:24:13 1883 +route PATCH /m18/res84/:id mod18.ts:88:25 index.ts:24:13 1884 +route GET /m18/res85/:id mod18.ts:89:23 index.ts:24:13 1885 +route POST /m18/res86/:id mod18.ts:90:24 index.ts:24:13 1886 +route PUT /m18/res87/:id mod18.ts:91:23 index.ts:24:13 1887 +route DELETE /m18/res88/:id mod18.ts:92:26 index.ts:24:13 1888 +route PATCH /m18/res89/:id mod18.ts:93:25 index.ts:24:13 1889 +route GET /m18/res90/:id mod18.ts:94:23 index.ts:24:13 1890 +route POST /m18/res91/:id mod18.ts:95:24 index.ts:24:13 1891 +route PUT /m18/res92/:id mod18.ts:96:23 index.ts:24:13 1892 +route DELETE /m18/res93/:id mod18.ts:97:26 index.ts:24:13 1893 +route PATCH /m18/res94/:id mod18.ts:98:25 index.ts:24:13 1894 +route GET /m18/res95/:id mod18.ts:99:23 index.ts:24:13 1895 +route POST /m18/res96/:id mod18.ts:100:24 index.ts:24:13 1896 +route PUT /m18/res97/:id mod18.ts:101:23 index.ts:24:13 1897 +route DELETE /m18/res98/:id mod18.ts:102:26 index.ts:24:13 1898 +route PATCH /m18/res99/:id mod18.ts:103:25 index.ts:24:13 1899 +route GET /m19/res0/:id mod19.ts:4:22 index.ts:24:13 1900 +route POST /m19/res1/:id mod19.ts:5:23 index.ts:24:13 1901 +route PUT /m19/res2/:id mod19.ts:6:22 index.ts:24:13 1902 +route DELETE /m19/res3/:id mod19.ts:7:25 index.ts:24:13 1903 +route PATCH /m19/res4/:id mod19.ts:8:24 index.ts:24:13 1904 +route GET /m19/res5/:id mod19.ts:9:22 index.ts:24:13 1905 +route POST /m19/res6/:id mod19.ts:10:23 index.ts:24:13 1906 +route PUT /m19/res7/:id mod19.ts:11:22 index.ts:24:13 1907 +route DELETE /m19/res8/:id mod19.ts:12:25 index.ts:24:13 1908 +route PATCH /m19/res9/:id mod19.ts:13:24 index.ts:24:13 1909 +route GET /m19/res10/:id mod19.ts:14:23 index.ts:24:13 1910 +route POST /m19/res11/:id mod19.ts:15:24 index.ts:24:13 1911 +route PUT /m19/res12/:id mod19.ts:16:23 index.ts:24:13 1912 +route DELETE /m19/res13/:id mod19.ts:17:26 index.ts:24:13 1913 +route PATCH /m19/res14/:id mod19.ts:18:25 index.ts:24:13 1914 +route GET /m19/res15/:id mod19.ts:19:23 index.ts:24:13 1915 +route POST /m19/res16/:id mod19.ts:20:24 index.ts:24:13 1916 +route PUT /m19/res17/:id mod19.ts:21:23 index.ts:24:13 1917 +route DELETE /m19/res18/:id mod19.ts:22:26 index.ts:24:13 1918 +route PATCH /m19/res19/:id mod19.ts:23:25 index.ts:24:13 1919 +route GET /m19/res20/:id mod19.ts:24:23 index.ts:24:13 1920 +route POST /m19/res21/:id mod19.ts:25:24 index.ts:24:13 1921 +route PUT /m19/res22/:id mod19.ts:26:23 index.ts:24:13 1922 +route DELETE /m19/res23/:id mod19.ts:27:26 index.ts:24:13 1923 +route PATCH /m19/res24/:id mod19.ts:28:25 index.ts:24:13 1924 +route GET /m19/res25/:id mod19.ts:29:23 index.ts:24:13 1925 +route POST /m19/res26/:id mod19.ts:30:24 index.ts:24:13 1926 +route PUT /m19/res27/:id mod19.ts:31:23 index.ts:24:13 1927 +route DELETE /m19/res28/:id mod19.ts:32:26 index.ts:24:13 1928 +route PATCH /m19/res29/:id mod19.ts:33:25 index.ts:24:13 1929 +route GET /m19/res30/:id mod19.ts:34:23 index.ts:24:13 1930 +route POST /m19/res31/:id mod19.ts:35:24 index.ts:24:13 1931 +route PUT /m19/res32/:id mod19.ts:36:23 index.ts:24:13 1932 +route DELETE /m19/res33/:id mod19.ts:37:26 index.ts:24:13 1933 +route PATCH /m19/res34/:id mod19.ts:38:25 index.ts:24:13 1934 +route GET /m19/res35/:id mod19.ts:39:23 index.ts:24:13 1935 +route POST /m19/res36/:id mod19.ts:40:24 index.ts:24:13 1936 +route PUT /m19/res37/:id mod19.ts:41:23 index.ts:24:13 1937 +route DELETE /m19/res38/:id mod19.ts:42:26 index.ts:24:13 1938 +route PATCH /m19/res39/:id mod19.ts:43:25 index.ts:24:13 1939 +route GET /m19/res40/:id mod19.ts:44:23 index.ts:24:13 1940 +route POST /m19/res41/:id mod19.ts:45:24 index.ts:24:13 1941 +route PUT /m19/res42/:id mod19.ts:46:23 index.ts:24:13 1942 +route DELETE /m19/res43/:id mod19.ts:47:26 index.ts:24:13 1943 +route PATCH /m19/res44/:id mod19.ts:48:25 index.ts:24:13 1944 +route GET /m19/res45/:id mod19.ts:49:23 index.ts:24:13 1945 +route POST /m19/res46/:id mod19.ts:50:24 index.ts:24:13 1946 +route PUT /m19/res47/:id mod19.ts:51:23 index.ts:24:13 1947 +route DELETE /m19/res48/:id mod19.ts:52:26 index.ts:24:13 1948 +route PATCH /m19/res49/:id mod19.ts:53:25 index.ts:24:13 1949 +route GET /m19/res50/:id mod19.ts:54:23 index.ts:24:13 1950 +route POST /m19/res51/:id mod19.ts:55:24 index.ts:24:13 1951 +route PUT /m19/res52/:id mod19.ts:56:23 index.ts:24:13 1952 +route DELETE /m19/res53/:id mod19.ts:57:26 index.ts:24:13 1953 +route PATCH /m19/res54/:id mod19.ts:58:25 index.ts:24:13 1954 +route GET /m19/res55/:id mod19.ts:59:23 index.ts:24:13 1955 +route POST /m19/res56/:id mod19.ts:60:24 index.ts:24:13 1956 +route PUT /m19/res57/:id mod19.ts:61:23 index.ts:24:13 1957 +route DELETE /m19/res58/:id mod19.ts:62:26 index.ts:24:13 1958 +route PATCH /m19/res59/:id mod19.ts:63:25 index.ts:24:13 1959 +route GET /m19/res60/:id mod19.ts:64:23 index.ts:24:13 1960 +route POST /m19/res61/:id mod19.ts:65:24 index.ts:24:13 1961 +route PUT /m19/res62/:id mod19.ts:66:23 index.ts:24:13 1962 +route DELETE /m19/res63/:id mod19.ts:67:26 index.ts:24:13 1963 +route PATCH /m19/res64/:id mod19.ts:68:25 index.ts:24:13 1964 +route GET /m19/res65/:id mod19.ts:69:23 index.ts:24:13 1965 +route POST /m19/res66/:id mod19.ts:70:24 index.ts:24:13 1966 +route PUT /m19/res67/:id mod19.ts:71:23 index.ts:24:13 1967 +route DELETE /m19/res68/:id mod19.ts:72:26 index.ts:24:13 1968 +route PATCH /m19/res69/:id mod19.ts:73:25 index.ts:24:13 1969 +route GET /m19/res70/:id mod19.ts:74:23 index.ts:24:13 1970 +route POST /m19/res71/:id mod19.ts:75:24 index.ts:24:13 1971 +route PUT /m19/res72/:id mod19.ts:76:23 index.ts:24:13 1972 +route DELETE /m19/res73/:id mod19.ts:77:26 index.ts:24:13 1973 +route PATCH /m19/res74/:id mod19.ts:78:25 index.ts:24:13 1974 +route GET /m19/res75/:id mod19.ts:79:23 index.ts:24:13 1975 +route POST /m19/res76/:id mod19.ts:80:24 index.ts:24:13 1976 +route PUT /m19/res77/:id mod19.ts:81:23 index.ts:24:13 1977 +route DELETE /m19/res78/:id mod19.ts:82:26 index.ts:24:13 1978 +route PATCH /m19/res79/:id mod19.ts:83:25 index.ts:24:13 1979 +route GET /m19/res80/:id mod19.ts:84:23 index.ts:24:13 1980 +route POST /m19/res81/:id mod19.ts:85:24 index.ts:24:13 1981 +route PUT /m19/res82/:id mod19.ts:86:23 index.ts:24:13 1982 +route DELETE /m19/res83/:id mod19.ts:87:26 index.ts:24:13 1983 +route PATCH /m19/res84/:id mod19.ts:88:25 index.ts:24:13 1984 +route GET /m19/res85/:id mod19.ts:89:23 index.ts:24:13 1985 +route POST /m19/res86/:id mod19.ts:90:24 index.ts:24:13 1986 +route PUT /m19/res87/:id mod19.ts:91:23 index.ts:24:13 1987 +route DELETE /m19/res88/:id mod19.ts:92:26 index.ts:24:13 1988 +route PATCH /m19/res89/:id mod19.ts:93:25 index.ts:24:13 1989 +route GET /m19/res90/:id mod19.ts:94:23 index.ts:24:13 1990 +route POST /m19/res91/:id mod19.ts:95:24 index.ts:24:13 1991 +route PUT /m19/res92/:id mod19.ts:96:23 index.ts:24:13 1992 +route DELETE /m19/res93/:id mod19.ts:97:26 index.ts:24:13 1993 +route PATCH /m19/res94/:id mod19.ts:98:25 index.ts:24:13 1994 +route GET /m19/res95/:id mod19.ts:99:23 index.ts:24:13 1995 +route POST /m19/res96/:id mod19.ts:100:24 index.ts:24:13 1996 +route PUT /m19/res97/:id mod19.ts:101:23 index.ts:24:13 1997 +route DELETE /m19/res98/:id mod19.ts:102:26 index.ts:24:13 1998 +route PATCH /m19/res99/:id mod19.ts:103:25 index.ts:24:13 1999 +submount /m0 index.ts:25:5 +submount /m1 index.ts:26:5 +submount /m2 index.ts:27:5 +submount /m3 index.ts:28:5 +submount /m4 index.ts:29:5 +submount /m5 index.ts:30:5 +submount /m6 index.ts:31:5 +submount /m7 index.ts:32:5 +submount /m8 index.ts:33:5 +submount /m9 index.ts:34:5 +submount /m10 index.ts:35:5 +submount /m11 index.ts:36:5 +submount /m12 index.ts:37:5 +submount /m13 index.ts:38:5 +submount /m14 index.ts:39:5 +submount /m15 index.ts:40:5 +submount /m16 index.ts:41:5 +submount /m17 index.ts:42:5 +submount /m18 index.ts:43:5 +submount /m19 index.ts:44:5 +regby mod0.ts:1:1 mod0.ts:100:23 POST /m0/res96/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:101:22 PUT /m0/res97/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:102:25 DELETE /m0/res98/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:103:24 PATCH /m0/res99/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:10:22 POST /m0/res6/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:11:21 PUT /m0/res7/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:12:24 DELETE /m0/res8/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:13:23 PATCH /m0/res9/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:14:22 GET /m0/res10/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:15:23 POST /m0/res11/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:16:22 PUT /m0/res12/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:17:25 DELETE /m0/res13/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:18:24 PATCH /m0/res14/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:19:22 GET /m0/res15/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:20:23 POST /m0/res16/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:21:22 PUT /m0/res17/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:22:25 DELETE /m0/res18/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:23:24 PATCH /m0/res19/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:24:22 GET /m0/res20/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:25:23 POST /m0/res21/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:26:22 PUT /m0/res22/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:27:25 DELETE /m0/res23/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:28:24 PATCH /m0/res24/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:29:22 GET /m0/res25/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:30:23 POST /m0/res26/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:31:22 PUT /m0/res27/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:32:25 DELETE /m0/res28/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:33:24 PATCH /m0/res29/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:34:22 GET /m0/res30/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:35:23 POST /m0/res31/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:36:22 PUT /m0/res32/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:37:25 DELETE /m0/res33/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:38:24 PATCH /m0/res34/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:39:22 GET /m0/res35/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:40:23 POST /m0/res36/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:41:22 PUT /m0/res37/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:42:25 DELETE /m0/res38/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:43:24 PATCH /m0/res39/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:44:22 GET /m0/res40/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:45:23 POST /m0/res41/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:46:22 PUT /m0/res42/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:47:25 DELETE /m0/res43/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:48:24 PATCH /m0/res44/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:49:22 GET /m0/res45/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:4:21 GET /m0/res0/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:50:23 POST /m0/res46/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:51:22 PUT /m0/res47/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:52:25 DELETE /m0/res48/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:53:24 PATCH /m0/res49/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:54:22 GET /m0/res50/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:55:23 POST /m0/res51/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:56:22 PUT /m0/res52/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:57:25 DELETE /m0/res53/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:58:24 PATCH /m0/res54/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:59:22 GET /m0/res55/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:5:22 POST /m0/res1/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:60:23 POST /m0/res56/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:61:22 PUT /m0/res57/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:62:25 DELETE /m0/res58/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:63:24 PATCH /m0/res59/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:64:22 GET /m0/res60/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:65:23 POST /m0/res61/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:66:22 PUT /m0/res62/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:67:25 DELETE /m0/res63/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:68:24 PATCH /m0/res64/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:69:22 GET /m0/res65/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:6:21 PUT /m0/res2/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:70:23 POST /m0/res66/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:71:22 PUT /m0/res67/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:72:25 DELETE /m0/res68/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:73:24 PATCH /m0/res69/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:74:22 GET /m0/res70/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:75:23 POST /m0/res71/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:76:22 PUT /m0/res72/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:77:25 DELETE /m0/res73/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:78:24 PATCH /m0/res74/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:79:22 GET /m0/res75/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:7:24 DELETE /m0/res3/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:80:23 POST /m0/res76/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:81:22 PUT /m0/res77/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:82:25 DELETE /m0/res78/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:83:24 PATCH /m0/res79/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:84:22 GET /m0/res80/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:85:23 POST /m0/res81/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:86:22 PUT /m0/res82/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:87:25 DELETE /m0/res83/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:88:24 PATCH /m0/res84/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:89:22 GET /m0/res85/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:8:23 PATCH /m0/res4/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:90:23 POST /m0/res86/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:91:22 PUT /m0/res87/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:92:25 DELETE /m0/res88/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:93:24 PATCH /m0/res89/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:94:22 GET /m0/res90/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:95:23 POST /m0/res91/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:96:22 PUT /m0/res92/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:97:25 DELETE /m0/res93/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:98:24 PATCH /m0/res94/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:99:22 GET /m0/res95/:id index.ts:24:13 +regby mod0.ts:1:1 mod0.ts:9:21 GET /m0/res5/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:100:23 POST /m1/res96/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:101:22 PUT /m1/res97/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:102:25 DELETE /m1/res98/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:103:24 PATCH /m1/res99/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:10:22 POST /m1/res6/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:11:21 PUT /m1/res7/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:12:24 DELETE /m1/res8/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:13:23 PATCH /m1/res9/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:14:22 GET /m1/res10/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:15:23 POST /m1/res11/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:16:22 PUT /m1/res12/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:17:25 DELETE /m1/res13/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:18:24 PATCH /m1/res14/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:19:22 GET /m1/res15/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:20:23 POST /m1/res16/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:21:22 PUT /m1/res17/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:22:25 DELETE /m1/res18/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:23:24 PATCH /m1/res19/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:24:22 GET /m1/res20/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:25:23 POST /m1/res21/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:26:22 PUT /m1/res22/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:27:25 DELETE /m1/res23/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:28:24 PATCH /m1/res24/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:29:22 GET /m1/res25/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:30:23 POST /m1/res26/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:31:22 PUT /m1/res27/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:32:25 DELETE /m1/res28/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:33:24 PATCH /m1/res29/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:34:22 GET /m1/res30/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:35:23 POST /m1/res31/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:36:22 PUT /m1/res32/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:37:25 DELETE /m1/res33/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:38:24 PATCH /m1/res34/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:39:22 GET /m1/res35/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:40:23 POST /m1/res36/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:41:22 PUT /m1/res37/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:42:25 DELETE /m1/res38/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:43:24 PATCH /m1/res39/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:44:22 GET /m1/res40/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:45:23 POST /m1/res41/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:46:22 PUT /m1/res42/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:47:25 DELETE /m1/res43/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:48:24 PATCH /m1/res44/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:49:22 GET /m1/res45/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:4:21 GET /m1/res0/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:50:23 POST /m1/res46/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:51:22 PUT /m1/res47/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:52:25 DELETE /m1/res48/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:53:24 PATCH /m1/res49/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:54:22 GET /m1/res50/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:55:23 POST /m1/res51/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:56:22 PUT /m1/res52/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:57:25 DELETE /m1/res53/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:58:24 PATCH /m1/res54/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:59:22 GET /m1/res55/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:5:22 POST /m1/res1/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:60:23 POST /m1/res56/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:61:22 PUT /m1/res57/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:62:25 DELETE /m1/res58/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:63:24 PATCH /m1/res59/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:64:22 GET /m1/res60/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:65:23 POST /m1/res61/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:66:22 PUT /m1/res62/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:67:25 DELETE /m1/res63/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:68:24 PATCH /m1/res64/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:69:22 GET /m1/res65/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:6:21 PUT /m1/res2/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:70:23 POST /m1/res66/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:71:22 PUT /m1/res67/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:72:25 DELETE /m1/res68/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:73:24 PATCH /m1/res69/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:74:22 GET /m1/res70/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:75:23 POST /m1/res71/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:76:22 PUT /m1/res72/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:77:25 DELETE /m1/res73/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:78:24 PATCH /m1/res74/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:79:22 GET /m1/res75/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:7:24 DELETE /m1/res3/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:80:23 POST /m1/res76/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:81:22 PUT /m1/res77/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:82:25 DELETE /m1/res78/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:83:24 PATCH /m1/res79/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:84:22 GET /m1/res80/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:85:23 POST /m1/res81/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:86:22 PUT /m1/res82/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:87:25 DELETE /m1/res83/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:88:24 PATCH /m1/res84/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:89:22 GET /m1/res85/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:8:23 PATCH /m1/res4/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:90:23 POST /m1/res86/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:91:22 PUT /m1/res87/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:92:25 DELETE /m1/res88/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:93:24 PATCH /m1/res89/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:94:22 GET /m1/res90/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:95:23 POST /m1/res91/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:96:22 PUT /m1/res92/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:97:25 DELETE /m1/res93/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:98:24 PATCH /m1/res94/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:99:22 GET /m1/res95/:id index.ts:24:13 +regby mod1.ts:1:1 mod1.ts:9:21 GET /m1/res5/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:100:24 POST /m10/res96/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:101:23 PUT /m10/res97/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:102:26 DELETE /m10/res98/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:103:25 PATCH /m10/res99/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:10:23 POST /m10/res6/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:11:22 PUT /m10/res7/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:12:25 DELETE /m10/res8/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:13:24 PATCH /m10/res9/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:14:23 GET /m10/res10/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:15:24 POST /m10/res11/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:16:23 PUT /m10/res12/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:17:26 DELETE /m10/res13/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:18:25 PATCH /m10/res14/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:19:23 GET /m10/res15/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:20:24 POST /m10/res16/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:21:23 PUT /m10/res17/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:22:26 DELETE /m10/res18/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:23:25 PATCH /m10/res19/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:24:23 GET /m10/res20/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:25:24 POST /m10/res21/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:26:23 PUT /m10/res22/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:27:26 DELETE /m10/res23/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:28:25 PATCH /m10/res24/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:29:23 GET /m10/res25/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:30:24 POST /m10/res26/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:31:23 PUT /m10/res27/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:32:26 DELETE /m10/res28/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:33:25 PATCH /m10/res29/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:34:23 GET /m10/res30/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:35:24 POST /m10/res31/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:36:23 PUT /m10/res32/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:37:26 DELETE /m10/res33/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:38:25 PATCH /m10/res34/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:39:23 GET /m10/res35/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:40:24 POST /m10/res36/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:41:23 PUT /m10/res37/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:42:26 DELETE /m10/res38/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:43:25 PATCH /m10/res39/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:44:23 GET /m10/res40/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:45:24 POST /m10/res41/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:46:23 PUT /m10/res42/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:47:26 DELETE /m10/res43/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:48:25 PATCH /m10/res44/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:49:23 GET /m10/res45/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:4:22 GET /m10/res0/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:50:24 POST /m10/res46/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:51:23 PUT /m10/res47/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:52:26 DELETE /m10/res48/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:53:25 PATCH /m10/res49/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:54:23 GET /m10/res50/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:55:24 POST /m10/res51/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:56:23 PUT /m10/res52/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:57:26 DELETE /m10/res53/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:58:25 PATCH /m10/res54/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:59:23 GET /m10/res55/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:5:23 POST /m10/res1/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:60:24 POST /m10/res56/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:61:23 PUT /m10/res57/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:62:26 DELETE /m10/res58/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:63:25 PATCH /m10/res59/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:64:23 GET /m10/res60/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:65:24 POST /m10/res61/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:66:23 PUT /m10/res62/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:67:26 DELETE /m10/res63/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:68:25 PATCH /m10/res64/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:69:23 GET /m10/res65/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:6:22 PUT /m10/res2/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:70:24 POST /m10/res66/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:71:23 PUT /m10/res67/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:72:26 DELETE /m10/res68/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:73:25 PATCH /m10/res69/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:74:23 GET /m10/res70/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:75:24 POST /m10/res71/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:76:23 PUT /m10/res72/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:77:26 DELETE /m10/res73/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:78:25 PATCH /m10/res74/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:79:23 GET /m10/res75/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:7:25 DELETE /m10/res3/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:80:24 POST /m10/res76/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:81:23 PUT /m10/res77/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:82:26 DELETE /m10/res78/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:83:25 PATCH /m10/res79/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:84:23 GET /m10/res80/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:85:24 POST /m10/res81/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:86:23 PUT /m10/res82/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:87:26 DELETE /m10/res83/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:88:25 PATCH /m10/res84/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:89:23 GET /m10/res85/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:8:24 PATCH /m10/res4/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:90:24 POST /m10/res86/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:91:23 PUT /m10/res87/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:92:26 DELETE /m10/res88/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:93:25 PATCH /m10/res89/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:94:23 GET /m10/res90/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:95:24 POST /m10/res91/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:96:23 PUT /m10/res92/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:97:26 DELETE /m10/res93/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:98:25 PATCH /m10/res94/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:99:23 GET /m10/res95/:id index.ts:24:13 +regby mod10.ts:1:1 mod10.ts:9:22 GET /m10/res5/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:100:24 POST /m11/res96/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:101:23 PUT /m11/res97/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:102:26 DELETE /m11/res98/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:103:25 PATCH /m11/res99/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:10:23 POST /m11/res6/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:11:22 PUT /m11/res7/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:12:25 DELETE /m11/res8/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:13:24 PATCH /m11/res9/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:14:23 GET /m11/res10/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:15:24 POST /m11/res11/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:16:23 PUT /m11/res12/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:17:26 DELETE /m11/res13/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:18:25 PATCH /m11/res14/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:19:23 GET /m11/res15/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:20:24 POST /m11/res16/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:21:23 PUT /m11/res17/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:22:26 DELETE /m11/res18/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:23:25 PATCH /m11/res19/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:24:23 GET /m11/res20/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:25:24 POST /m11/res21/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:26:23 PUT /m11/res22/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:27:26 DELETE /m11/res23/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:28:25 PATCH /m11/res24/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:29:23 GET /m11/res25/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:30:24 POST /m11/res26/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:31:23 PUT /m11/res27/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:32:26 DELETE /m11/res28/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:33:25 PATCH /m11/res29/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:34:23 GET /m11/res30/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:35:24 POST /m11/res31/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:36:23 PUT /m11/res32/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:37:26 DELETE /m11/res33/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:38:25 PATCH /m11/res34/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:39:23 GET /m11/res35/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:40:24 POST /m11/res36/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:41:23 PUT /m11/res37/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:42:26 DELETE /m11/res38/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:43:25 PATCH /m11/res39/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:44:23 GET /m11/res40/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:45:24 POST /m11/res41/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:46:23 PUT /m11/res42/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:47:26 DELETE /m11/res43/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:48:25 PATCH /m11/res44/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:49:23 GET /m11/res45/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:4:22 GET /m11/res0/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:50:24 POST /m11/res46/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:51:23 PUT /m11/res47/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:52:26 DELETE /m11/res48/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:53:25 PATCH /m11/res49/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:54:23 GET /m11/res50/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:55:24 POST /m11/res51/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:56:23 PUT /m11/res52/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:57:26 DELETE /m11/res53/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:58:25 PATCH /m11/res54/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:59:23 GET /m11/res55/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:5:23 POST /m11/res1/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:60:24 POST /m11/res56/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:61:23 PUT /m11/res57/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:62:26 DELETE /m11/res58/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:63:25 PATCH /m11/res59/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:64:23 GET /m11/res60/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:65:24 POST /m11/res61/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:66:23 PUT /m11/res62/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:67:26 DELETE /m11/res63/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:68:25 PATCH /m11/res64/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:69:23 GET /m11/res65/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:6:22 PUT /m11/res2/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:70:24 POST /m11/res66/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:71:23 PUT /m11/res67/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:72:26 DELETE /m11/res68/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:73:25 PATCH /m11/res69/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:74:23 GET /m11/res70/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:75:24 POST /m11/res71/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:76:23 PUT /m11/res72/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:77:26 DELETE /m11/res73/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:78:25 PATCH /m11/res74/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:79:23 GET /m11/res75/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:7:25 DELETE /m11/res3/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:80:24 POST /m11/res76/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:81:23 PUT /m11/res77/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:82:26 DELETE /m11/res78/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:83:25 PATCH /m11/res79/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:84:23 GET /m11/res80/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:85:24 POST /m11/res81/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:86:23 PUT /m11/res82/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:87:26 DELETE /m11/res83/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:88:25 PATCH /m11/res84/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:89:23 GET /m11/res85/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:8:24 PATCH /m11/res4/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:90:24 POST /m11/res86/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:91:23 PUT /m11/res87/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:92:26 DELETE /m11/res88/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:93:25 PATCH /m11/res89/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:94:23 GET /m11/res90/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:95:24 POST /m11/res91/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:96:23 PUT /m11/res92/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:97:26 DELETE /m11/res93/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:98:25 PATCH /m11/res94/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:99:23 GET /m11/res95/:id index.ts:24:13 +regby mod11.ts:1:1 mod11.ts:9:22 GET /m11/res5/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:100:24 POST /m12/res96/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:101:23 PUT /m12/res97/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:102:26 DELETE /m12/res98/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:103:25 PATCH /m12/res99/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:10:23 POST /m12/res6/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:11:22 PUT /m12/res7/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:12:25 DELETE /m12/res8/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:13:24 PATCH /m12/res9/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:14:23 GET /m12/res10/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:15:24 POST /m12/res11/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:16:23 PUT /m12/res12/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:17:26 DELETE /m12/res13/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:18:25 PATCH /m12/res14/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:19:23 GET /m12/res15/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:20:24 POST /m12/res16/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:21:23 PUT /m12/res17/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:22:26 DELETE /m12/res18/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:23:25 PATCH /m12/res19/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:24:23 GET /m12/res20/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:25:24 POST /m12/res21/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:26:23 PUT /m12/res22/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:27:26 DELETE /m12/res23/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:28:25 PATCH /m12/res24/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:29:23 GET /m12/res25/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:30:24 POST /m12/res26/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:31:23 PUT /m12/res27/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:32:26 DELETE /m12/res28/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:33:25 PATCH /m12/res29/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:34:23 GET /m12/res30/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:35:24 POST /m12/res31/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:36:23 PUT /m12/res32/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:37:26 DELETE /m12/res33/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:38:25 PATCH /m12/res34/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:39:23 GET /m12/res35/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:40:24 POST /m12/res36/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:41:23 PUT /m12/res37/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:42:26 DELETE /m12/res38/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:43:25 PATCH /m12/res39/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:44:23 GET /m12/res40/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:45:24 POST /m12/res41/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:46:23 PUT /m12/res42/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:47:26 DELETE /m12/res43/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:48:25 PATCH /m12/res44/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:49:23 GET /m12/res45/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:4:22 GET /m12/res0/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:50:24 POST /m12/res46/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:51:23 PUT /m12/res47/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:52:26 DELETE /m12/res48/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:53:25 PATCH /m12/res49/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:54:23 GET /m12/res50/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:55:24 POST /m12/res51/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:56:23 PUT /m12/res52/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:57:26 DELETE /m12/res53/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:58:25 PATCH /m12/res54/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:59:23 GET /m12/res55/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:5:23 POST /m12/res1/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:60:24 POST /m12/res56/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:61:23 PUT /m12/res57/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:62:26 DELETE /m12/res58/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:63:25 PATCH /m12/res59/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:64:23 GET /m12/res60/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:65:24 POST /m12/res61/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:66:23 PUT /m12/res62/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:67:26 DELETE /m12/res63/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:68:25 PATCH /m12/res64/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:69:23 GET /m12/res65/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:6:22 PUT /m12/res2/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:70:24 POST /m12/res66/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:71:23 PUT /m12/res67/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:72:26 DELETE /m12/res68/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:73:25 PATCH /m12/res69/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:74:23 GET /m12/res70/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:75:24 POST /m12/res71/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:76:23 PUT /m12/res72/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:77:26 DELETE /m12/res73/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:78:25 PATCH /m12/res74/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:79:23 GET /m12/res75/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:7:25 DELETE /m12/res3/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:80:24 POST /m12/res76/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:81:23 PUT /m12/res77/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:82:26 DELETE /m12/res78/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:83:25 PATCH /m12/res79/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:84:23 GET /m12/res80/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:85:24 POST /m12/res81/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:86:23 PUT /m12/res82/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:87:26 DELETE /m12/res83/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:88:25 PATCH /m12/res84/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:89:23 GET /m12/res85/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:8:24 PATCH /m12/res4/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:90:24 POST /m12/res86/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:91:23 PUT /m12/res87/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:92:26 DELETE /m12/res88/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:93:25 PATCH /m12/res89/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:94:23 GET /m12/res90/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:95:24 POST /m12/res91/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:96:23 PUT /m12/res92/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:97:26 DELETE /m12/res93/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:98:25 PATCH /m12/res94/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:99:23 GET /m12/res95/:id index.ts:24:13 +regby mod12.ts:1:1 mod12.ts:9:22 GET /m12/res5/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:100:24 POST /m13/res96/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:101:23 PUT /m13/res97/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:102:26 DELETE /m13/res98/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:103:25 PATCH /m13/res99/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:10:23 POST /m13/res6/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:11:22 PUT /m13/res7/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:12:25 DELETE /m13/res8/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:13:24 PATCH /m13/res9/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:14:23 GET /m13/res10/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:15:24 POST /m13/res11/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:16:23 PUT /m13/res12/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:17:26 DELETE /m13/res13/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:18:25 PATCH /m13/res14/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:19:23 GET /m13/res15/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:20:24 POST /m13/res16/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:21:23 PUT /m13/res17/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:22:26 DELETE /m13/res18/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:23:25 PATCH /m13/res19/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:24:23 GET /m13/res20/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:25:24 POST /m13/res21/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:26:23 PUT /m13/res22/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:27:26 DELETE /m13/res23/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:28:25 PATCH /m13/res24/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:29:23 GET /m13/res25/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:30:24 POST /m13/res26/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:31:23 PUT /m13/res27/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:32:26 DELETE /m13/res28/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:33:25 PATCH /m13/res29/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:34:23 GET /m13/res30/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:35:24 POST /m13/res31/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:36:23 PUT /m13/res32/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:37:26 DELETE /m13/res33/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:38:25 PATCH /m13/res34/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:39:23 GET /m13/res35/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:40:24 POST /m13/res36/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:41:23 PUT /m13/res37/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:42:26 DELETE /m13/res38/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:43:25 PATCH /m13/res39/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:44:23 GET /m13/res40/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:45:24 POST /m13/res41/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:46:23 PUT /m13/res42/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:47:26 DELETE /m13/res43/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:48:25 PATCH /m13/res44/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:49:23 GET /m13/res45/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:4:22 GET /m13/res0/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:50:24 POST /m13/res46/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:51:23 PUT /m13/res47/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:52:26 DELETE /m13/res48/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:53:25 PATCH /m13/res49/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:54:23 GET /m13/res50/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:55:24 POST /m13/res51/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:56:23 PUT /m13/res52/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:57:26 DELETE /m13/res53/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:58:25 PATCH /m13/res54/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:59:23 GET /m13/res55/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:5:23 POST /m13/res1/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:60:24 POST /m13/res56/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:61:23 PUT /m13/res57/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:62:26 DELETE /m13/res58/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:63:25 PATCH /m13/res59/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:64:23 GET /m13/res60/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:65:24 POST /m13/res61/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:66:23 PUT /m13/res62/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:67:26 DELETE /m13/res63/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:68:25 PATCH /m13/res64/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:69:23 GET /m13/res65/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:6:22 PUT /m13/res2/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:70:24 POST /m13/res66/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:71:23 PUT /m13/res67/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:72:26 DELETE /m13/res68/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:73:25 PATCH /m13/res69/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:74:23 GET /m13/res70/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:75:24 POST /m13/res71/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:76:23 PUT /m13/res72/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:77:26 DELETE /m13/res73/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:78:25 PATCH /m13/res74/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:79:23 GET /m13/res75/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:7:25 DELETE /m13/res3/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:80:24 POST /m13/res76/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:81:23 PUT /m13/res77/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:82:26 DELETE /m13/res78/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:83:25 PATCH /m13/res79/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:84:23 GET /m13/res80/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:85:24 POST /m13/res81/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:86:23 PUT /m13/res82/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:87:26 DELETE /m13/res83/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:88:25 PATCH /m13/res84/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:89:23 GET /m13/res85/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:8:24 PATCH /m13/res4/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:90:24 POST /m13/res86/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:91:23 PUT /m13/res87/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:92:26 DELETE /m13/res88/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:93:25 PATCH /m13/res89/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:94:23 GET /m13/res90/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:95:24 POST /m13/res91/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:96:23 PUT /m13/res92/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:97:26 DELETE /m13/res93/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:98:25 PATCH /m13/res94/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:99:23 GET /m13/res95/:id index.ts:24:13 +regby mod13.ts:1:1 mod13.ts:9:22 GET /m13/res5/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:100:24 POST /m14/res96/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:101:23 PUT /m14/res97/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:102:26 DELETE /m14/res98/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:103:25 PATCH /m14/res99/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:10:23 POST /m14/res6/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:11:22 PUT /m14/res7/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:12:25 DELETE /m14/res8/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:13:24 PATCH /m14/res9/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:14:23 GET /m14/res10/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:15:24 POST /m14/res11/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:16:23 PUT /m14/res12/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:17:26 DELETE /m14/res13/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:18:25 PATCH /m14/res14/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:19:23 GET /m14/res15/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:20:24 POST /m14/res16/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:21:23 PUT /m14/res17/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:22:26 DELETE /m14/res18/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:23:25 PATCH /m14/res19/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:24:23 GET /m14/res20/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:25:24 POST /m14/res21/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:26:23 PUT /m14/res22/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:27:26 DELETE /m14/res23/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:28:25 PATCH /m14/res24/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:29:23 GET /m14/res25/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:30:24 POST /m14/res26/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:31:23 PUT /m14/res27/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:32:26 DELETE /m14/res28/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:33:25 PATCH /m14/res29/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:34:23 GET /m14/res30/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:35:24 POST /m14/res31/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:36:23 PUT /m14/res32/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:37:26 DELETE /m14/res33/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:38:25 PATCH /m14/res34/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:39:23 GET /m14/res35/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:40:24 POST /m14/res36/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:41:23 PUT /m14/res37/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:42:26 DELETE /m14/res38/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:43:25 PATCH /m14/res39/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:44:23 GET /m14/res40/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:45:24 POST /m14/res41/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:46:23 PUT /m14/res42/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:47:26 DELETE /m14/res43/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:48:25 PATCH /m14/res44/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:49:23 GET /m14/res45/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:4:22 GET /m14/res0/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:50:24 POST /m14/res46/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:51:23 PUT /m14/res47/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:52:26 DELETE /m14/res48/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:53:25 PATCH /m14/res49/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:54:23 GET /m14/res50/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:55:24 POST /m14/res51/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:56:23 PUT /m14/res52/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:57:26 DELETE /m14/res53/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:58:25 PATCH /m14/res54/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:59:23 GET /m14/res55/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:5:23 POST /m14/res1/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:60:24 POST /m14/res56/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:61:23 PUT /m14/res57/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:62:26 DELETE /m14/res58/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:63:25 PATCH /m14/res59/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:64:23 GET /m14/res60/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:65:24 POST /m14/res61/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:66:23 PUT /m14/res62/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:67:26 DELETE /m14/res63/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:68:25 PATCH /m14/res64/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:69:23 GET /m14/res65/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:6:22 PUT /m14/res2/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:70:24 POST /m14/res66/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:71:23 PUT /m14/res67/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:72:26 DELETE /m14/res68/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:73:25 PATCH /m14/res69/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:74:23 GET /m14/res70/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:75:24 POST /m14/res71/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:76:23 PUT /m14/res72/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:77:26 DELETE /m14/res73/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:78:25 PATCH /m14/res74/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:79:23 GET /m14/res75/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:7:25 DELETE /m14/res3/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:80:24 POST /m14/res76/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:81:23 PUT /m14/res77/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:82:26 DELETE /m14/res78/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:83:25 PATCH /m14/res79/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:84:23 GET /m14/res80/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:85:24 POST /m14/res81/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:86:23 PUT /m14/res82/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:87:26 DELETE /m14/res83/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:88:25 PATCH /m14/res84/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:89:23 GET /m14/res85/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:8:24 PATCH /m14/res4/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:90:24 POST /m14/res86/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:91:23 PUT /m14/res87/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:92:26 DELETE /m14/res88/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:93:25 PATCH /m14/res89/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:94:23 GET /m14/res90/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:95:24 POST /m14/res91/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:96:23 PUT /m14/res92/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:97:26 DELETE /m14/res93/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:98:25 PATCH /m14/res94/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:99:23 GET /m14/res95/:id index.ts:24:13 +regby mod14.ts:1:1 mod14.ts:9:22 GET /m14/res5/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:100:24 POST /m15/res96/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:101:23 PUT /m15/res97/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:102:26 DELETE /m15/res98/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:103:25 PATCH /m15/res99/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:10:23 POST /m15/res6/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:11:22 PUT /m15/res7/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:12:25 DELETE /m15/res8/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:13:24 PATCH /m15/res9/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:14:23 GET /m15/res10/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:15:24 POST /m15/res11/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:16:23 PUT /m15/res12/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:17:26 DELETE /m15/res13/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:18:25 PATCH /m15/res14/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:19:23 GET /m15/res15/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:20:24 POST /m15/res16/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:21:23 PUT /m15/res17/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:22:26 DELETE /m15/res18/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:23:25 PATCH /m15/res19/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:24:23 GET /m15/res20/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:25:24 POST /m15/res21/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:26:23 PUT /m15/res22/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:27:26 DELETE /m15/res23/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:28:25 PATCH /m15/res24/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:29:23 GET /m15/res25/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:30:24 POST /m15/res26/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:31:23 PUT /m15/res27/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:32:26 DELETE /m15/res28/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:33:25 PATCH /m15/res29/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:34:23 GET /m15/res30/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:35:24 POST /m15/res31/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:36:23 PUT /m15/res32/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:37:26 DELETE /m15/res33/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:38:25 PATCH /m15/res34/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:39:23 GET /m15/res35/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:40:24 POST /m15/res36/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:41:23 PUT /m15/res37/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:42:26 DELETE /m15/res38/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:43:25 PATCH /m15/res39/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:44:23 GET /m15/res40/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:45:24 POST /m15/res41/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:46:23 PUT /m15/res42/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:47:26 DELETE /m15/res43/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:48:25 PATCH /m15/res44/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:49:23 GET /m15/res45/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:4:22 GET /m15/res0/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:50:24 POST /m15/res46/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:51:23 PUT /m15/res47/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:52:26 DELETE /m15/res48/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:53:25 PATCH /m15/res49/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:54:23 GET /m15/res50/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:55:24 POST /m15/res51/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:56:23 PUT /m15/res52/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:57:26 DELETE /m15/res53/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:58:25 PATCH /m15/res54/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:59:23 GET /m15/res55/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:5:23 POST /m15/res1/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:60:24 POST /m15/res56/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:61:23 PUT /m15/res57/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:62:26 DELETE /m15/res58/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:63:25 PATCH /m15/res59/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:64:23 GET /m15/res60/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:65:24 POST /m15/res61/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:66:23 PUT /m15/res62/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:67:26 DELETE /m15/res63/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:68:25 PATCH /m15/res64/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:69:23 GET /m15/res65/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:6:22 PUT /m15/res2/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:70:24 POST /m15/res66/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:71:23 PUT /m15/res67/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:72:26 DELETE /m15/res68/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:73:25 PATCH /m15/res69/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:74:23 GET /m15/res70/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:75:24 POST /m15/res71/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:76:23 PUT /m15/res72/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:77:26 DELETE /m15/res73/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:78:25 PATCH /m15/res74/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:79:23 GET /m15/res75/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:7:25 DELETE /m15/res3/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:80:24 POST /m15/res76/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:81:23 PUT /m15/res77/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:82:26 DELETE /m15/res78/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:83:25 PATCH /m15/res79/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:84:23 GET /m15/res80/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:85:24 POST /m15/res81/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:86:23 PUT /m15/res82/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:87:26 DELETE /m15/res83/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:88:25 PATCH /m15/res84/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:89:23 GET /m15/res85/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:8:24 PATCH /m15/res4/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:90:24 POST /m15/res86/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:91:23 PUT /m15/res87/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:92:26 DELETE /m15/res88/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:93:25 PATCH /m15/res89/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:94:23 GET /m15/res90/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:95:24 POST /m15/res91/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:96:23 PUT /m15/res92/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:97:26 DELETE /m15/res93/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:98:25 PATCH /m15/res94/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:99:23 GET /m15/res95/:id index.ts:24:13 +regby mod15.ts:1:1 mod15.ts:9:22 GET /m15/res5/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:100:24 POST /m16/res96/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:101:23 PUT /m16/res97/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:102:26 DELETE /m16/res98/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:103:25 PATCH /m16/res99/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:10:23 POST /m16/res6/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:11:22 PUT /m16/res7/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:12:25 DELETE /m16/res8/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:13:24 PATCH /m16/res9/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:14:23 GET /m16/res10/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:15:24 POST /m16/res11/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:16:23 PUT /m16/res12/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:17:26 DELETE /m16/res13/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:18:25 PATCH /m16/res14/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:19:23 GET /m16/res15/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:20:24 POST /m16/res16/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:21:23 PUT /m16/res17/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:22:26 DELETE /m16/res18/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:23:25 PATCH /m16/res19/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:24:23 GET /m16/res20/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:25:24 POST /m16/res21/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:26:23 PUT /m16/res22/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:27:26 DELETE /m16/res23/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:28:25 PATCH /m16/res24/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:29:23 GET /m16/res25/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:30:24 POST /m16/res26/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:31:23 PUT /m16/res27/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:32:26 DELETE /m16/res28/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:33:25 PATCH /m16/res29/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:34:23 GET /m16/res30/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:35:24 POST /m16/res31/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:36:23 PUT /m16/res32/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:37:26 DELETE /m16/res33/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:38:25 PATCH /m16/res34/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:39:23 GET /m16/res35/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:40:24 POST /m16/res36/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:41:23 PUT /m16/res37/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:42:26 DELETE /m16/res38/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:43:25 PATCH /m16/res39/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:44:23 GET /m16/res40/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:45:24 POST /m16/res41/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:46:23 PUT /m16/res42/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:47:26 DELETE /m16/res43/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:48:25 PATCH /m16/res44/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:49:23 GET /m16/res45/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:4:22 GET /m16/res0/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:50:24 POST /m16/res46/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:51:23 PUT /m16/res47/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:52:26 DELETE /m16/res48/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:53:25 PATCH /m16/res49/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:54:23 GET /m16/res50/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:55:24 POST /m16/res51/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:56:23 PUT /m16/res52/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:57:26 DELETE /m16/res53/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:58:25 PATCH /m16/res54/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:59:23 GET /m16/res55/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:5:23 POST /m16/res1/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:60:24 POST /m16/res56/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:61:23 PUT /m16/res57/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:62:26 DELETE /m16/res58/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:63:25 PATCH /m16/res59/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:64:23 GET /m16/res60/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:65:24 POST /m16/res61/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:66:23 PUT /m16/res62/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:67:26 DELETE /m16/res63/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:68:25 PATCH /m16/res64/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:69:23 GET /m16/res65/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:6:22 PUT /m16/res2/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:70:24 POST /m16/res66/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:71:23 PUT /m16/res67/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:72:26 DELETE /m16/res68/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:73:25 PATCH /m16/res69/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:74:23 GET /m16/res70/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:75:24 POST /m16/res71/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:76:23 PUT /m16/res72/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:77:26 DELETE /m16/res73/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:78:25 PATCH /m16/res74/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:79:23 GET /m16/res75/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:7:25 DELETE /m16/res3/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:80:24 POST /m16/res76/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:81:23 PUT /m16/res77/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:82:26 DELETE /m16/res78/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:83:25 PATCH /m16/res79/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:84:23 GET /m16/res80/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:85:24 POST /m16/res81/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:86:23 PUT /m16/res82/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:87:26 DELETE /m16/res83/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:88:25 PATCH /m16/res84/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:89:23 GET /m16/res85/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:8:24 PATCH /m16/res4/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:90:24 POST /m16/res86/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:91:23 PUT /m16/res87/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:92:26 DELETE /m16/res88/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:93:25 PATCH /m16/res89/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:94:23 GET /m16/res90/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:95:24 POST /m16/res91/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:96:23 PUT /m16/res92/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:97:26 DELETE /m16/res93/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:98:25 PATCH /m16/res94/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:99:23 GET /m16/res95/:id index.ts:24:13 +regby mod16.ts:1:1 mod16.ts:9:22 GET /m16/res5/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:100:24 POST /m17/res96/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:101:23 PUT /m17/res97/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:102:26 DELETE /m17/res98/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:103:25 PATCH /m17/res99/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:10:23 POST /m17/res6/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:11:22 PUT /m17/res7/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:12:25 DELETE /m17/res8/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:13:24 PATCH /m17/res9/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:14:23 GET /m17/res10/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:15:24 POST /m17/res11/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:16:23 PUT /m17/res12/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:17:26 DELETE /m17/res13/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:18:25 PATCH /m17/res14/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:19:23 GET /m17/res15/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:20:24 POST /m17/res16/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:21:23 PUT /m17/res17/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:22:26 DELETE /m17/res18/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:23:25 PATCH /m17/res19/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:24:23 GET /m17/res20/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:25:24 POST /m17/res21/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:26:23 PUT /m17/res22/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:27:26 DELETE /m17/res23/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:28:25 PATCH /m17/res24/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:29:23 GET /m17/res25/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:30:24 POST /m17/res26/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:31:23 PUT /m17/res27/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:32:26 DELETE /m17/res28/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:33:25 PATCH /m17/res29/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:34:23 GET /m17/res30/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:35:24 POST /m17/res31/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:36:23 PUT /m17/res32/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:37:26 DELETE /m17/res33/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:38:25 PATCH /m17/res34/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:39:23 GET /m17/res35/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:40:24 POST /m17/res36/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:41:23 PUT /m17/res37/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:42:26 DELETE /m17/res38/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:43:25 PATCH /m17/res39/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:44:23 GET /m17/res40/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:45:24 POST /m17/res41/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:46:23 PUT /m17/res42/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:47:26 DELETE /m17/res43/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:48:25 PATCH /m17/res44/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:49:23 GET /m17/res45/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:4:22 GET /m17/res0/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:50:24 POST /m17/res46/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:51:23 PUT /m17/res47/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:52:26 DELETE /m17/res48/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:53:25 PATCH /m17/res49/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:54:23 GET /m17/res50/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:55:24 POST /m17/res51/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:56:23 PUT /m17/res52/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:57:26 DELETE /m17/res53/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:58:25 PATCH /m17/res54/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:59:23 GET /m17/res55/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:5:23 POST /m17/res1/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:60:24 POST /m17/res56/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:61:23 PUT /m17/res57/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:62:26 DELETE /m17/res58/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:63:25 PATCH /m17/res59/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:64:23 GET /m17/res60/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:65:24 POST /m17/res61/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:66:23 PUT /m17/res62/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:67:26 DELETE /m17/res63/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:68:25 PATCH /m17/res64/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:69:23 GET /m17/res65/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:6:22 PUT /m17/res2/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:70:24 POST /m17/res66/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:71:23 PUT /m17/res67/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:72:26 DELETE /m17/res68/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:73:25 PATCH /m17/res69/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:74:23 GET /m17/res70/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:75:24 POST /m17/res71/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:76:23 PUT /m17/res72/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:77:26 DELETE /m17/res73/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:78:25 PATCH /m17/res74/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:79:23 GET /m17/res75/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:7:25 DELETE /m17/res3/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:80:24 POST /m17/res76/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:81:23 PUT /m17/res77/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:82:26 DELETE /m17/res78/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:83:25 PATCH /m17/res79/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:84:23 GET /m17/res80/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:85:24 POST /m17/res81/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:86:23 PUT /m17/res82/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:87:26 DELETE /m17/res83/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:88:25 PATCH /m17/res84/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:89:23 GET /m17/res85/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:8:24 PATCH /m17/res4/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:90:24 POST /m17/res86/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:91:23 PUT /m17/res87/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:92:26 DELETE /m17/res88/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:93:25 PATCH /m17/res89/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:94:23 GET /m17/res90/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:95:24 POST /m17/res91/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:96:23 PUT /m17/res92/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:97:26 DELETE /m17/res93/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:98:25 PATCH /m17/res94/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:99:23 GET /m17/res95/:id index.ts:24:13 +regby mod17.ts:1:1 mod17.ts:9:22 GET /m17/res5/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:100:24 POST /m18/res96/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:101:23 PUT /m18/res97/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:102:26 DELETE /m18/res98/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:103:25 PATCH /m18/res99/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:10:23 POST /m18/res6/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:11:22 PUT /m18/res7/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:12:25 DELETE /m18/res8/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:13:24 PATCH /m18/res9/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:14:23 GET /m18/res10/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:15:24 POST /m18/res11/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:16:23 PUT /m18/res12/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:17:26 DELETE /m18/res13/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:18:25 PATCH /m18/res14/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:19:23 GET /m18/res15/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:20:24 POST /m18/res16/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:21:23 PUT /m18/res17/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:22:26 DELETE /m18/res18/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:23:25 PATCH /m18/res19/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:24:23 GET /m18/res20/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:25:24 POST /m18/res21/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:26:23 PUT /m18/res22/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:27:26 DELETE /m18/res23/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:28:25 PATCH /m18/res24/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:29:23 GET /m18/res25/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:30:24 POST /m18/res26/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:31:23 PUT /m18/res27/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:32:26 DELETE /m18/res28/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:33:25 PATCH /m18/res29/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:34:23 GET /m18/res30/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:35:24 POST /m18/res31/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:36:23 PUT /m18/res32/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:37:26 DELETE /m18/res33/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:38:25 PATCH /m18/res34/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:39:23 GET /m18/res35/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:40:24 POST /m18/res36/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:41:23 PUT /m18/res37/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:42:26 DELETE /m18/res38/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:43:25 PATCH /m18/res39/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:44:23 GET /m18/res40/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:45:24 POST /m18/res41/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:46:23 PUT /m18/res42/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:47:26 DELETE /m18/res43/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:48:25 PATCH /m18/res44/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:49:23 GET /m18/res45/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:4:22 GET /m18/res0/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:50:24 POST /m18/res46/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:51:23 PUT /m18/res47/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:52:26 DELETE /m18/res48/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:53:25 PATCH /m18/res49/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:54:23 GET /m18/res50/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:55:24 POST /m18/res51/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:56:23 PUT /m18/res52/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:57:26 DELETE /m18/res53/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:58:25 PATCH /m18/res54/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:59:23 GET /m18/res55/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:5:23 POST /m18/res1/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:60:24 POST /m18/res56/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:61:23 PUT /m18/res57/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:62:26 DELETE /m18/res58/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:63:25 PATCH /m18/res59/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:64:23 GET /m18/res60/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:65:24 POST /m18/res61/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:66:23 PUT /m18/res62/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:67:26 DELETE /m18/res63/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:68:25 PATCH /m18/res64/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:69:23 GET /m18/res65/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:6:22 PUT /m18/res2/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:70:24 POST /m18/res66/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:71:23 PUT /m18/res67/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:72:26 DELETE /m18/res68/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:73:25 PATCH /m18/res69/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:74:23 GET /m18/res70/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:75:24 POST /m18/res71/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:76:23 PUT /m18/res72/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:77:26 DELETE /m18/res73/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:78:25 PATCH /m18/res74/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:79:23 GET /m18/res75/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:7:25 DELETE /m18/res3/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:80:24 POST /m18/res76/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:81:23 PUT /m18/res77/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:82:26 DELETE /m18/res78/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:83:25 PATCH /m18/res79/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:84:23 GET /m18/res80/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:85:24 POST /m18/res81/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:86:23 PUT /m18/res82/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:87:26 DELETE /m18/res83/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:88:25 PATCH /m18/res84/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:89:23 GET /m18/res85/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:8:24 PATCH /m18/res4/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:90:24 POST /m18/res86/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:91:23 PUT /m18/res87/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:92:26 DELETE /m18/res88/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:93:25 PATCH /m18/res89/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:94:23 GET /m18/res90/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:95:24 POST /m18/res91/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:96:23 PUT /m18/res92/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:97:26 DELETE /m18/res93/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:98:25 PATCH /m18/res94/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:99:23 GET /m18/res95/:id index.ts:24:13 +regby mod18.ts:1:1 mod18.ts:9:22 GET /m18/res5/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:100:24 POST /m19/res96/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:101:23 PUT /m19/res97/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:102:26 DELETE /m19/res98/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:103:25 PATCH /m19/res99/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:10:23 POST /m19/res6/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:11:22 PUT /m19/res7/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:12:25 DELETE /m19/res8/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:13:24 PATCH /m19/res9/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:14:23 GET /m19/res10/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:15:24 POST /m19/res11/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:16:23 PUT /m19/res12/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:17:26 DELETE /m19/res13/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:18:25 PATCH /m19/res14/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:19:23 GET /m19/res15/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:20:24 POST /m19/res16/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:21:23 PUT /m19/res17/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:22:26 DELETE /m19/res18/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:23:25 PATCH /m19/res19/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:24:23 GET /m19/res20/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:25:24 POST /m19/res21/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:26:23 PUT /m19/res22/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:27:26 DELETE /m19/res23/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:28:25 PATCH /m19/res24/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:29:23 GET /m19/res25/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:30:24 POST /m19/res26/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:31:23 PUT /m19/res27/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:32:26 DELETE /m19/res28/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:33:25 PATCH /m19/res29/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:34:23 GET /m19/res30/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:35:24 POST /m19/res31/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:36:23 PUT /m19/res32/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:37:26 DELETE /m19/res33/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:38:25 PATCH /m19/res34/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:39:23 GET /m19/res35/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:40:24 POST /m19/res36/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:41:23 PUT /m19/res37/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:42:26 DELETE /m19/res38/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:43:25 PATCH /m19/res39/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:44:23 GET /m19/res40/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:45:24 POST /m19/res41/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:46:23 PUT /m19/res42/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:47:26 DELETE /m19/res43/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:48:25 PATCH /m19/res44/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:49:23 GET /m19/res45/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:4:22 GET /m19/res0/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:50:24 POST /m19/res46/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:51:23 PUT /m19/res47/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:52:26 DELETE /m19/res48/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:53:25 PATCH /m19/res49/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:54:23 GET /m19/res50/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:55:24 POST /m19/res51/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:56:23 PUT /m19/res52/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:57:26 DELETE /m19/res53/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:58:25 PATCH /m19/res54/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:59:23 GET /m19/res55/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:5:23 POST /m19/res1/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:60:24 POST /m19/res56/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:61:23 PUT /m19/res57/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:62:26 DELETE /m19/res58/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:63:25 PATCH /m19/res59/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:64:23 GET /m19/res60/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:65:24 POST /m19/res61/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:66:23 PUT /m19/res62/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:67:26 DELETE /m19/res63/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:68:25 PATCH /m19/res64/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:69:23 GET /m19/res65/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:6:22 PUT /m19/res2/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:70:24 POST /m19/res66/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:71:23 PUT /m19/res67/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:72:26 DELETE /m19/res68/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:73:25 PATCH /m19/res69/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:74:23 GET /m19/res70/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:75:24 POST /m19/res71/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:76:23 PUT /m19/res72/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:77:26 DELETE /m19/res73/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:78:25 PATCH /m19/res74/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:79:23 GET /m19/res75/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:7:25 DELETE /m19/res3/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:80:24 POST /m19/res76/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:81:23 PUT /m19/res77/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:82:26 DELETE /m19/res78/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:83:25 PATCH /m19/res79/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:84:23 GET /m19/res80/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:85:24 POST /m19/res81/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:86:23 PUT /m19/res82/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:87:26 DELETE /m19/res83/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:88:25 PATCH /m19/res84/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:89:23 GET /m19/res85/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:8:24 PATCH /m19/res4/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:90:24 POST /m19/res86/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:91:23 PUT /m19/res87/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:92:26 DELETE /m19/res88/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:93:25 PATCH /m19/res89/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:94:23 GET /m19/res90/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:95:24 POST /m19/res91/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:96:23 PUT /m19/res92/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:97:26 DELETE /m19/res93/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:98:25 PATCH /m19/res94/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:99:23 GET /m19/res95/:id index.ts:24:13 +regby mod19.ts:1:1 mod19.ts:9:22 GET /m19/res5/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:100:23 POST /m2/res96/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:101:22 PUT /m2/res97/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:102:25 DELETE /m2/res98/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:103:24 PATCH /m2/res99/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:10:22 POST /m2/res6/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:11:21 PUT /m2/res7/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:12:24 DELETE /m2/res8/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:13:23 PATCH /m2/res9/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:14:22 GET /m2/res10/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:15:23 POST /m2/res11/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:16:22 PUT /m2/res12/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:17:25 DELETE /m2/res13/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:18:24 PATCH /m2/res14/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:19:22 GET /m2/res15/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:20:23 POST /m2/res16/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:21:22 PUT /m2/res17/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:22:25 DELETE /m2/res18/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:23:24 PATCH /m2/res19/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:24:22 GET /m2/res20/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:25:23 POST /m2/res21/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:26:22 PUT /m2/res22/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:27:25 DELETE /m2/res23/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:28:24 PATCH /m2/res24/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:29:22 GET /m2/res25/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:30:23 POST /m2/res26/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:31:22 PUT /m2/res27/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:32:25 DELETE /m2/res28/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:33:24 PATCH /m2/res29/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:34:22 GET /m2/res30/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:35:23 POST /m2/res31/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:36:22 PUT /m2/res32/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:37:25 DELETE /m2/res33/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:38:24 PATCH /m2/res34/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:39:22 GET /m2/res35/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:40:23 POST /m2/res36/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:41:22 PUT /m2/res37/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:42:25 DELETE /m2/res38/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:43:24 PATCH /m2/res39/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:44:22 GET /m2/res40/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:45:23 POST /m2/res41/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:46:22 PUT /m2/res42/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:47:25 DELETE /m2/res43/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:48:24 PATCH /m2/res44/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:49:22 GET /m2/res45/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:4:21 GET /m2/res0/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:50:23 POST /m2/res46/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:51:22 PUT /m2/res47/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:52:25 DELETE /m2/res48/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:53:24 PATCH /m2/res49/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:54:22 GET /m2/res50/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:55:23 POST /m2/res51/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:56:22 PUT /m2/res52/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:57:25 DELETE /m2/res53/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:58:24 PATCH /m2/res54/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:59:22 GET /m2/res55/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:5:22 POST /m2/res1/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:60:23 POST /m2/res56/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:61:22 PUT /m2/res57/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:62:25 DELETE /m2/res58/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:63:24 PATCH /m2/res59/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:64:22 GET /m2/res60/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:65:23 POST /m2/res61/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:66:22 PUT /m2/res62/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:67:25 DELETE /m2/res63/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:68:24 PATCH /m2/res64/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:69:22 GET /m2/res65/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:6:21 PUT /m2/res2/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:70:23 POST /m2/res66/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:71:22 PUT /m2/res67/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:72:25 DELETE /m2/res68/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:73:24 PATCH /m2/res69/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:74:22 GET /m2/res70/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:75:23 POST /m2/res71/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:76:22 PUT /m2/res72/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:77:25 DELETE /m2/res73/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:78:24 PATCH /m2/res74/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:79:22 GET /m2/res75/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:7:24 DELETE /m2/res3/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:80:23 POST /m2/res76/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:81:22 PUT /m2/res77/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:82:25 DELETE /m2/res78/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:83:24 PATCH /m2/res79/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:84:22 GET /m2/res80/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:85:23 POST /m2/res81/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:86:22 PUT /m2/res82/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:87:25 DELETE /m2/res83/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:88:24 PATCH /m2/res84/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:89:22 GET /m2/res85/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:8:23 PATCH /m2/res4/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:90:23 POST /m2/res86/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:91:22 PUT /m2/res87/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:92:25 DELETE /m2/res88/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:93:24 PATCH /m2/res89/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:94:22 GET /m2/res90/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:95:23 POST /m2/res91/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:96:22 PUT /m2/res92/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:97:25 DELETE /m2/res93/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:98:24 PATCH /m2/res94/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:99:22 GET /m2/res95/:id index.ts:24:13 +regby mod2.ts:1:1 mod2.ts:9:21 GET /m2/res5/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:100:23 POST /m3/res96/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:101:22 PUT /m3/res97/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:102:25 DELETE /m3/res98/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:103:24 PATCH /m3/res99/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:10:22 POST /m3/res6/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:11:21 PUT /m3/res7/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:12:24 DELETE /m3/res8/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:13:23 PATCH /m3/res9/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:14:22 GET /m3/res10/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:15:23 POST /m3/res11/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:16:22 PUT /m3/res12/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:17:25 DELETE /m3/res13/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:18:24 PATCH /m3/res14/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:19:22 GET /m3/res15/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:20:23 POST /m3/res16/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:21:22 PUT /m3/res17/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:22:25 DELETE /m3/res18/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:23:24 PATCH /m3/res19/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:24:22 GET /m3/res20/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:25:23 POST /m3/res21/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:26:22 PUT /m3/res22/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:27:25 DELETE /m3/res23/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:28:24 PATCH /m3/res24/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:29:22 GET /m3/res25/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:30:23 POST /m3/res26/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:31:22 PUT /m3/res27/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:32:25 DELETE /m3/res28/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:33:24 PATCH /m3/res29/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:34:22 GET /m3/res30/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:35:23 POST /m3/res31/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:36:22 PUT /m3/res32/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:37:25 DELETE /m3/res33/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:38:24 PATCH /m3/res34/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:39:22 GET /m3/res35/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:40:23 POST /m3/res36/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:41:22 PUT /m3/res37/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:42:25 DELETE /m3/res38/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:43:24 PATCH /m3/res39/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:44:22 GET /m3/res40/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:45:23 POST /m3/res41/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:46:22 PUT /m3/res42/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:47:25 DELETE /m3/res43/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:48:24 PATCH /m3/res44/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:49:22 GET /m3/res45/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:4:21 GET /m3/res0/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:50:23 POST /m3/res46/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:51:22 PUT /m3/res47/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:52:25 DELETE /m3/res48/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:53:24 PATCH /m3/res49/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:54:22 GET /m3/res50/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:55:23 POST /m3/res51/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:56:22 PUT /m3/res52/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:57:25 DELETE /m3/res53/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:58:24 PATCH /m3/res54/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:59:22 GET /m3/res55/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:5:22 POST /m3/res1/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:60:23 POST /m3/res56/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:61:22 PUT /m3/res57/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:62:25 DELETE /m3/res58/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:63:24 PATCH /m3/res59/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:64:22 GET /m3/res60/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:65:23 POST /m3/res61/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:66:22 PUT /m3/res62/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:67:25 DELETE /m3/res63/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:68:24 PATCH /m3/res64/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:69:22 GET /m3/res65/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:6:21 PUT /m3/res2/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:70:23 POST /m3/res66/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:71:22 PUT /m3/res67/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:72:25 DELETE /m3/res68/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:73:24 PATCH /m3/res69/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:74:22 GET /m3/res70/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:75:23 POST /m3/res71/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:76:22 PUT /m3/res72/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:77:25 DELETE /m3/res73/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:78:24 PATCH /m3/res74/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:79:22 GET /m3/res75/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:7:24 DELETE /m3/res3/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:80:23 POST /m3/res76/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:81:22 PUT /m3/res77/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:82:25 DELETE /m3/res78/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:83:24 PATCH /m3/res79/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:84:22 GET /m3/res80/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:85:23 POST /m3/res81/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:86:22 PUT /m3/res82/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:87:25 DELETE /m3/res83/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:88:24 PATCH /m3/res84/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:89:22 GET /m3/res85/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:8:23 PATCH /m3/res4/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:90:23 POST /m3/res86/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:91:22 PUT /m3/res87/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:92:25 DELETE /m3/res88/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:93:24 PATCH /m3/res89/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:94:22 GET /m3/res90/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:95:23 POST /m3/res91/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:96:22 PUT /m3/res92/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:97:25 DELETE /m3/res93/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:98:24 PATCH /m3/res94/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:99:22 GET /m3/res95/:id index.ts:24:13 +regby mod3.ts:1:1 mod3.ts:9:21 GET /m3/res5/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:100:23 POST /m4/res96/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:101:22 PUT /m4/res97/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:102:25 DELETE /m4/res98/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:103:24 PATCH /m4/res99/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:10:22 POST /m4/res6/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:11:21 PUT /m4/res7/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:12:24 DELETE /m4/res8/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:13:23 PATCH /m4/res9/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:14:22 GET /m4/res10/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:15:23 POST /m4/res11/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:16:22 PUT /m4/res12/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:17:25 DELETE /m4/res13/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:18:24 PATCH /m4/res14/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:19:22 GET /m4/res15/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:20:23 POST /m4/res16/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:21:22 PUT /m4/res17/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:22:25 DELETE /m4/res18/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:23:24 PATCH /m4/res19/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:24:22 GET /m4/res20/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:25:23 POST /m4/res21/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:26:22 PUT /m4/res22/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:27:25 DELETE /m4/res23/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:28:24 PATCH /m4/res24/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:29:22 GET /m4/res25/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:30:23 POST /m4/res26/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:31:22 PUT /m4/res27/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:32:25 DELETE /m4/res28/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:33:24 PATCH /m4/res29/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:34:22 GET /m4/res30/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:35:23 POST /m4/res31/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:36:22 PUT /m4/res32/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:37:25 DELETE /m4/res33/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:38:24 PATCH /m4/res34/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:39:22 GET /m4/res35/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:40:23 POST /m4/res36/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:41:22 PUT /m4/res37/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:42:25 DELETE /m4/res38/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:43:24 PATCH /m4/res39/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:44:22 GET /m4/res40/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:45:23 POST /m4/res41/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:46:22 PUT /m4/res42/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:47:25 DELETE /m4/res43/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:48:24 PATCH /m4/res44/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:49:22 GET /m4/res45/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:4:21 GET /m4/res0/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:50:23 POST /m4/res46/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:51:22 PUT /m4/res47/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:52:25 DELETE /m4/res48/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:53:24 PATCH /m4/res49/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:54:22 GET /m4/res50/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:55:23 POST /m4/res51/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:56:22 PUT /m4/res52/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:57:25 DELETE /m4/res53/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:58:24 PATCH /m4/res54/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:59:22 GET /m4/res55/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:5:22 POST /m4/res1/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:60:23 POST /m4/res56/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:61:22 PUT /m4/res57/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:62:25 DELETE /m4/res58/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:63:24 PATCH /m4/res59/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:64:22 GET /m4/res60/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:65:23 POST /m4/res61/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:66:22 PUT /m4/res62/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:67:25 DELETE /m4/res63/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:68:24 PATCH /m4/res64/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:69:22 GET /m4/res65/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:6:21 PUT /m4/res2/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:70:23 POST /m4/res66/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:71:22 PUT /m4/res67/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:72:25 DELETE /m4/res68/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:73:24 PATCH /m4/res69/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:74:22 GET /m4/res70/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:75:23 POST /m4/res71/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:76:22 PUT /m4/res72/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:77:25 DELETE /m4/res73/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:78:24 PATCH /m4/res74/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:79:22 GET /m4/res75/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:7:24 DELETE /m4/res3/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:80:23 POST /m4/res76/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:81:22 PUT /m4/res77/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:82:25 DELETE /m4/res78/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:83:24 PATCH /m4/res79/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:84:22 GET /m4/res80/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:85:23 POST /m4/res81/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:86:22 PUT /m4/res82/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:87:25 DELETE /m4/res83/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:88:24 PATCH /m4/res84/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:89:22 GET /m4/res85/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:8:23 PATCH /m4/res4/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:90:23 POST /m4/res86/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:91:22 PUT /m4/res87/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:92:25 DELETE /m4/res88/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:93:24 PATCH /m4/res89/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:94:22 GET /m4/res90/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:95:23 POST /m4/res91/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:96:22 PUT /m4/res92/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:97:25 DELETE /m4/res93/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:98:24 PATCH /m4/res94/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:99:22 GET /m4/res95/:id index.ts:24:13 +regby mod4.ts:1:1 mod4.ts:9:21 GET /m4/res5/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:100:23 POST /m5/res96/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:101:22 PUT /m5/res97/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:102:25 DELETE /m5/res98/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:103:24 PATCH /m5/res99/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:10:22 POST /m5/res6/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:11:21 PUT /m5/res7/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:12:24 DELETE /m5/res8/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:13:23 PATCH /m5/res9/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:14:22 GET /m5/res10/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:15:23 POST /m5/res11/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:16:22 PUT /m5/res12/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:17:25 DELETE /m5/res13/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:18:24 PATCH /m5/res14/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:19:22 GET /m5/res15/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:20:23 POST /m5/res16/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:21:22 PUT /m5/res17/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:22:25 DELETE /m5/res18/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:23:24 PATCH /m5/res19/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:24:22 GET /m5/res20/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:25:23 POST /m5/res21/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:26:22 PUT /m5/res22/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:27:25 DELETE /m5/res23/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:28:24 PATCH /m5/res24/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:29:22 GET /m5/res25/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:30:23 POST /m5/res26/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:31:22 PUT /m5/res27/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:32:25 DELETE /m5/res28/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:33:24 PATCH /m5/res29/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:34:22 GET /m5/res30/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:35:23 POST /m5/res31/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:36:22 PUT /m5/res32/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:37:25 DELETE /m5/res33/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:38:24 PATCH /m5/res34/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:39:22 GET /m5/res35/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:40:23 POST /m5/res36/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:41:22 PUT /m5/res37/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:42:25 DELETE /m5/res38/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:43:24 PATCH /m5/res39/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:44:22 GET /m5/res40/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:45:23 POST /m5/res41/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:46:22 PUT /m5/res42/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:47:25 DELETE /m5/res43/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:48:24 PATCH /m5/res44/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:49:22 GET /m5/res45/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:4:21 GET /m5/res0/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:50:23 POST /m5/res46/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:51:22 PUT /m5/res47/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:52:25 DELETE /m5/res48/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:53:24 PATCH /m5/res49/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:54:22 GET /m5/res50/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:55:23 POST /m5/res51/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:56:22 PUT /m5/res52/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:57:25 DELETE /m5/res53/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:58:24 PATCH /m5/res54/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:59:22 GET /m5/res55/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:5:22 POST /m5/res1/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:60:23 POST /m5/res56/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:61:22 PUT /m5/res57/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:62:25 DELETE /m5/res58/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:63:24 PATCH /m5/res59/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:64:22 GET /m5/res60/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:65:23 POST /m5/res61/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:66:22 PUT /m5/res62/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:67:25 DELETE /m5/res63/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:68:24 PATCH /m5/res64/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:69:22 GET /m5/res65/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:6:21 PUT /m5/res2/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:70:23 POST /m5/res66/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:71:22 PUT /m5/res67/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:72:25 DELETE /m5/res68/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:73:24 PATCH /m5/res69/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:74:22 GET /m5/res70/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:75:23 POST /m5/res71/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:76:22 PUT /m5/res72/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:77:25 DELETE /m5/res73/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:78:24 PATCH /m5/res74/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:79:22 GET /m5/res75/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:7:24 DELETE /m5/res3/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:80:23 POST /m5/res76/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:81:22 PUT /m5/res77/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:82:25 DELETE /m5/res78/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:83:24 PATCH /m5/res79/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:84:22 GET /m5/res80/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:85:23 POST /m5/res81/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:86:22 PUT /m5/res82/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:87:25 DELETE /m5/res83/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:88:24 PATCH /m5/res84/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:89:22 GET /m5/res85/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:8:23 PATCH /m5/res4/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:90:23 POST /m5/res86/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:91:22 PUT /m5/res87/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:92:25 DELETE /m5/res88/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:93:24 PATCH /m5/res89/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:94:22 GET /m5/res90/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:95:23 POST /m5/res91/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:96:22 PUT /m5/res92/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:97:25 DELETE /m5/res93/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:98:24 PATCH /m5/res94/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:99:22 GET /m5/res95/:id index.ts:24:13 +regby mod5.ts:1:1 mod5.ts:9:21 GET /m5/res5/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:100:23 POST /m6/res96/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:101:22 PUT /m6/res97/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:102:25 DELETE /m6/res98/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:103:24 PATCH /m6/res99/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:10:22 POST /m6/res6/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:11:21 PUT /m6/res7/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:12:24 DELETE /m6/res8/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:13:23 PATCH /m6/res9/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:14:22 GET /m6/res10/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:15:23 POST /m6/res11/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:16:22 PUT /m6/res12/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:17:25 DELETE /m6/res13/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:18:24 PATCH /m6/res14/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:19:22 GET /m6/res15/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:20:23 POST /m6/res16/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:21:22 PUT /m6/res17/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:22:25 DELETE /m6/res18/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:23:24 PATCH /m6/res19/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:24:22 GET /m6/res20/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:25:23 POST /m6/res21/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:26:22 PUT /m6/res22/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:27:25 DELETE /m6/res23/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:28:24 PATCH /m6/res24/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:29:22 GET /m6/res25/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:30:23 POST /m6/res26/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:31:22 PUT /m6/res27/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:32:25 DELETE /m6/res28/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:33:24 PATCH /m6/res29/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:34:22 GET /m6/res30/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:35:23 POST /m6/res31/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:36:22 PUT /m6/res32/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:37:25 DELETE /m6/res33/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:38:24 PATCH /m6/res34/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:39:22 GET /m6/res35/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:40:23 POST /m6/res36/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:41:22 PUT /m6/res37/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:42:25 DELETE /m6/res38/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:43:24 PATCH /m6/res39/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:44:22 GET /m6/res40/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:45:23 POST /m6/res41/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:46:22 PUT /m6/res42/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:47:25 DELETE /m6/res43/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:48:24 PATCH /m6/res44/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:49:22 GET /m6/res45/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:4:21 GET /m6/res0/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:50:23 POST /m6/res46/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:51:22 PUT /m6/res47/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:52:25 DELETE /m6/res48/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:53:24 PATCH /m6/res49/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:54:22 GET /m6/res50/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:55:23 POST /m6/res51/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:56:22 PUT /m6/res52/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:57:25 DELETE /m6/res53/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:58:24 PATCH /m6/res54/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:59:22 GET /m6/res55/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:5:22 POST /m6/res1/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:60:23 POST /m6/res56/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:61:22 PUT /m6/res57/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:62:25 DELETE /m6/res58/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:63:24 PATCH /m6/res59/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:64:22 GET /m6/res60/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:65:23 POST /m6/res61/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:66:22 PUT /m6/res62/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:67:25 DELETE /m6/res63/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:68:24 PATCH /m6/res64/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:69:22 GET /m6/res65/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:6:21 PUT /m6/res2/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:70:23 POST /m6/res66/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:71:22 PUT /m6/res67/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:72:25 DELETE /m6/res68/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:73:24 PATCH /m6/res69/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:74:22 GET /m6/res70/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:75:23 POST /m6/res71/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:76:22 PUT /m6/res72/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:77:25 DELETE /m6/res73/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:78:24 PATCH /m6/res74/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:79:22 GET /m6/res75/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:7:24 DELETE /m6/res3/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:80:23 POST /m6/res76/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:81:22 PUT /m6/res77/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:82:25 DELETE /m6/res78/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:83:24 PATCH /m6/res79/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:84:22 GET /m6/res80/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:85:23 POST /m6/res81/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:86:22 PUT /m6/res82/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:87:25 DELETE /m6/res83/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:88:24 PATCH /m6/res84/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:89:22 GET /m6/res85/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:8:23 PATCH /m6/res4/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:90:23 POST /m6/res86/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:91:22 PUT /m6/res87/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:92:25 DELETE /m6/res88/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:93:24 PATCH /m6/res89/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:94:22 GET /m6/res90/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:95:23 POST /m6/res91/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:96:22 PUT /m6/res92/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:97:25 DELETE /m6/res93/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:98:24 PATCH /m6/res94/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:99:22 GET /m6/res95/:id index.ts:24:13 +regby mod6.ts:1:1 mod6.ts:9:21 GET /m6/res5/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:100:23 POST /m7/res96/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:101:22 PUT /m7/res97/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:102:25 DELETE /m7/res98/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:103:24 PATCH /m7/res99/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:10:22 POST /m7/res6/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:11:21 PUT /m7/res7/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:12:24 DELETE /m7/res8/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:13:23 PATCH /m7/res9/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:14:22 GET /m7/res10/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:15:23 POST /m7/res11/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:16:22 PUT /m7/res12/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:17:25 DELETE /m7/res13/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:18:24 PATCH /m7/res14/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:19:22 GET /m7/res15/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:20:23 POST /m7/res16/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:21:22 PUT /m7/res17/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:22:25 DELETE /m7/res18/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:23:24 PATCH /m7/res19/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:24:22 GET /m7/res20/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:25:23 POST /m7/res21/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:26:22 PUT /m7/res22/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:27:25 DELETE /m7/res23/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:28:24 PATCH /m7/res24/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:29:22 GET /m7/res25/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:30:23 POST /m7/res26/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:31:22 PUT /m7/res27/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:32:25 DELETE /m7/res28/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:33:24 PATCH /m7/res29/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:34:22 GET /m7/res30/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:35:23 POST /m7/res31/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:36:22 PUT /m7/res32/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:37:25 DELETE /m7/res33/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:38:24 PATCH /m7/res34/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:39:22 GET /m7/res35/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:40:23 POST /m7/res36/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:41:22 PUT /m7/res37/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:42:25 DELETE /m7/res38/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:43:24 PATCH /m7/res39/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:44:22 GET /m7/res40/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:45:23 POST /m7/res41/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:46:22 PUT /m7/res42/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:47:25 DELETE /m7/res43/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:48:24 PATCH /m7/res44/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:49:22 GET /m7/res45/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:4:21 GET /m7/res0/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:50:23 POST /m7/res46/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:51:22 PUT /m7/res47/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:52:25 DELETE /m7/res48/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:53:24 PATCH /m7/res49/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:54:22 GET /m7/res50/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:55:23 POST /m7/res51/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:56:22 PUT /m7/res52/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:57:25 DELETE /m7/res53/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:58:24 PATCH /m7/res54/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:59:22 GET /m7/res55/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:5:22 POST /m7/res1/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:60:23 POST /m7/res56/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:61:22 PUT /m7/res57/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:62:25 DELETE /m7/res58/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:63:24 PATCH /m7/res59/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:64:22 GET /m7/res60/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:65:23 POST /m7/res61/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:66:22 PUT /m7/res62/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:67:25 DELETE /m7/res63/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:68:24 PATCH /m7/res64/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:69:22 GET /m7/res65/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:6:21 PUT /m7/res2/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:70:23 POST /m7/res66/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:71:22 PUT /m7/res67/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:72:25 DELETE /m7/res68/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:73:24 PATCH /m7/res69/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:74:22 GET /m7/res70/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:75:23 POST /m7/res71/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:76:22 PUT /m7/res72/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:77:25 DELETE /m7/res73/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:78:24 PATCH /m7/res74/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:79:22 GET /m7/res75/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:7:24 DELETE /m7/res3/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:80:23 POST /m7/res76/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:81:22 PUT /m7/res77/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:82:25 DELETE /m7/res78/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:83:24 PATCH /m7/res79/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:84:22 GET /m7/res80/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:85:23 POST /m7/res81/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:86:22 PUT /m7/res82/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:87:25 DELETE /m7/res83/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:88:24 PATCH /m7/res84/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:89:22 GET /m7/res85/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:8:23 PATCH /m7/res4/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:90:23 POST /m7/res86/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:91:22 PUT /m7/res87/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:92:25 DELETE /m7/res88/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:93:24 PATCH /m7/res89/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:94:22 GET /m7/res90/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:95:23 POST /m7/res91/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:96:22 PUT /m7/res92/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:97:25 DELETE /m7/res93/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:98:24 PATCH /m7/res94/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:99:22 GET /m7/res95/:id index.ts:24:13 +regby mod7.ts:1:1 mod7.ts:9:21 GET /m7/res5/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:100:23 POST /m8/res96/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:101:22 PUT /m8/res97/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:102:25 DELETE /m8/res98/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:103:24 PATCH /m8/res99/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:10:22 POST /m8/res6/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:11:21 PUT /m8/res7/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:12:24 DELETE /m8/res8/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:13:23 PATCH /m8/res9/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:14:22 GET /m8/res10/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:15:23 POST /m8/res11/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:16:22 PUT /m8/res12/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:17:25 DELETE /m8/res13/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:18:24 PATCH /m8/res14/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:19:22 GET /m8/res15/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:20:23 POST /m8/res16/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:21:22 PUT /m8/res17/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:22:25 DELETE /m8/res18/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:23:24 PATCH /m8/res19/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:24:22 GET /m8/res20/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:25:23 POST /m8/res21/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:26:22 PUT /m8/res22/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:27:25 DELETE /m8/res23/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:28:24 PATCH /m8/res24/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:29:22 GET /m8/res25/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:30:23 POST /m8/res26/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:31:22 PUT /m8/res27/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:32:25 DELETE /m8/res28/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:33:24 PATCH /m8/res29/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:34:22 GET /m8/res30/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:35:23 POST /m8/res31/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:36:22 PUT /m8/res32/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:37:25 DELETE /m8/res33/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:38:24 PATCH /m8/res34/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:39:22 GET /m8/res35/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:40:23 POST /m8/res36/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:41:22 PUT /m8/res37/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:42:25 DELETE /m8/res38/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:43:24 PATCH /m8/res39/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:44:22 GET /m8/res40/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:45:23 POST /m8/res41/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:46:22 PUT /m8/res42/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:47:25 DELETE /m8/res43/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:48:24 PATCH /m8/res44/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:49:22 GET /m8/res45/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:4:21 GET /m8/res0/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:50:23 POST /m8/res46/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:51:22 PUT /m8/res47/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:52:25 DELETE /m8/res48/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:53:24 PATCH /m8/res49/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:54:22 GET /m8/res50/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:55:23 POST /m8/res51/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:56:22 PUT /m8/res52/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:57:25 DELETE /m8/res53/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:58:24 PATCH /m8/res54/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:59:22 GET /m8/res55/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:5:22 POST /m8/res1/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:60:23 POST /m8/res56/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:61:22 PUT /m8/res57/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:62:25 DELETE /m8/res58/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:63:24 PATCH /m8/res59/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:64:22 GET /m8/res60/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:65:23 POST /m8/res61/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:66:22 PUT /m8/res62/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:67:25 DELETE /m8/res63/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:68:24 PATCH /m8/res64/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:69:22 GET /m8/res65/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:6:21 PUT /m8/res2/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:70:23 POST /m8/res66/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:71:22 PUT /m8/res67/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:72:25 DELETE /m8/res68/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:73:24 PATCH /m8/res69/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:74:22 GET /m8/res70/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:75:23 POST /m8/res71/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:76:22 PUT /m8/res72/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:77:25 DELETE /m8/res73/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:78:24 PATCH /m8/res74/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:79:22 GET /m8/res75/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:7:24 DELETE /m8/res3/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:80:23 POST /m8/res76/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:81:22 PUT /m8/res77/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:82:25 DELETE /m8/res78/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:83:24 PATCH /m8/res79/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:84:22 GET /m8/res80/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:85:23 POST /m8/res81/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:86:22 PUT /m8/res82/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:87:25 DELETE /m8/res83/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:88:24 PATCH /m8/res84/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:89:22 GET /m8/res85/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:8:23 PATCH /m8/res4/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:90:23 POST /m8/res86/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:91:22 PUT /m8/res87/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:92:25 DELETE /m8/res88/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:93:24 PATCH /m8/res89/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:94:22 GET /m8/res90/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:95:23 POST /m8/res91/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:96:22 PUT /m8/res92/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:97:25 DELETE /m8/res93/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:98:24 PATCH /m8/res94/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:99:22 GET /m8/res95/:id index.ts:24:13 +regby mod8.ts:1:1 mod8.ts:9:21 GET /m8/res5/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:100:23 POST /m9/res96/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:101:22 PUT /m9/res97/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:102:25 DELETE /m9/res98/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:103:24 PATCH /m9/res99/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:10:22 POST /m9/res6/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:11:21 PUT /m9/res7/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:12:24 DELETE /m9/res8/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:13:23 PATCH /m9/res9/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:14:22 GET /m9/res10/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:15:23 POST /m9/res11/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:16:22 PUT /m9/res12/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:17:25 DELETE /m9/res13/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:18:24 PATCH /m9/res14/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:19:22 GET /m9/res15/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:20:23 POST /m9/res16/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:21:22 PUT /m9/res17/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:22:25 DELETE /m9/res18/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:23:24 PATCH /m9/res19/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:24:22 GET /m9/res20/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:25:23 POST /m9/res21/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:26:22 PUT /m9/res22/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:27:25 DELETE /m9/res23/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:28:24 PATCH /m9/res24/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:29:22 GET /m9/res25/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:30:23 POST /m9/res26/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:31:22 PUT /m9/res27/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:32:25 DELETE /m9/res28/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:33:24 PATCH /m9/res29/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:34:22 GET /m9/res30/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:35:23 POST /m9/res31/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:36:22 PUT /m9/res32/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:37:25 DELETE /m9/res33/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:38:24 PATCH /m9/res34/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:39:22 GET /m9/res35/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:40:23 POST /m9/res36/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:41:22 PUT /m9/res37/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:42:25 DELETE /m9/res38/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:43:24 PATCH /m9/res39/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:44:22 GET /m9/res40/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:45:23 POST /m9/res41/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:46:22 PUT /m9/res42/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:47:25 DELETE /m9/res43/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:48:24 PATCH /m9/res44/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:49:22 GET /m9/res45/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:4:21 GET /m9/res0/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:50:23 POST /m9/res46/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:51:22 PUT /m9/res47/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:52:25 DELETE /m9/res48/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:53:24 PATCH /m9/res49/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:54:22 GET /m9/res50/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:55:23 POST /m9/res51/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:56:22 PUT /m9/res52/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:57:25 DELETE /m9/res53/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:58:24 PATCH /m9/res54/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:59:22 GET /m9/res55/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:5:22 POST /m9/res1/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:60:23 POST /m9/res56/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:61:22 PUT /m9/res57/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:62:25 DELETE /m9/res58/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:63:24 PATCH /m9/res59/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:64:22 GET /m9/res60/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:65:23 POST /m9/res61/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:66:22 PUT /m9/res62/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:67:25 DELETE /m9/res63/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:68:24 PATCH /m9/res64/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:69:22 GET /m9/res65/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:6:21 PUT /m9/res2/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:70:23 POST /m9/res66/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:71:22 PUT /m9/res67/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:72:25 DELETE /m9/res68/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:73:24 PATCH /m9/res69/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:74:22 GET /m9/res70/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:75:23 POST /m9/res71/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:76:22 PUT /m9/res72/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:77:25 DELETE /m9/res73/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:78:24 PATCH /m9/res74/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:79:22 GET /m9/res75/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:7:24 DELETE /m9/res3/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:80:23 POST /m9/res76/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:81:22 PUT /m9/res77/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:82:25 DELETE /m9/res78/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:83:24 PATCH /m9/res79/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:84:22 GET /m9/res80/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:85:23 POST /m9/res81/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:86:22 PUT /m9/res82/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:87:25 DELETE /m9/res83/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:88:24 PATCH /m9/res84/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:89:22 GET /m9/res85/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:8:23 PATCH /m9/res4/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:90:23 POST /m9/res86/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:91:22 PUT /m9/res87/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:92:25 DELETE /m9/res88/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:93:24 PATCH /m9/res89/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:94:22 GET /m9/res90/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:95:23 POST /m9/res91/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:96:22 PUT /m9/res92/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:97:25 DELETE /m9/res93/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:98:24 PATCH /m9/res94/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:99:22 GET /m9/res95/:id index.ts:24:13 +regby mod9.ts:1:1 mod9.ts:9:21 GET /m9/res5/:id index.ts:24:13 diff --git a/graph/test/typescript/hono/expected/zod/composition.entries b/graph/test/typescript/hono/expected/zod/composition.entries new file mode 100644 index 000000000..a0aa82659 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/composition.entries @@ -0,0 +1,9 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: each derived schema plus Base (and Extra for merge); .openapi('Person') keeps the same schema with Base as base +# census: zvalidator (SPEC 3.9 composition) +entry index.ts:19:53 http +entry index.ts:20:49 http +entry index.ts:21:49 http +entry index.ts:22:51 http +entry index.ts:23:52 http +entry index.ts:24:44 http +entry index.ts:25:47 http diff --git a/graph/test/typescript/hono/expected/zod/composition.tsv b/graph/test/typescript/hono/expected/zod/composition.tsv new file mode 100644 index 000000000..648a316d8 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/composition.tsv @@ -0,0 +1,47 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: each derived schema plus Base (and Extra for merge); .openapi('Person') keeps the same schema with Base as base +# census: zvalidator (SPEC 3.9 composition) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /extended index.ts:19:53 index.ts:18:13 1 +route POST /merged index.ts:20:49 index.ts:18:13 3 +route POST /picked index.ts:21:49 index.ts:18:13 5 +route POST /omitted index.ts:22:51 index.ts:18:13 7 +route PATCH /partial index.ts:23:52 index.ts:18:13 9 +route PUT /many index.ts:24:44 index.ts:18:13 11 +route POST /named index.ts:25:47 index.ts:18:13 13 +mw lib:@hono/zod-validator.zValidator@index.ts:19:23 index.ts:19:53 POST /extended 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:20:21 index.ts:20:49 POST /merged 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:21:21 index.ts:21:49 POST /picked 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:22:22 index.ts:22:51 POST /omitted 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:23:23 index.ts:23:52 PATCH /partial 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:24:18 index.ts:24:44 PUT /many 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:25:20 index.ts:25:47 POST /named 0 index.ts:18:13 +schema index.ts:19:53 json index.ts:10:7 +schema index.ts:19:53 json index.ts:8:7 +schema index.ts:20:49 json index.ts:11:7 +schema index.ts:20:49 json index.ts:8:7 +schema index.ts:20:49 json index.ts:9:7 +schema index.ts:21:49 json index.ts:12:7 +schema index.ts:21:49 json index.ts:8:7 +schema index.ts:22:51 json index.ts:13:7 +schema index.ts:22:51 json index.ts:8:7 +schema index.ts:23:52 json index.ts:14:7 +schema index.ts:23:52 json index.ts:8:7 +schema index.ts:24:44 json index.ts:15:7 +schema index.ts:24:44 json index.ts:8:7 +schema index.ts:25:47 json index.ts:16:7 +schema index.ts:25:47 json index.ts:8:7 +validread index.ts:19:67 index.ts:19:53 json index.ts:10:7 +validread index.ts:20:63 index.ts:20:49 json index.ts:11:7 +validread index.ts:21:63 index.ts:21:49 json index.ts:12:7 +validread index.ts:22:65 index.ts:22:51 json index.ts:13:7 +validread index.ts:23:66 index.ts:23:52 json index.ts:14:7 +validread index.ts:24:58 index.ts:24:44 json index.ts:15:7 +validread index.ts:25:61 index.ts:25:47 json index.ts:16:7 +regby index.ts:1:1 index.ts:19:53 POST /extended index.ts:18:13 +regby index.ts:1:1 index.ts:20:49 POST /merged index.ts:18:13 +regby index.ts:1:1 index.ts:21:49 POST /picked index.ts:18:13 +regby index.ts:1:1 index.ts:22:51 POST /omitted index.ts:18:13 +regby index.ts:1:1 index.ts:23:52 PATCH /partial index.ts:18:13 +regby index.ts:1:1 index.ts:24:44 PUT /many index.ts:18:13 +regby index.ts:1:1 index.ts:25:47 POST /named index.ts:18:13 diff --git a/graph/test/typescript/hono/expected/zod/decl-forms.entries b/graph/test/typescript/hono/expected/zod/decl-forms.entries new file mode 100644 index 000000000..aedb74df0 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/decl-forms.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: inline (expression), local, named, default, namespace member and barrel re-export each resolve to the declaration +# census: zvalidator, req_valid (SPEC 3.9 declaration forms) +entry index.ts:14:70 http +entry index.ts:15:47 http +entry index.ts:16:46 http +entry index.ts:17:52 http +entry index.ts:18:54 http +entry index.ts:19:53 http diff --git a/graph/test/typescript/hono/expected/zod/decl-forms.tsv b/graph/test/typescript/hono/expected/zod/decl-forms.tsv new file mode 100644 index 000000000..1af3dc2db --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/decl-forms.tsv @@ -0,0 +1,34 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: inline (expression), local, named, default, namespace member and barrel re-export each resolve to the declaration +# census: zvalidator, req_valid (SPEC 3.9 declaration forms) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /inline index.ts:14:70 index.ts:13:13 1 +route POST /local index.ts:15:47 index.ts:13:13 3 +route POST /named index.ts:16:46 index.ts:13:13 5 +route POST /default index.ts:17:52 index.ts:13:13 7 +route GET /namespace index.ts:18:54 index.ts:13:13 9 +route POST /barrel index.ts:19:53 index.ts:13:13 11 +mw lib:@hono/zod-validator.zValidator@index.ts:14:21 index.ts:14:70 POST /inline 0 index.ts:13:13 +mw lib:@hono/zod-validator.zValidator@index.ts:15:20 index.ts:15:47 POST /local 0 index.ts:13:13 +mw lib:@hono/zod-validator.zValidator@index.ts:16:20 index.ts:16:46 POST /named 0 index.ts:13:13 +mw lib:@hono/zod-validator.zValidator@index.ts:17:22 index.ts:17:52 POST /default 0 index.ts:13:13 +mw lib:@hono/zod-validator.zValidator@index.ts:18:23 index.ts:18:54 GET /namespace 0 index.ts:13:13 +mw lib:@hono/zod-validator.zValidator@index.ts:19:21 index.ts:19:53 POST /barrel 0 index.ts:13:13 +schema index.ts:14:70 json expr@index.ts:14:40 +schema index.ts:15:47 json index.ts:11:7 +schema index.ts:16:46 json schemas/user.ts:3:14 +schema index.ts:17:52 json schemas/user.ts:5:7 +schema index.ts:18:54 query schemas/query.ts:3:14 +schema index.ts:19:53 json schemas/user.ts:3:14 +validread index.ts:14:84 index.ts:14:70 json expr@index.ts:14:40 +validread index.ts:15:61 index.ts:15:47 json index.ts:11:7 +validread index.ts:16:60 index.ts:16:46 json schemas/user.ts:3:14 +validread index.ts:17:66 index.ts:17:52 json schemas/user.ts:5:7 +validread index.ts:18:68 index.ts:18:54 query schemas/query.ts:3:14 +validread index.ts:19:67 index.ts:19:53 json schemas/user.ts:3:14 +regby index.ts:1:1 index.ts:14:70 POST /inline index.ts:13:13 +regby index.ts:1:1 index.ts:15:47 POST /local index.ts:13:13 +regby index.ts:1:1 index.ts:16:46 POST /named index.ts:13:13 +regby index.ts:1:1 index.ts:17:52 POST /default index.ts:13:13 +regby index.ts:1:1 index.ts:18:54 GET /namespace index.ts:13:13 +regby index.ts:1:1 index.ts:19:53 POST /barrel index.ts:13:13 diff --git a/graph/test/typescript/hono/expected/zod/no-route.entries b/graph/test/typescript/hono/expected/zod/no-route.entries new file mode 100644 index 000000000..4bd1b866e --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/no-route.entries @@ -0,0 +1,2 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: zod with no Hono app: zero rows; route table and route_schema must still be exported +# census: zvalidator (negative partition: zod with no Hono route, SPEC 3.9) diff --git a/graph/test/typescript/hono/expected/zod/no-route.tsv b/graph/test/typescript/hono/expected/zod/no-route.tsv new file mode 100644 index 000000000..a478d1df3 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/no-route.tsv @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: zod with no Hono app: zero rows; route table and route_schema must still be exported +# census: zvalidator (negative partition: zod with no Hono route, SPEC 3.9) +absent forms.ts:7:1 +absent forms.ts:12:1 diff --git a/graph/test/typescript/hono/expected/zod/specifiers.entries b/graph/test/typescript/hono/expected/zod/specifiers.entries new file mode 100644 index 000000000..d322a7fc0 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/specifiers.entries @@ -0,0 +1,8 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: z from zod, zod/v4, zod/v3, zod/v4-mini and @hono/zod-openapi: each route's json schema is its const; a validator(fn) route has no schema row +# census: zvalidator, req_valid (SPEC 3.9 import forms: zod, zod/v4, zod/v3, zod/v4-mini, @hono/zod-openapi's z) +entry index.ts:19:47 http +entry index.ts:20:45 http +entry index.ts:21:45 http +entry index.ts:22:49 http +entry index.ts:23:66 http +entry index.ts:24:57 http diff --git a/graph/test/typescript/hono/expected/zod/specifiers.tsv b/graph/test/typescript/hono/expected/zod/specifiers.tsv new file mode 100644 index 000000000..cde130fec --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/specifiers.tsv @@ -0,0 +1,32 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: z from zod, zod/v4, zod/v3, zod/v4-mini and @hono/zod-openapi: each route's json schema is its const; a validator(fn) route has no schema row +# census: zvalidator, req_valid (SPEC 3.9 import forms: zod, zod/v4, zod/v3, zod/v4-mini, @hono/zod-openapi's z) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /zod index.ts:19:47 index.ts:18:13 1 +route POST /v4 index.ts:20:45 index.ts:18:13 3 +route POST /v3 index.ts:21:45 index.ts:18:13 5 +route POST /mini index.ts:22:49 index.ts:18:13 7 +route POST /fn index.ts:23:66 index.ts:18:13 9 +route POST /openapi-z index.ts:24:57 index.ts:18:13 11 +mw lib:@hono/zod-validator.zValidator@index.ts:19:18 index.ts:19:47 POST /zod 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:20:17 index.ts:20:45 POST /v4 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:21:17 index.ts:21:45 POST /v3 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:22:19 index.ts:22:49 POST /mini 0 index.ts:18:13 +mw lib:hono/validator.validator@index.ts:23:17 index.ts:23:66 POST /fn 0 index.ts:18:13 +mw lib:@hono/zod-validator.zValidator@index.ts:24:24 index.ts:24:57 POST /openapi-z 0 index.ts:18:13 +schema index.ts:19:47 json index.ts:12:7 +schema index.ts:20:45 json index.ts:13:7 +schema index.ts:21:45 json index.ts:14:7 +schema index.ts:22:49 json index.ts:15:7 +schema index.ts:24:57 json index.ts:16:7 +validread index.ts:19:61 index.ts:19:47 json index.ts:12:7 +validread index.ts:20:59 index.ts:20:45 json index.ts:13:7 +validread index.ts:21:59 index.ts:21:45 json index.ts:14:7 +validread index.ts:22:63 index.ts:22:49 json index.ts:15:7 +validread index.ts:24:71 index.ts:24:57 json index.ts:16:7 +regby index.ts:1:1 index.ts:19:47 POST /zod index.ts:18:13 +regby index.ts:1:1 index.ts:20:45 POST /v4 index.ts:18:13 +regby index.ts:1:1 index.ts:21:45 POST /v3 index.ts:18:13 +regby index.ts:1:1 index.ts:22:49 POST /mini index.ts:18:13 +regby index.ts:1:1 index.ts:23:66 POST /fn index.ts:18:13 +regby index.ts:1:1 index.ts:24:57 POST /openapi-z index.ts:18:13 diff --git a/graph/test/typescript/hono/expected/zod/valid-targets.entries b/graph/test/typescript/hono/expected/zod/valid-targets.entries new file mode 100644 index 000000000..2c7d29e32 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/valid-targets.entries @@ -0,0 +1,4 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: six targets each read and linked; valid('json') on /missing is valid_without_validator +# census: req_valid, zvalidator, validator_builtin (SPEC 3.9 targets) +entry index.ts:24:3 http +entry index.ts:29:45 http diff --git a/graph/test/typescript/hono/expected/zod/valid-targets.tsv b/graph/test/typescript/hono/expected/zod/valid-targets.tsv new file mode 100644 index 000000000..c5182b7c7 --- /dev/null +++ b/graph/test/typescript/hono/expected/zod/valid-targets.tsv @@ -0,0 +1,30 @@ +# hand-reviewed 2026-10-24 against the fixture and the oracle: six targets each read and linked; valid('json') on /missing is valid_without_validator +# census: req_valid, zvalidator, validator_builtin (SPEC 3.9 targets) +# iteration 2: mw rows carry the served root app (SPEC R3), re-derived; every other row unchanged +# iteration 2: regby rows (route_registered_by, SPEC 4) re-derived; every other row unchanged +route POST /all/:id index.ts:24:3 index.ts:15:13 6 +route GET /missing index.ts:29:45 index.ts:15:13 8 +mw lib:@hono/zod-validator.zValidator@index.ts:18:3 index.ts:24:3 POST /all/:id 0 index.ts:15:13 +mw lib:@hono/zod-validator.zValidator@index.ts:19:3 index.ts:24:3 POST /all/:id 1 index.ts:15:13 +mw lib:@hono/zod-validator.zValidator@index.ts:20:3 index.ts:24:3 POST /all/:id 2 index.ts:15:13 +mw lib:@hono/zod-validator.zValidator@index.ts:21:3 index.ts:24:3 POST /all/:id 3 index.ts:15:13 +mw lib:@hono/zod-validator.zValidator@index.ts:22:3 index.ts:24:3 POST /all/:id 4 index.ts:15:13 +mw lib:@hono/zod-validator.zValidator@index.ts:23:3 index.ts:24:3 POST /all/:id 5 index.ts:15:13 +mw lib:@hono/zod-validator.zValidator@index.ts:29:21 index.ts:29:45 GET /missing 0 index.ts:15:13 +schema index.ts:24:3 cookie index.ts:13:7 +schema index.ts:24:3 form index.ts:11:7 +schema index.ts:24:3 header index.ts:12:7 +schema index.ts:24:3 json index.ts:8:7 +schema index.ts:24:3 param index.ts:10:7 +schema index.ts:24:3 query index.ts:9:7 +schema index.ts:29:45 query index.ts:9:7 +validread index.ts:25:104 index.ts:24:3 header index.ts:12:7 +validread index.ts:25:127 index.ts:24:3 cookie index.ts:13:7 +validread index.ts:25:18 index.ts:24:3 json index.ts:8:7 +validread index.ts:25:39 index.ts:24:3 query index.ts:9:7 +validread index.ts:25:61 index.ts:24:3 param index.ts:10:7 +validread index.ts:25:83 index.ts:24:3 form index.ts:11:7 +validread index.ts:32:18 index.ts:29:45 query index.ts:9:7 +regby index.ts:1:1 index.ts:24:3 POST /all/:id index.ts:15:13 +regby index.ts:1:1 index.ts:29:45 GET /missing index.ts:15:13 +unknown index.ts:31:16 valid_without_validator index.ts:29:45 diff --git a/graph/test/typescript/hono/relations.tsv b/graph/test/typescript/hono/relations.tsv new file mode 100644 index 000000000..628b62c83 --- /dev/null +++ b/graph/test/typescript/hono/relations.tsv @@ -0,0 +1,22 @@ +# projection engine relation (export_manifest.tsv name) column=index ... +# The ONE place the suite names the engine's relations and their columns: SPEC.md section 4. +# A projection fed by several relations lists one line per relation (rows are unioned). +route http_route handler=0 verb=1 path=2 app=3 order=4 +partial http_route_partial handler=0 verb=1 path=2 app=3 reason=4 +submount http_mount parent=0 child=1 prefix=2 order=3 +mw middleware_applies mw=0 handler=1 verb=2 path=3 position=4 app=5 +ctx ctx_key_flow setter=0 reader=1 key=2 +remote remote_edge from=0 to=1 transport=2 dest=3 conf=4 +unserved remote_unserved fn=0 transport=1 dest=2 +entry entry_point fn=0 kind=1 +unknown remote_undetermined fn=0 transport=1 reason=2 +unknown framework_undetermined fn=0 what=1 reason=2 +schema route_schema handler=0 target=1 decl=2 +validread valid_read read=0 handler=1 target=2 decl=3 +regby route_registered_by regmethod=0 handler=1 verb=2 path=3 app=4 +# chains/ suite (SPEC R18-R21): call edges, the dispatch widening of a declared base, function-value calls, and the +# functions holding a call the engine declares unresolved (compare_chains in tools/hono_compare.py) +chainedge call_chain_edge from=1 to=3 prov=4 +dispatch method_dispatch_candidate base=0 impl=1 +fnvalue fn_value_call from=0 to=1 +ccunknown method_has_unknown_call fn=0 diff --git a/graph/test/typescript/hono/run-tests.sh b/graph/test/typescript/hono/run-tests.sh new file mode 100755 index 000000000..32cdb2aa8 --- /dev/null +++ b/graph/test/typescript/hono/run-tests.sh @@ -0,0 +1,230 @@ +#!/usr/bin/env bash +# ───────────────────────────────────────────────────────────────────────────── +# axiom-code-graph: Hono torture suites (TypeScript; the JavaScript twin sources this runner) +# +# For every case cases///src: +# 1. the expected truth must exist and say it was REVIEWED: expected//.tsv and +# expected//.entries, each starting `# hand-reviewed`. A missing or unreviewed +# golden FAILS: it never skips. +# 2. with --oracle: the independent oracle (truth/, the TypeScript compiler API plus the real +# pinned `hono`) must reproduce the expected rows exactly, and its runtime half (the fixture +# run under the real Hono, `app.routes` read back) must agree with the static half wherever +# the fixture loads. A refusal or a disagreement FAILS. +# 3. the engine runs TWICE: `bare` (no library: a real checkout without node_modules) and `lib` +# (the pinned hono type declarations staged as a library). Each variant's Hono relations are +# normalised and compared row by row (tools/hono_compare.py). Until the engine exports the +# relations SPEC.md section 4 names, the case FAILS with "relation not exported". +# 4. at least ONE row is compared, or the case fails: an empty golden is not a pass. +# +# ./run-tests.sh [filter...] cases whose / contains a filter +# ./run-tests.sh --oracle also check expected/ against the oracle (needs truth/node_modules: npm install there) +# ./run-tests.sh --oracle-only only step 2 (no parser, no solver): validates the goldens +# ./run-tests.sh --draft write the oracle's rows to expected/*.draft for REVIEW (never to the golden) +# ./run-tests.sh --keep keep .work/ +# +# cases///partial-paths (opt-in): the oracle also prints, and the compare also checks, `ppath HANDLER +# VERB KNOWNPATH` rows: a partial route's composed path with `{}` for the run-time piece (http_route_partial KnownPath). +# +# expected//.known-missing: `\t` per line (the row as the +# compare prints it after MISSING). A new miss fails; a listed miss that starts passing fails. +# +# Environment: AXIOM_PARSER (default parser/dist/index.js), HONO_ENGINE_ROOT (score another checkout's engine), +# HONO_LANG (typescript|javascript), +# HONO_SUITE_DIR (the suite dir holding cases/ and expected/; default: this dir) +# ───────────────────────────────────────────────────────────────────────────── +set -uo pipefail +TS_HONO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +HERE="${HONO_SUITE_DIR:-$TS_HONO}" +LANG_="${HONO_LANG:-typescript}" +ROOT="$TS_HONO"; while [ "$ROOT" != / ] && { [ ! -f "$ROOT/package.json" ] || [ ! -d "$ROOT/graph" ]; }; do ROOT="$(dirname "$ROOT")"; done +# HONO_ENGINE_ROOT: score ANOTHER checkout's parser and engine (e.g. the implementation branch's worktree) +# with this checkout's cases, goldens and oracle +ENGINE_ROOT="${HONO_ENGINE_ROOT:-$ROOT}" +PARSER="${AXIOM_PARSER:-$ENGINE_ROOT/parser/dist/index.js}" +# the baseline engine (pre-Hono): HONO_BASELINE_ROOT, else a wt-hono-baseline sibling of this checkout, else this tree +BASELINE_ROOT="${HONO_BASELINE_ROOT:-}" +if [ -z "$BASELINE_ROOT" ]; then + for cand in "$(cd "$ROOT/.." && pwd)/wt-hono-baseline"; do + [ -f "$cand/graph/pipeline/run-souffle.sh" ] && { BASELINE_ROOT="$cand"; break; } + done + [ -n "$BASELINE_ROOT" ] || BASELINE_ROOT="$ROOT" +fi +echo "baseline engine for pre-existing entry points: $BASELINE_ROOT" +ORACLE_DIR="$TS_HONO/truth" # NOT `oracle/`: the repository .gitignore ignores every dir of that name +WORK="$HERE/.work" +ORACLE=0; ORACLE_ONLY=0; DRAFT=0; KEEP=0; FILTERS=() +for a in "$@"; do case "$a" in + --oracle) ORACLE=1;; --oracle-only) ORACLE=1; ORACLE_ONLY=1;; --draft) ORACLE=1; ORACLE_ONLY=1; DRAFT=1;; + --keep) KEEP=1;; -h|--help) sed -n '2,30p' "$0"; exit 0;; *) FILTERS+=("$a");; esac; done + +if [ "$ORACLE" = 1 ] && [ ! -d "$ORACLE_DIR/node_modules/hono" ]; then + echo "FAIL: the oracle is not installed: (cd $ORACLE_DIR && npm install): refusing to score without it"; exit 1 +fi +[ "$ORACLE_ONLY" = 1 ] || [ -f "$PARSER" ] || { echo "FAIL: parser not found at $PARSER (build it: npm install)"; exit 1; } +MANIFEST="$ENGINE_ROOT/graph/$LANG_/souffle/export_manifest.tsv" +mkdir -p "$WORK" +EMPTY_LIB="$WORK/.empty-library"; mkdir -p "$EMPTY_LIB" + +# the `lib` variant's library: the pinned packages' TYPE declarations, parsed once per run +LIBIR="$WORK/.hono-lib-ir" +stage_lib() { + [ -s "$LIBIR/all-typescript-modules.csv" ] && return 0 + local src="$WORK/.hono-lib-src" p + rm -rf "$src" "$LIBIR"; mkdir -p "$src" "$LIBIR" + [ -d "$ORACLE_DIR/node_modules/hono" ] || { echo " (lib variant needs truth/node_modules: npm install there)"; return 1; } + for p in hono @hono/zod-openapi @hono/zod-validator @hono/node-server; do + local d="$ORACLE_DIR/node_modules/$p"; [ -d "$d" ] || continue + mkdir -p "$src/$p"; cp "$d/package.json" "$src/$p/" + if [ -d "$d/dist/types" ]; then cp -R "$d/dist/types/." "$src/$p/" + else (cd "$d/dist" && find . -name '*.d.ts' -o -name '*.d.mts' | while read -r f; do mkdir -p "$src/$p/$(dirname "$f")"; cp "$f" "$src/$p/$f"; done); fi + done + node "$PARSER" "$src" "hono-lib" false "$LIBIR" >"$WORK/.hono-lib.log" 2>&1 + [ -s "$LIBIR/all-typescript-modules.csv" ] +} + +solve() { # ir lib out (writes $3/rss_kb: the peak resident set of the solve, from /usr/bin/time -l) + local rc + if [ -x /usr/bin/time ]; then + /usr/bin/time -l bash "$ENGINE_ROOT/graph/pipeline/run-souffle.sh" --debug --language "$LANG_" \ + --client-ir "$1" --library "$2" --intermediate "$3/int" --output "$3/out" >"$3/solve.log" 2>"$3/solve.err"; rc=$? + cat "$3/solve.err" >>"$3/solve.log" + # macOS reports bytes, GNU time kilobytes: normalise to KB + awk -v div="$([ "$(uname)" = Darwin ] && echo 1024 || echo 1)" '/maximum resident set size/{b=$1} END{if(b!="") print int(b/div)}' "$3/solve.err" >"$3/rss_kb" + return $rc + fi + bash "$ENGINE_ROOT/graph/pipeline/run-souffle.sh" --debug --language "$LANG_" \ + --client-ir "$1" --library "$2" --intermediate "$3/int" --output "$3/out" >"$3/solve.log" 2>&1 +} + +rows_of() { grep -v '^#' "$1" | grep -v '^absent' | grep -v '^$' | sort; } + +pass=0; fail=0; failed=(); notexported=0 +for dir in "$HERE"/cases/*/*/; do + dir="${dir%/}"; suite="$(basename "$(dirname "$dir")")"; name="$(basename "$dir")"; id="$suite/$name" + if [ ${#FILTERS[@]} -gt 0 ]; then + m=0; for f in "${FILTERS[@]}"; do [[ "$id" == *"$f"* ]] && m=1; done; [ $m = 1 ] || continue + fi + printf '%-44s ' "$id" + exp="$HERE/expected/$suite/$name.tsv"; ent="$HERE/expected/$suite/$name.entries"; km="$HERE/expected/$suite/$name.known-missing" + # chains/ (SPEC R18-R21): a third golden of whole call chains, checked against the compiler oracle and the runtime trace + chf="$HERE/expected/$suite/$name.chains"; chargs=() + w="$WORK/$suite/$name"; rm -rf "$w"; mkdir -p "$w" + # a `partial-paths` file opts the case into `ppath` rows: the known path of each partial route (hono-7-05) + oflags=(); [ -f "$dir/partial-paths" ] && oflags=(--partial-paths) + ok=1; notes="" + + if [ "$DRAFT" = 1 ]; then + mkdir -p "$(dirname "$exp")" + if node "$ORACLE_DIR/hono-oracle.mjs" "$dir/src" --stores ${oflags[@]+"${oflags[@]}"} >"$w/oracle.full" 2>"$w/oracle.log"; then + rt="$(node "$ORACLE_DIR/runtime-check.mjs" "$dir/src" "$w/oracle.full" 2>&1 | head -6)" + grep -v '^store' "$w/oracle.full" | grep -v '^entry' >"$exp.draft" + grep '^entry' "$w/oracle.full" >"$ent.draft" + if [ "$suite" = chains ]; then + node "$ORACLE_DIR/cc-oracle.mjs" "$dir/src" >"$w/cc.tsv" 2>"$w/cc.log" + node "$ORACLE_DIR/chain-runtime.mjs" "$dir/src" /dev/null --edges --routes "$w/oracle.full" --requests "$chf" >"$w/rt.tsv" 2>&1 + rt="$rt; $(python3 "$TS_HONO/tools/chain_check.py" --cc "$w/cc.tsv" --hono "$w/oracle.full" --rt "$w/rt.tsv" --draft "$chf.draft")" + fi + echo "drafted ($rt)"; pass=$((pass+1)) + else echo "FAIL (oracle refused)"; sed 's/^/ /' "$w/oracle.log" | head -4; fail=$((fail+1)); failed+=("$id"); fi + continue + fi + + golds=("$exp" "$ent"); [ "$suite" = chains ] && golds+=("$chf") + [ -f "$chf" ] && chargs=(--chains "$chf") + for f in "${golds[@]}"; do + if [ ! -f "$f" ]; then echo "FAIL (no golden: ${f#$HERE/}: draft with --draft, then REVIEW)"; ok=0; break; fi + if ! head -1 "$f" | grep -q '^# hand-reviewed'; then echo "FAIL (golden not reviewed: ${f#$HERE/} lacks the '# hand-reviewed' header)"; ok=0; break; fi + done + [ $ok = 1 ] || { fail=$((fail+1)); failed+=("$id"); continue; } + + if [ "$ORACLE" = 1 ]; then + if node "$ORACLE_DIR/hono-oracle.mjs" "$dir/src" --stores ${oflags[@]+"${oflags[@]}"} >"$w/oracle.full" 2>"$w/oracle.log"; then + grep -v '^store' "$w/oracle.full" | sort >"$w/oracle.rows" + cat "$exp" "$ent" | rows_of /dev/stdin >"$w/expected.rows" + if grep -q 'ORACLE_UNDECIDED' "$w/oracle.rows"; then echo "FAIL (the oracle could not decide a chain: extend it, do not hand-write)"; ok=0; fi + if ! diff -q "$w/expected.rows" "$w/oracle.rows" >/dev/null; then + echo "FAIL (expected differs from the oracle)"; diff "$w/expected.rows" "$w/oracle.rows" | sed 's/^/ /' | head -20; ok=0 + fi + # an `absent` row on a location that is no function can never fail: refuse it here, engine or not + node "$TS_HONO/tools/fn-locs.mjs" "$dir/src" | cut -f1 >"$w/fns" + for a in $(grep '^absent' "$exp" | cut -f2); do grep -qxF "$a" "$w/fns" || { echo "FAIL (absent row $a names no function in the fixture)"; ok=0; }; done + rt="$(node "$ORACLE_DIR/runtime-check.mjs" "$dir/src" "$w/oracle.full" 2>&1)"; rc=$? + if [ $rc -ne 0 ]; then echo "FAIL (runtime oracle disagrees with the static oracle)"; echo "$rt" | sed 's/^/ /' | head -8; ok=0; fi + notes="[$(echo "$rt" | head -1)]" + if [ -f "$chf" ]; then + if ! node "$ORACLE_DIR/cc-oracle.mjs" "$dir/src" >"$w/cc.tsv" 2>"$w/cc.log"; then echo "FAIL (call-chain oracle refused)"; head -3 "$w/cc.log" | sed 's/^/ /'; ok=0 + else + node "$ORACLE_DIR/chain-runtime.mjs" "$dir/src" /dev/null --edges --routes "$w/oracle.full" --requests "$chf" >"$w/rt.tsv" 2>&1 + if grep -q '^runtime skip' "$w/rt.tsv"; then echo "FAIL (chains need the runtime trace: $(grep '^runtime skip' "$w/rt.tsv"))"; ok=0; fi + if ! python3 "$TS_HONO/tools/chain_check.py" --cc "$w/cc.tsv" --hono "$w/oracle.full" --rt "$w/rt.tsv" --golden "$chf" >"$w/chaincheck.txt"; then + echo "FAIL (chains golden differs from the oracles)"; sed 's/^/ /' "$w/chaincheck.txt" | head -12; ok=0; fi + crt="$(node "$ORACLE_DIR/chain-runtime.mjs" "$dir/src" "$chf" 2>&1)" || { echo "FAIL (a chain hop was not observed at run time)"; echo "$crt" | sed 's/^/ /' | head -8; ok=0; } + notes="$notes [$(head -1 "$w/chaincheck.txt"); $(echo "$crt" | tail -1)]" + fi + fi + else + echo "FAIL (oracle refused: the case is unscored, not passing)"; sed 's/^/ /' "$w/oracle.log" | head -4; ok=0 + fi + if [ "$ORACLE_ONLY" = 1 ]; then + if [ $ok = 1 ]; then echo "oracle ok $notes"; pass=$((pass+1)); else fail=$((fail+1)); failed+=("$id"); fi + continue + fi + fi + + mkdir -p "$w/ir" + if ! node "$PARSER" "$dir/src" "$name" false "$w/ir" >"$w/parse.log" 2>&1; then + echo "FAIL (parse: see $w/parse.log)"; fail=$((fail+1)); failed+=("$id"); continue; fi + res="" + for variant in bare lib; do + v="$w/$variant"; mkdir -p "$v" + lib="$EMPTY_LIB" + if [ "$variant" = lib ]; then + if ! stage_lib; then res="$res lib:STAGING-FAILED"; ok=0; continue; fi + lib="$LIBIR" + fi + t0=$(date +%s) + if ! solve "$w/ir" "$lib" "$v"; then res="$res $variant:SOLVE-FAILED(see $v/solve.log)"; ok=0; continue; fi + dt=$(( $(date +%s) - t0 )) + # scale/ cases carry a wall-time budget (seconds) for the solve; exceeding it fails the case + # budget file: line 1 = seconds, optional `rss_mb N` = peak resident set of the solve + rss_mb=$(( $(cat "$v/rss_kb" 2>/dev/null || echo 0) / 1024 )) + if [ -f "$dir/budget" ]; then + tb="$(head -1 "$dir/budget")"; mb="$(sed -n 's/^rss_mb //p' "$dir/budget")" + if [ "$dt" -gt "$tb" ]; then res="$res $variant:OVER-BUDGET(${dt}s>${tb}s)"; ok=0; continue; fi + if [ -n "$mb" ] && [ ! -s "$v/rss_kb" ]; then res="$res $variant:RSS-UNMEASURED"; ok=0; continue; fi + if [ -n "$mb" ] && [ "$rss_mb" -gt "$mb" ]; then res="$res $variant:OVER-MEMORY(${rss_mb}MB>${mb}MB)"; ok=0; continue; fi + fi + python3 "$TS_HONO/tools/hono_compare.py" --lang "$LANG_" --ir "$w/ir" --raw "$v/out/raw" \ + --manifest "$MANIFEST" --relations "$TS_HONO/relations.tsv" --expected "$exp" --entries "$ent" \ + --known-missing "$km" --variant "$variant" ${chargs[@]+"${chargs[@]}"} >"$v/compare.txt" 2>&1; rc=$? + # an http entry_point row the engine adds that is not in the golden: if the BASELINE engine + # (HONO_BASELINE_ROOT, default the untouched baseline worktree) already emits it on the same IR, it is + # pre-existing receiver-blind behaviour SPEC keeps, not a Hono row (orchestrator ruling, iteration 1) + if [ $rc -eq 1 ] && grep -q '^EXTRA entry' "$v/compare.txt"; then + mkdir -p "$v/base" + if bash "$BASELINE_ROOT/graph/pipeline/run-souffle.sh" --debug --language "$LANG_" --client-ir "$w/ir" --library "$lib" \ + --intermediate "$v/base/int" --output "$v/base/out" >"$v/base/solve.log" 2>&1; then + python3 "$TS_HONO/tools/hono_compare.py" --lang "$LANG_" --ir "$w/ir" --raw "$v/out/raw" \ + --manifest "$MANIFEST" --relations "$TS_HONO/relations.tsv" --expected "$exp" --entries "$ent" \ + --known-missing "$km" --variant "$variant" ${chargs[@]+"${chargs[@]}"} --baseline-raw "$v/base/out/raw" >"$v/compare.txt" 2>&1; rc=$? + else res="$res $variant:BASELINE-SOLVE-FAILED"; ok=0; continue; fi + fi + n="$(sed -n 's/^compared=//p' "$v/compare.txt" | tail -1)" + if [ $rc -eq 3 ]; then res="$res $variant:$(head -1 "$v/compare.txt")"; ok=0; notexported=1; continue; fi + if [ $rc -eq 1 ]; then res="$res $variant:DIFF"; ok=0; continue; fi + if [ $rc -ne 0 ]; then res="$res $variant:COMPARE-CRASHED(see $v/compare.txt)"; ok=0; continue; fi + if [ "${n:-0}" -lt 1 ]; then res="$res $variant:COMPARED-0"; ok=0; continue; fi + res="$res $variant:ok($n,${dt}s,${rss_mb}MB)" + done + if [ $ok = 1 ]; then echo "ok$res $notes"; pass=$((pass+1)) + else + echo "FAIL$res" + for variant in bare lib; do [ -f "$w/$variant/compare.txt" ] && grep -E '^(MISSING|EXTRA|NOW-FIXED|PRESENT|CHAIN-BROKEN)' "$w/$variant/compare.txt" | head -12 | sed "s/^/ $variant /"; done + fail=$((fail+1)); failed+=("$id") + fi +done +[ "$KEEP" = 1 ] || rm -rf "$WORK"/*/ +echo +echo "passed $pass, failed $fail" +[ $((pass+fail)) -ge 1 ] || { echo "FAIL: no case ran (a filter matching nothing is not a pass)"; exit 1; } +[ $fail -eq 0 ] || { printf ' %s\n' "${failed[@]}"; exit 1; } diff --git a/graph/test/typescript/hono/tools/chain_check.py b/graph/test/typescript/hono/tools/chain_check.py new file mode 100644 index 000000000..b0022a0fb --- /dev/null +++ b/graph/test/typescript/hono/tools/chain_check.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +"""chains/ suite (SPEC R18-R21): check a case's `.chains` golden against BOTH halves of the truth, or draft one. + + --cc the compiler call-chain oracle's output (truth/cc-oracle.mjs: fn / edge / unres rows) + --hono the Hono oracle's output (truth/hono-oracle.mjs: its `mw` rows, and a partial route's `mwp` rows, + give the middleware hops) + --rt the runtime trace's observed edges (truth/chain-runtime.mjs --edges: `rtedge FROM TO`) + --golden the reviewed `.chains` file --draft OUT write the oracle rows (no chain rows) to OUT + +Truth, in the golden's vocabulary: + fn every function with a body (the compiler oracle's fn rows, modules excluded) + edge every compiler edge between two such functions, plus `rt` edges: observed at run time, not seen by the + compiler (a function value the compiler types only as a signature), and not a middleware hop + chain each hop is a truth edge or a middleware hop (the Hono oracle's chain order: middleware -> next middleware + of the same handler's chain -> the handler) + ccunknown the function holds a call the compiler cannot resolve (`unres` row) and that no run-time edge covers +Exit 1 with the differences listed; prints `chains ok ` otherwise. +""" +import argparse +import sys + + +def tsv(p): + with open(p) as fh: + return [l.rstrip('\n').split('\t') for l in fh if l.strip() and not l.startswith('#')] + + +def main(): + a = argparse.ArgumentParser() + a.add_argument('--cc', required=True) + a.add_argument('--hono', required=True) + a.add_argument('--rt', required=True) + a.add_argument('--golden', default='') + a.add_argument('--draft', default='') + o = a.parse_args() + cc = tsv(o.cc) + fns = {r[1] for r in cc if r[0] == 'fn' and r[2] != 'MODULE'} + static = {(r[1], r[2]) for r in cc if r[0] == 'edge' and r[1] in fns and r[2] in fns} + unres = {r[1] for r in cc if r[0] == 'unres'} + unres_sites = {r[2] for r in cc if r[0] == 'unres'} + chain_of = {} + for r in tsv(o.hono): + if r[0] == 'mw': + chain_of.setdefault((r[2], r[6] if len(r) > 6 else ''), []).append((int(r[5]), r[1])) + elif r[0] == 'mwp': + # a PARTIAL route's decidable chain (`mwp MW HANDLER VERB ORDER`): its hops are middleware hops too + chain_of.setdefault((r[2], 'partial ' + r[3]), []).append((int(r[4]), r[1])) + mwhops = set() + for (h, _), ms in chain_of.items(): + ms.sort() + for (p, m) in ms: + mwhops.add((m, h)) # a middleware reaches the handler through the rest of the chain + for (q, n) in ms: + if q == p + 1: + mwhops.add((m, n)) + # a run-time edge counts only at a call site the compiler could not resolve: a callback a library invokes is + # attributed by the tracer to whatever site is open (its documented limit), which is never such a site + rt = {(r[1], r[2]) for r in tsv(o.rt) if r[0] == 'rtedge' and r[1] in fns and r[2] in fns and len(r) > 3 and r[3] in unres_sites} + rt_only = rt - static - mwhops + if o.draft: + with open(o.draft, 'w') as fh: + for f in sorted(fns): + fh.write(f'fn\t{f}\n') + for e in sorted(static): + fh.write(f'edge\t{e[0]}\t{e[1]}\n') + for e in sorted(rt_only): + fh.write(f'edge\t{e[0]}\t{e[1]}\trt\n') + for u in sorted(unres & fns): + fh.write(f'# unres in {u} (write a ccunknown row when no rt edge covers it)\n') + print(f'drafted {len(fns)} fn, {len(static)} static + {len(rt_only)} rt edges') + return 0 + g = tsv(o.golden) + bad = [] + gf = {r[1] for r in g if r[0] == 'fn'} + gs = {(r[1], r[2]) for r in g if r[0] == 'edge' and len(r) < 4} + gr = {(r[1], r[2]) for r in g if r[0] == 'edge' and len(r) >= 4 and r[3] == 'rt'} + for x in sorted(gf ^ fns): + bad.append(f'fn {x}: ' + ('golden only' if x in gf else 'oracle only')) + for e in sorted(gs ^ static): + bad.append(f'edge {e[0]} -> {e[1]}: ' + ('golden only' if e in gs else 'compiler only')) + for e in sorted(gr ^ rt_only): + bad.append(f'rt edge {e[0]} -> {e[1]}: ' + ('golden only (not observed, or the compiler has it)' if e in gr else 'observed at run time, not in the golden')) + truth = static | rt_only | mwhops + chains = [r for r in g if r[0] == 'chain'] + for r in chains: + f = r[4:] + if len(f) < 2: + bad.append(f'chain {r[1]} has fewer than two functions') + for i in range(len(f) - 1): + if (f[i], f[i + 1]) not in truth: + bad.append(f'chain {r[1]} hop {i + 1}: {f[i]} -> {f[i + 1]} is no truth edge or middleware hop') + for r in g: + if r[0] == 'ccunknown' and r[1] not in unres: + bad.append(f'ccunknown {r[1]}: the compiler resolves every call in it') + if not chains: + bad.append('no chain row: a chains case must assert at least one whole chain') + for b in bad: + print('CHAIN-ORACLE ' + b) + if bad: + return 1 + print(f'chains ok {len(chains)} chains, {len(gs)} + {len(gr)} rt edges') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/graph/test/typescript/hono/tools/fn-locs.mjs b/graph/test/typescript/hono/tools/fn-locs.mjs new file mode 100644 index 000000000..9657178e7 --- /dev/null +++ b/graph/test/typescript/hono/tools/fn-locs.mjs @@ -0,0 +1,19 @@ +#!/usr/bin/env node +// List every function in a fixture with the location key the suite uses (`::`), +// for writing `absent` rows of a negative control by hand. usage: fn-locs.mjs +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +const { loadTypeScript } = await import(new URL('../../ground-truth/load-typescript.mjs', import.meta.url).href); +const ts = loadTypeScript(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'truth'), { toolName: 'fn-locs' }); +const src = path.resolve(process.argv[2]); +for (const f of fs.readdirSync(src, { recursive: true }).filter(f => /\.(m?[jt]sx?|cjs)$/.test(f)).sort()) { + const sf = ts.createSourceFile(f, fs.readFileSync(path.join(src, f), 'utf8'), ts.ScriptTarget.Latest, true); + (function v(n) { + if (ts.isFunctionLike(n) && n.body) { + const p = sf.getLineAndCharacterOfPosition(n.getStart(sf)); + console.log(`${f.split(path.sep).join('/')}:${p.line + 1}:${p.character + 1}\t${n.getText(sf).split('\n')[0].slice(0, 60)}`); + } + ts.forEachChild(n, v); + })(sf); +} diff --git a/graph/test/typescript/hono/tools/gen-scale.mjs b/graph/test/typescript/hono/tools/gen-scale.mjs new file mode 100644 index 000000000..a5c7022a0 --- /dev/null +++ b/graph/test/typescript/hono/tools/gen-scale.mjs @@ -0,0 +1,38 @@ +#!/usr/bin/env node +// Generate the scale/ fixtures (deterministic; re-run after editing, then --draft and review the counts). +// routes-2k : 20 modules x 100 routes, each module a sub-app mounted under its own prefix +// deep-mount: a chain of 10 sub-apps, each mounted inside the previous one +// mw-200 : 200 app-level middleware registered before 10 routes (2,000 applications) +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +const C = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'cases', 'scale'); +const w = (rel, txt) => { const f = path.join(C, rel); fs.mkdirSync(path.dirname(f), { recursive: true }); fs.writeFileSync(f, txt); }; +const VERBS = ['get', 'post', 'put', 'delete', 'patch']; + +// routes-2k +let idx = `// census: route_mount_literal, verb_literal_path (scale: 2,000 routes; generated by tools/gen-scale.mjs)\nimport { Hono } from 'hono'\n`; +for (let m = 0; m < 20; m++) { + let s = `import { Hono } from 'hono'\n\nexport const r${m} = new Hono()\n`; + for (let i = 0; i < 100; i++) s += `r${m}.${VERBS[i % 5]}('/res${i}/:id', (c) => c.text('m${m} r${i}'))\n`; + w(`routes-2k/src/mod${m}.ts`, s); + idx += `import { r${m} } from './mod${m}'\n`; +} +idx += `\nconst app = new Hono()\n`; +for (let m = 0; m < 20; m++) idx += `app.route('/m${m}', r${m})\n`; +w('routes-2k/src/index.ts', idx + `\nexport default app\n`); +w('routes-2k/budget', '300\nrss_mb 2048\n'); // seconds, then peak RSS of the solve in MB + +// deep-mount +let d = `// census: route_mount_literal (scale: 10-deep mounting; generated by tools/gen-scale.mjs)\nimport { Hono } from 'hono'\n\n`; +for (let i = 0; i < 10; i++) d += `const l${i} = new Hono()\nl${i}.get('/here', (c) => c.text('level ${i}'))\n`; +for (let i = 8; i >= 0; i--) d += `l${i}.route('/d${i + 1}', l${i + 1})\n`; +w('deep-mount/src/index.ts', d + `\nexport default l0\n`); +w('deep-mount/budget', '120\nrss_mb 2048\n'); // seconds, then peak RSS of the solve in MB + +// mw-200 +let mw = `// census: use_global, await_next (scale: 200 middleware x 10 routes; generated by tools/gen-scale.mjs)\nimport { Hono } from 'hono'\nimport type { MiddlewareHandler } from 'hono'\n\nconst app = new Hono()\n`; +for (let i = 0; i < 200; i++) mw += `const m${i}: MiddlewareHandler = async (c, next) => { await next() }\napp.use(m${i})\n`; +for (let i = 0; i < 10; i++) mw += `app.get('/r${i}', (c) => c.text('${i}'))\n`; +w('mw-200/src/index.ts', mw + `\nexport default app\n`); +w('mw-200/budget', '300\nrss_mb 2048\n'); // seconds, then peak RSS of the solve in MB diff --git a/graph/test/typescript/hono/tools/hono_compare.py b/graph/test/typescript/hono/tools/hono_compare.py new file mode 100644 index 000000000..4b70bfadc --- /dev/null +++ b/graph/test/typescript/hono/tools/hono_compare.py @@ -0,0 +1,404 @@ +#!/usr/bin/env python3 +"""Compare the engine's Hono relations against a hand-reviewed expected TSV. + +usage: hono_compare.py --lang typescript|javascript --ir IR --raw OUT/raw --manifest export_manifest.tsv + --relations relations.tsv --expected CASE.tsv --entries CASE.entries + [--known-missing CASE.known-missing] --variant bare|lib + +Every engine row is normalised to the expected file's vocabulary: a function is +`::` of its declaration (the IR's own filePath, +startLine, startColumn); a function that is not in the client IR (a library declaration) is `lib`. +A `lib:@` key in the expected file compares as `lib` too. + +Compared projections (relations.tsv says which engine file and columns feed each one, so a +column rename in SPEC.md is a one-line edit there, never a change here): + route VERB FULLPATH HANDLER @APP <- route(Handler, Verb, FullPath, App, Order); App is compared (SPEC R16a) + mw MW HANDLER ORDER <- middleware_applies(Mw, Handler, Order) + ctx SETTER READER KEY <- ctx_key_flow(Setter, Reader, Key) + mwp MW HANDLER VERB ORDER <- middleware_applies rows of a partial-only handler (path, app dropped) + ppath HANDLER VERB KNOWNPATH <- http_route_partial(Handler, Verb, KnownPath); only when the golden has ppath rows + rpc / request FROM HANDLER [CONF] <- remote_edge(From, To, .., Confidence): class base_unknown | method_unknown | known + entry FN <- entry_point(Fn, "http") + unknown FN <- remote_undetermined(Fn, ...) (expected col 4) + mount PATH <- a route row ALL PATH (any handler) + absent FN <- FN must appear in NO row above (negative controls) + +Verdicts: MISSING (expected, not produced), EXTRA (produced, not expected), NOW-FIXED (a +known-missing row that is produced). Any of them fails. Exits 3 when a relation the expected +file needs is not exported at all, so the runner can say so instead of reporting a diff. +Prints `compared=`; n is the number of expected rows checked, and the runner requires n >= 1. +""" +import argparse +import re +import csv +import os +import sys + +csv.field_size_limit(10**9) + + +def read_tsv(p): + if not os.path.exists(p) or os.path.getsize(p) == 0: + return [] + with open(p, newline='') as fh: + return [r for r in csv.reader(fh, delimiter='\t')] + + +def ir_methods(ir, lang): + f = 'all-typescript-methods.csv' if lang == 'typescript' else 'all-javascript-methods.csv' + hcol = 'tsMethodUniqueHash' if lang == 'typescript' else 'jsMethodUniqueHash' + rows = read_tsv(os.path.join(ir, f)) + if not rows: + return {} + hdr = rows[0] + ix = {c: i for i, c in enumerate(hdr)} + out = {} + for r in rows[1:]: + r = r + [''] * (len(hdr) - len(r)) + out[r[ix[hcol]]] = f"{r[ix['filePath']].replace(os.sep, '/')}:{r[ix['startLine']]}:{r[ix['startColumn']]}" + return out + + +def ir_vars(ir, lang): + """variable hash -> `::` of its name (a schema declaration, SPEC 3.9).""" + t = 'typescript' if lang == 'typescript' else 'javascript' + pre = 'ts' if lang == 'typescript' else 'js' + rows = read_tsv(os.path.join(ir, f'all-{t}-variables.csv')) + if not rows: + return {} + ix = {c: i for i, c in enumerate(rows[0])} + hk = f'{pre}VariableUniqueHash' + if hk not in ix or not {'startColumn', 'startLine', 'filePath'} <= set(ix): + return {} # the JavaScript IR's variables carry no filePath: schemas are a TypeScript row for now + out = {} + # TypeScript variables carry filePath; JavaScript ones only their module, joined like expressions + mk = next((c for c in rows[0] if c.endswith('ModuleLinkHash')), None) + mpath = module_paths(ir, t) if 'filePath' not in ix else {} + for r in rows[1:]: + r = r + [''] * (len(rows[0]) - len(r)) + fp = r[ix['filePath']] if 'filePath' in ix else mpath.get(r[ix[mk]], '?') if mk else '?' + out[r[ix[hk]]] = f"{fp.replace(os.sep, '/')}:{r[ix['startLine']]}:{r[ix['startColumn']]}" + return out + + +def module_paths(ir, t): + mods = read_tsv(os.path.join(ir, f'all-{t}-modules.csv')) + out = {} + if mods: + ix = {c: i for i, c in enumerate(mods[0])} + hk = next((c for c in mods[0] if c.endswith('ModuleUniqueHash')), None) + for r in mods[1:]: + if hk and 'filePath' in ix and len(r) > max(ix[hk], ix['filePath']): + out[r[ix[hk]]] = r[ix['filePath']].replace(os.sep, '/') + return out + + +def ir_exprs(ir, lang): + """expression hash -> `::` (the module's filePath joined through tsModuleLinkHash).""" + t = 'typescript' if lang == 'typescript' else 'javascript' + pre = 'ts' if lang == 'typescript' else 'js' + mods = read_tsv(os.path.join(ir, f'all-{t}-modules.csv')) + mpath = {} + if mods: + ix = {c: i for i, c in enumerate(mods[0])} + hk = next((c for c in mods[0] if c.endswith('ModuleUniqueHash')), None) + for r in mods[1:]: + if hk and 'filePath' in ix and len(r) > max(ix[hk], ix['filePath']): + mpath[r[ix[hk]]] = r[ix['filePath']].replace(os.sep, '/') + rows = read_tsv(os.path.join(ir, f'all-{t}-expressions.csv')) + out = {} + if not rows: + return out + ix = {c: i for i, c in enumerate(rows[0])} + hk = f'{pre}ExpressionUniqueHash' + mk = next((c for c in rows[0] if c.endswith('ModuleLinkHash')), None) + if hk not in ix or not mk: + return out + for r in rows[1:]: + r = r + [''] * (len(rows[0]) - len(r)) + out[r[ix[hk]]] = f"{mpath.get(r[ix[mk]], '?')}:{r[ix['startLine']]}:{r[ix['startColumn']]}" + return out + + +def main(): + a = argparse.ArgumentParser() + for k in ('lang', 'ir', 'raw', 'manifest', 'relations', 'expected', 'entries', 'variant'): + a.add_argument('--' + k, required=True) + a.add_argument('--known-missing', default='') + # the BASELINE engine's raw output on the same IR: an http entry_point row it already produced is + # pre-existing behaviour (the receiver-blind route-verb rule, which SPEC keeps), not a Hono row + a.add_argument('--baseline-raw', default='') + # chains/ suite (SPEC R18-R21): the case's `.chains` golden (fn / edge / chain / ccunknown rows) + a.add_argument('--chains', default='') + o = a.parse_args() + + names = ir_methods(o.ir, o.lang) + exprs = ir_exprs(o.ir, o.lang) + # a project function is its location; an expression (a library middleware's registering + # argument, SPEC 4) is `lib@`; anything else (a library declaration) is `lib` + names.update(ir_vars(o.ir, o.lang)) + fn = lambda h: names.get(h) or (('@' + exprs[h]) if h in exprs else 'lib') + manifest = {r[0]: r[1] for r in read_tsv(o.manifest) if len(r) >= 2} + rel = {} + for r in read_tsv(o.relations): + if not r or r[0].startswith('#'): + continue + rel.setdefault(r[0], []).append((r[1], dict(x.split('=') for x in r[2:]))) + + exp = [] + for path in (o.expected, o.entries): + for r in read_tsv(path): + if r and r[0] and not r[0].startswith('#'): + exp.append(r) + kinds = {r[0] for r in exp} + proj_of = {'route': {'route'}, 'mw': {'mw'}, 'ctx': {'ctx'}, 'rpc': {'remote'}, 'request': {'remote'}, + 'entry': {'entry'}, 'unknown': {'unknown'}, 'partial': {'partial'}, 'submount': {'submount'}, + 'unserved': {'unserved'}, 'schema': {'schema'}, 'validread': {'validread'}, 'regby': {'regby'}, + 'absent': {'route', 'mw'}, 'mwp': {'mw'}, 'ppath': {'partial'}} + # an absence is checked against every Hono relation the engine exports; route and mw are required + # (above), the later ones (ctx, remote, schema) join the check as soon as they are exported + absent_optional = {'ctx', 'remote', 'schema'} + need = {'route'} # even a negative case asserts the route table EXISTS: absence of an + for k in kinds: # unexported relation is not absence of rows + need |= proj_of.get(k, set()) + missing_rel = sorted({f"{p} ({r[0]})" for p in need for r in rel.get(p, [('?', {})]) if r[0] not in manifest}) + if missing_rel: + print('relation not exported: ' + ', '.join(missing_rel)) + print('compared=0') + sys.exit(3) + + def engine(proj): + out = [] + for relname, cols in rel[proj]: + c = {k: int(v) for k, v in cols.items()} + rows = read_tsv(os.path.join(o.raw, manifest[relname])) + short = [k for k, i in c.items() if rows and any(len(r) <= i for r in rows)] + if short: + # a column SPEC names that the engine does not write is a missing relation shape, not a diff + print(f'relation {relname} lacks column(s): {", ".join(short)}') + print('compared=0') + sys.exit(3) + for r in rows: + g = lambda k: r[c[k]] if k in c and c[k] < len(r) else '' + if proj == 'route': + # SPEC R16a: the App column answers "which app serves this"; a wrong App is a false route (R16) + out.append(('route', g('verb').upper(), g('path'), fn(g('handler'))) + ((fn(g('app')),) if 'app' in c else ())) + elif proj == 'partial': + out.append(('partial', fn(g('handler')), g('reason'))) + # hono-7-05 (opt-in: a case whose golden has ppath rows): the KnownPath of the partial route + if 'ppath' in kinds: + out.append(('ppath', fn(g('handler')), (g('verb') or '').upper(), g('path'))) + elif proj == 'submount': + out.append(('submount', g('prefix'))) + elif proj == 'mw': + out.append(('mw', fn(g('mw')), fn(g('handler')), g('verb').upper(), g('path'), str(int(g('position') or -1))) + + ((fn(g('app')),) if 'app' in c else ())) + elif proj == 'ctx': + out.append(('ctx', fn(g('setter')), fn(g('reader')), g('key'))) + elif proj == 'remote': + # R14: precision is scored per confidence; base_unknown is its own class, the others (exact, + # route_shape) one class, as before + # R17: method_unknown (a request whose verb is not decidable) is a class of its own too + out.append(('remote', fn(g('from')), fn(g('to')), g('conf') if g('conf') in ('base_unknown', 'method_unknown') else 'known')) + elif proj == 'unserved': + out.append(('unserved', fn(g('fn')))) + elif proj == 'entry': + if g('kind') == 'http': + out.append(('entry', fn(g('fn')))) + elif proj == 'unknown': + out.append(('unknown', fn(g('fn')), g('reason'))) + elif proj == 'regby': + out.append(('regby', fn(g('regmethod')), fn(g('handler')), g('verb').upper(), g('path'), fn(g('app')))) + elif proj == 'schema': + out.append(('schema', fn(g('handler')), g('target'), fn(g('decl')))) + elif proj == 'validread': + out.append(('validread', fn(g('read')), fn(g('handler')), g('target'), fn(g('decl')))) + return out + + def lib(k): + # an expression is named by its location: `lib:.@` and `expr@` -> `@`; + # a bare `lib:...` (a library declaration) -> `lib` + if k.startswith('expr@'): + return '@' + k[5:] + # a library key is `lib` or `lib:...`; a project path may itself start with lib/ or libs/ + if not (k == 'lib' or k.startswith('lib:')): + return k + # the site follows the LAST '@': a scoped package (@hono/zod-validator) has one of its own + m = re.search(r'@([^@]+:\d+:\d+)$', k) + return '@' + m.group(1) if m else 'lib' + mw_app = any('app' in cols for _, cols in rel.get('mw', [])) + route_app = any('app' in cols for _, cols in rel.get('route', [])) + want = set() + absent = [] + for r in exp: + k = r[0] + if k == 'route': + want.add(('route', r[1], r[2], lib(r[3])) + (('@' + r[4],) if route_app else ())) + elif k == 'mw': + want.add(('mw', lib(r[1]), lib(r[2]), r[3], r[4], r[5]) + (('@' + r[6],) if mw_app else ())) + elif k == 'ctx': + want.add(('ctx', r[1], r[2], r[3])) + elif k in ('rpc', 'request'): + # dest spelling is SPEC-open: not compared; an optional 6th column is the confidence class (R14) + want.add(('remote', r[1], lib(r[4]), r[5] if len(r) > 5 and r[5] in ('base_unknown', 'method_unknown') else 'known')) + elif k == 'mwp': + want.add(('mwp', lib(r[1]), lib(r[2]), r[3], r[4])) + elif k == 'entry': + if not (r[1] == 'lib' or r[1].startswith('lib:')): + want.add(('entry', r[1])) + elif k == 'unknown': + want.add(('unknown', r[3], r[2])) + elif k == 'partial': + want.add(('partial', lib(r[1]), r[3])) + elif k == 'ppath': + want.add(('ppath', lib(r[1]), r[2], r[3])) + elif k == 'submount': + want.add(('submount', r[1])) + elif k == 'unserved': + want.add(('unserved', r[1])) + elif k == 'schema': + want.add(('schema', r[1], r[2], lib(r[3]))) + elif k == 'regby': + want.add(('regby', r[1], lib(r[2]), r[3], r[4], '@' + r[5])) + elif k == 'validread': + want.add(('validread', '@' + r[1], r[2], r[3], lib(r[4]))) + elif k == 'absent': + absent.append(r[1]) + else: + print(f'bad expected row kind: {k}') + sys.exit(2) + + if 'absent' in kinds: + for p in sorted(absent_optional): + if all(r[0] in manifest for r in rel.get(p, [('?', {})])): + need.add(p) + else: + print(f'note: absence not yet checked in {p} (not exported)') + have = set() + for p in sorted(need): + have |= set(engine(p)) + # SPEC 3.3: a partial route's chain is compared without its path and app (neither is decidable); a middleware + # row whose handler is partial-only in the expected truth is projected the same way + partial_only = {w[1] for w in want if w[0] == 'partial'} - {w[3] for w in want if w[0] == 'route'} + if partial_only: + have = {('mwp', h[1], h[2], h[3], h[5]) if h[0] == 'mw' and h[2] in partial_only else h for h in have} + + known = set() + if o.known_missing and os.path.exists(o.known_missing): + for r in read_tsv(o.known_missing): + if not r or r[0].startswith('#'): + continue + if r[0] in ('*', o.variant): + known.add(tuple(r[1:])) + + bad = 0 + for w in sorted(want): + if w not in have and w not in known: + print('MISSING ' + '\t'.join(w)); bad += 1 + elif w in have and w in known: + print('NOW-FIXED ' + '\t'.join(w)); bad += 1 + # extras: a row the engine produced that the reviewed truth does not have + pre = set() + if o.baseline_raw and 'entry_point' in manifest: + for r in read_tsv(os.path.join(o.baseline_raw, manifest['entry_point'])): + if len(r) >= 2 and r[1] == 'http': + pre.add(('entry', fn(r[0]))) + for h in sorted(have): + if h in want: + continue + if h in pre: + print('PRE-EXISTING ' + '\t'.join(h) + ' (the baseline engine already emits it)') + continue + print('EXTRA ' + '\t'.join(h)); bad += 1 + known_fns = set(names.values()) + for f in absent: + if f not in known_fns: + # an absence check on a location that is no function is vacuous: it can never fail + print(f'BAD-ABSENT {f} names no function in the IR'); bad += 1 + continue + hits = [h for h in have if f in h[1:] and h not in pre] # a pre-existing entry row is not a Hono row + for h in hits: + print('PRESENT ' + '\t'.join(h) + f' (absent {f})'); bad += 1 + nchain = 0 + if o.chains: + cbad, nchain = compare_chains(o, rel, manifest, fn, read_tsv) + bad += cbad + print(f'compared={len(want) + len(absent) + nchain}') + sys.exit(1 if bad else 0) + + +def compare_chains(o, rel, manifest, fn, read_tsv): + """chains/ (SPEC R18-R21). The golden `.chains` holds, from the compiler oracle and the runtime trace: + fn KEY every function with a body in the fixture (the universe edges are scored in) + edge FROM TO [rt] a call edge between two of them (`rt`: observed at run time, beyond the compiler) + chain NAME VERB PATH F0..Fn a WHOLE chain; each hop is a call edge or a middleware hop (A applies to handler H + and the next is H, or the next middleware of H's chain) + ccunknown FN FN holds a call whose target is not decidable: the engine must declare it (R21) + Engine call edges: call_chain_edge (FromMethod -> ToMethod), a declared base widened by + method_dispatch_candidate, and fn_value_call. Edges are compared both ways inside the fn universe (an edge to a + same-named method of an unrelated class is EXTRA); a chain is reported once, at its first break.""" + rows = [r for r in read_tsv(o.chains) if r and r[0] and not r[0].startswith('#')] + fns = {r[1] for r in rows if r[0] == 'fn'} + want_e = {(r[1], r[2]) for r in rows if r[0] == 'edge'} + chains = [r for r in rows if r[0] == 'chain'] + want_u = {r[1] for r in rows if r[0] == 'ccunknown'} + need = ['chainedge', 'dispatch', 'fnvalue', 'ccunknown', 'mw'] + miss = sorted({f'{p} ({r[0]})' for p in need for r in rel.get(p, [('?', {})]) if r[0] not in manifest}) + if miss: + print('relation not exported: ' + ', '.join(miss)) + # without call edges or middleware rows there is nothing to compare; a missing widening relation (dispatch, + # fnvalue, ccunknown) still FAILS the case (exit 3 below), but the chains are compared on what IS exported, so + # the report shows where they break (the JavaScript engine exports neither widening relation) + if any(m.split(' ')[0] in ('chainedge', 'mw') for m in miss): + print('compared=0'); sys.exit(3) + + def raw(p): + out = [] + for relname, cols in rel[p]: + if relname not in manifest: + continue + c = {k: int(v) for k, v in cols.items()} + for r in read_tsv(os.path.join(o.raw, manifest[relname])): + out.append({k: (r[i] if i < len(r) else '') for k, i in c.items()}) + return out + base = {} + for r in raw('dispatch'): + base.setdefault(r['base'], set()).add(r['impl']) + have_e = set() + for r in raw('chainedge'): + if r['to'] in ('', '-'): + continue + for t in {r['to']} | base.get(r['to'], set()): + have_e.add((fn(r['from']), fn(t))) + for r in raw('fnvalue'): + have_e.add((fn(r['from']), fn(r['to']))) + have_e = {e for e in have_e if e[0] in fns and e[1] in fns} + mwpos = {} + for r in raw('mw'): + mwpos.setdefault(fn(r['handler']), {})[fn(r['mw'])] = int(r['position'] or -1) + def mw_hop(a, b): + for h, ch in mwpos.items(): + if a in ch and (b == h or (b in ch and ch[b] == ch[a] + 1)): + return True + return False + have_u = {fn(r['fn']) for r in raw('ccunknown')} + bad = 0 + for e in sorted(want_e - have_e): + print('MISSING edge\t' + '\t'.join(e)); bad += 1 + for e in sorted(have_e - want_e): + print('EXTRA edge\t' + '\t'.join(e)); bad += 1 + for r in chains: + f = r[4:] + for i in range(len(f) - 1): + if (f[i], f[i + 1]) not in have_e and not mw_hop(f[i], f[i + 1]): + print(f'CHAIN-BROKEN {r[1]} at hop {i + 1}/{len(f) - 1}\t{f[i]} -> {f[i + 1]}'); bad += 1 + break + for u in sorted(want_u - have_u): + print('MISSING ccunknown\t' + u); bad += 1 + if miss: + print(f'compared={len(want_e) + len(chains) + len(want_u)}'); sys.exit(3) + return bad, len(want_e) + len(chains) + len(want_u) + + +if __name__ == '__main__': + main() diff --git a/graph/test/typescript/hono/tools/promote-draft.sh b/graph/test/typescript/hono/tools/promote-draft.sh new file mode 100755 index 000000000..62f545786 --- /dev/null +++ b/graph/test/typescript/hono/tools/promote-draft.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Promote a REVIEWED oracle draft to the golden. Run only after reading the draft against the fixture: +# the header it writes is a claim that a person checked every row. +# tools/promote-draft.sh / "" +set -euo pipefail +D="${HONO_SUITE_DIR:-$(cd "$(dirname "$0")/.." && pwd)}" +id="$1"; note="$2"; suite="${id%%/*}"; name="${id#*/}" +census="$(grep -rhoE '(//|#) census: .*' "$D/cases/$id/src" | head -1 | sed -E 's@^(//|#) census: @@')" +[ -n "$census" ] || { echo "the fixture has no '// census:' header: cite the shape it models first" >&2; exit 1; } +for ext in tsv entries; do + dr="$D/expected/$id.$ext.draft"; [ -f "$dr" ] || { echo "no draft $dr" >&2; exit 1; } + { echo "# hand-reviewed $(date +%F) against the fixture and the oracle: $note" + echo "# census: $census" + cat "$dr"; } > "$D/expected/$id.$ext" + rm -f "$dr" +done diff --git a/graph/test/typescript/hono/truth/.gitignore b/graph/test/typescript/hono/truth/.gitignore new file mode 100644 index 000000000..504afef81 --- /dev/null +++ b/graph/test/typescript/hono/truth/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +package-lock.json diff --git a/graph/test/typescript/hono/truth/cc-oracle.mjs b/graph/test/typescript/hono/truth/cc-oracle.mjs new file mode 100644 index 000000000..e755b6565 --- /dev/null +++ b/graph/test/typescript/hono/truth/cc-oracle.mjs @@ -0,0 +1,511 @@ +#!/usr/bin/env node +// ───────────────────────────────────────────────────────────────────────────── +// Hono torture oracle: the STATIC half of the ground truth. +// +// Independent of the engine by construction: it uses the TypeScript compiler API and the +// real `hono` package pinned in ./package.json (never the axiom parser, never the IR). It +// walks every registration in PROGRAM ORDER and replays Hono's own semantics, as read from +// hono-base.js of the pinned version: +// +// - `new Hono()` / `new OpenAPIHono()` (the class must be DECLARED in the pinned package; +// a local class that happens to be called Hono is not an app); +// - `basePath(p)` returns a clone that SHARES the route list, with base = mergePath(base, p); +// - a verb / `all` / `on` / `use` registers one entry per handler, `use` with method ALL and +// default path `*`, a path-less verb continues the instance's last path; +// - `route(p, sub)` COPIES sub's entries present AT THAT MOMENT under mergePath(base, p); +// - `mount(p, fetch)` registers ALL mergePath(base, p, '*') to a foreign handler. +// +// Which middleware applies to which handler is decided by Hono's OWN router (SmartRouter of +// the pinned package) matched against a concrete sample of the handler's path, in +// registration order: never by a re-implementation of the pattern language. +// +// cc-oracle: program setup copied from hono-oracle.mjs (lines 1-219); call edges below. +// Output (TSV on stdout, one relation per first column; locations are +// `::` of the function node, 1-based): +// route VERB FULLPATH HANDLER APP ORDER +// mw MW HANDLER ORDER (ORDER = position in the handler's middleware chain) +// entry FN http +// ctx SETTER_FN READER_FN KEY +// rpc FROM_FN VERB PATH HANDLER +// request FROM_FN VERB PATH HANDLER +// mount PATH TARGET +// unknown SITE REASON +// Exit 2 (refusal) when the program does not typecheck: an unscored case is not a pass. +// ───────────────────────────────────────────────────────────────────────────── +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +// the compiler is the oracle's OWN pinned one, reached through the suite's shared loader (version-guarded) +const { loadTypeScript } = await import(new URL('../../ground-truth/load-typescript.mjs', import.meta.url).href); +const ts = loadTypeScript(HERE, { toolName: 'hono-oracle' }); +const NM = path.join(HERE, 'node_modules'); +const { SmartRouter } = await import(path.join(NM, 'hono/dist/router/smart-router/index.js')); +const { RegExpRouter } = await import(path.join(NM, 'hono/dist/router/reg-exp-router/index.js')); +const { TrieRouter } = await import(path.join(NM, 'hono/dist/router/trie-router/index.js')); + +const SRC = path.resolve(process.argv[2] || '.'); +const NO_TYPECHECK = process.argv.includes('--no-typecheck'); +const STORES = process.argv.includes('--stores'); +const DEBUG = !!process.env.HONO_ORACLE_DEBUG; +const T0 = Date.now(); +const phase = name => { if (DEBUG) process.stderr.write(`phase ${name} at ${((Date.now() - T0) / 1000).toFixed(1)}s\n`); }; + +// ── program ───────────────────────────────────────────────────────────────── +const EXT = /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/; +function walkDir(d, out = []) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) walkDir(p, out); + else if (EXT.test(e.name) && !e.name.endsWith('.d.ts')) out.push(p); + } + return out; +} +const files = walkDir(SRC).sort(); +const options = { + target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext, + moduleResolution: ts.ModuleResolutionKind.Bundler, strict: true, allowJs: true, checkJs: false, + noEmit: true, skipLibCheck: true, esModuleInterop: true, resolveJsonModule: true, + jsx: ts.JsxEmit.ReactJSX, jsxImportSource: 'hono/jsx', types: [], lib: ['lib.es2022.d.ts', 'lib.dom.d.ts'], + allowImportingTsExtensions: true, +}; +const host = ts.createCompilerHost(options, true); +const ANCHOR = path.join(HERE, 'anchor.ts'); // resolve bare packages from the oracle's own node_modules +// ── Deno: an import map (deno.json / deno.jsonc / import_map.json `imports`, exact and prefix keys) and +// jsr: / npm: / deno.land URL specifiers, each mapped to the PINNED package of the same name. This is a +// module-resolution host for the oracle only; it says nothing about how the engine should resolve them. +// every deno.json / deno.jsonc / import_map.json in the fixture (a Deno project need not sit at the root) +const denoCfgs = []; +(function scanDeno(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) scanDeno(p); else if (['deno.json', 'deno.jsonc', 'import_map.json'].includes(e.name)) denoCfgs.push(p); + } +})(SRC); +const DENO_CFG = denoCfgs.length > 0; +let importMap = {}; +for (const f of denoCfgs) { + try { + const j = JSON.parse(fs.readFileSync(f, 'utf8').replace(/^\s*\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '')); + importMap = { ...importMap, ...(j.imports || {}) }; + const im = j.importMap && path.join(path.dirname(f), j.importMap); + if (im && fs.existsSync(im)) importMap = { ...importMap, ...JSON.parse(fs.readFileSync(im, 'utf8')).imports }; + } catch { } +} +function canonicalSpec(spec) { + if (importMap[spec]) spec = importMap[spec]; + else { + const k = Object.keys(importMap).filter(k => k.endsWith('/') && spec.startsWith(k)).sort((a, b) => b.length - a.length)[0]; + if (k) spec = importMap[k] + spec.slice(k.length); + } + let m; + if ((m = spec.match(/^jsr:\/?@hono\/hono(?:@[^/]*)?(\/.*)?$/)) || (m = spec.match(/^@hono\/hono(\/.*)?$/))) return 'hono' + (m[1] || ''); + if ((m = spec.match(/^npm:\/?((?:@[^/@]+\/)?[^/@]+)(?:@[^/]*)?(\/.*)?$/))) return m[1] + (m[2] || ''); + if ((m = spec.match(/^jsr:\/?(@hono\/[^/@]+)(?:@[^/]*)?(\/.*)?$/))) return m[1] + (m[2] || ''); + if ((m = spec.match(/^https:\/\/deno\.land\/x\/hono(?:@[^/]*)?\/(.*)$/))) { + if (m[1] === 'mod.ts') return 'hono'; + if (m[1] === 'middleware.ts') return path.join(HERE, 'deno-shims', 'middleware.d.ts'); + return 'hono/' + m[1].replace(/^middleware\//, '').replace(/\/index\.ts$|\.ts$/, ''); + } + return spec; +} +const libLabel = ms => { const c = canonicalSpec(ms); return c.startsWith('/') ? 'hono/middleware' : c; }; +// tsconfig `paths` / `baseUrl` of the nearest tsconfig.json above the importing file (inside the fixture): +// an aliased project import (`@/lib/app`) resolves to the project file, as the project's compiler would +const _pathsCache = new Map(); +function pathsOpts(containing) { + let d = path.dirname(path.resolve(containing)); + const seen = []; + while (d.startsWith(SRC)) { + if (_pathsCache.has(d)) { const v = _pathsCache.get(d); seen.forEach(x => _pathsCache.set(x, v)); return v; } + seen.push(d); + const f = path.join(d, 'tsconfig.json'); + if (fs.existsSync(f)) { + let v = null; + try { + const cf = ts.readConfigFile(f, ts.sys.readFile); + const pc = ts.parseJsonConfigFileContent(cf.config || {}, ts.sys, d); + if (pc.options.paths || pc.options.baseUrl) v = { paths: pc.options.paths, baseUrl: pc.options.baseUrl, pathsBasePath: pc.options.pathsBasePath || d }; + } catch { v = null; } + seen.forEach(x => _pathsCache.set(x, v)); return v; + } + const up = path.dirname(d); if (up === d) break; d = up; + } + seen.forEach(x => _pathsCache.set(x, null)); return null; +} +// workspace packages: a package.json with a name anywhere in the fixture (not under node_modules) makes +// `` and `/` resolve to that package's files, as a workspace install links them +const workspace = new Map(); +(function scanWs(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) scanWs(p); + else if (e.name === 'package.json') { try { const n = JSON.parse(fs.readFileSync(p, 'utf8')).name; if (n) workspace.set(n, d); } catch { } } + } +})(SRC); +function exportsTarget(d, sub) { + // package.json `exports`: "./sub" -> a string, or a conditions object (types / import / default) + try { + const ex = JSON.parse(fs.readFileSync(path.join(d, 'package.json'), 'utf8')).exports; + if (!ex) return null; + const key = sub ? './' + sub : '.'; + let t = typeof ex === 'string' && key === '.' ? ex : ex[key]; + // a subpath pattern (`"./*"`, `"./adapters/*"`) lists every subpath it matches: substitute the matched part + if (t === undefined && typeof ex === 'object') for (const [k, v] of Object.entries(ex)) { + const i = k.indexOf('*'); if (i < 0 || !key.startsWith(k.slice(0, i)) || !key.endsWith(k.slice(i + 1)) || key.length < k.length - 1) continue; + const m = key.slice(i, key.length - (k.length - i - 1)); + let vv = v; if (vv && typeof vv === 'object') vv = vv.types || vv.import || vv.default || vv.require; + if (typeof vv === 'string') { t = vv.split('*').join(m); break; } + } + if (t && typeof t === 'object') t = t.types || t.import || t.default || t.require; + if (typeof t !== 'string') return null; + // O3b: an export that points at an unbuilt output file (`./dist/x.js`, `./dist/x.d.ts`) is served from the + // package's source in a checkout: the same path under src/, with a source extension + if (!fs.existsSync(path.join(d, t))) { + const stem = t.replace(/^\.?\//, '').replace(/^(dist|build|out|lib)\//, '').replace(/\.d\.(ts|mts|cts)$|\.(js|mjs|cjs|ts|mts|cts)$/, ''); + for (const base of ['src/', '']) for (const ext of ['.ts', '.tsx', '.mts', '.js', '.mjs', '/index.ts', '/index.js']) { + const c = path.join(d, base + stem + ext); + if (fs.existsSync(c)) return c; + } + } + return path.join(d, t); + } catch { return null; } +} +// the moduleResolution of the program a file belongs to: its nearest tsconfig.json inside the fixture, else the oracle's +const _mrCache = new Map(); +function moduleResolutionOf(containing) { + let d = path.dirname(path.resolve(containing)); + while (d.startsWith(SRC)) { + if (_mrCache.has(d)) return _mrCache.get(d); + const f = path.join(d, 'tsconfig.json'); + if (fs.existsSync(f)) { + let v = options.moduleResolution; + try { const pc = ts.parseJsonConfigFileContent(ts.readConfigFile(f, ts.sys.readFile).config || {}, ts.sys, d); v = ts.getEmitModuleResolutionKind(pc.options); } catch { } + _mrCache.set(d, v); return v; + } + const up = path.dirname(d); if (up === d) break; d = up; + } + return options.moduleResolution; +} +function workspaceOpts(spec, containing) { + for (const [n, d] of workspace) if (spec === n || spec.startsWith(n + '/')) { + const sub = spec === n ? '' : spec.slice(n.length + 1); + const t = exportsTarget(d, sub); + if (t) return { baseUrl: d, paths: { [spec]: [t] }, pathsBasePath: d }; + // SPEC R22a: a package whose `exports` does not list this subpath resolves only where the TypeScript compiler + // resolves it. node10 ignores `exports` and reads the package directory itself; bundler, node16 and nodenext + // enforce `exports`, so the import is unbound (no synthetic `src/` paths for it) + let hasExports = false; + try { hasExports = JSON.parse(fs.readFileSync(path.join(d, 'package.json'), 'utf8')).exports !== undefined; } catch { } + if (hasExports) { + const mr = containing ? moduleResolutionOf(containing) : options.moduleResolution; + if (mr !== ts.ModuleResolutionKind.Node10 && mr !== ts.ModuleResolutionKind.Classic) return null; + return { baseUrl: d, moduleResolution: ts.ModuleResolutionKind.Node10, paths: { [spec]: [sub ? path.join(d, sub) : d] }, pathsBasePath: d }; + } + return { baseUrl: d, paths: { [n]: [d, path.join(d, 'src')], [n + '/*']: [path.join(d, '*'), path.join(d, 'src', '*')] }, pathsBasePath: d }; + } + return null; +} +// ONE resolver for every project-side lookup (program building, module order, require), so a module the +// program contains is never evaluated out of order because a second lookup could not find it +function resolveSpec(rawSpec, containing, opts = options) { + const spec = canonicalSpec(rawSpec); + let r = ts.resolveModuleName(spec, containing, opts, host).resolvedModule; + if (!r && !spec.startsWith('.') && !spec.startsWith('/')) { + for (const po of [pathsOpts(containing), workspaceOpts(spec, containing)]) { + if (r || !po) continue; + r = ts.resolveModuleName(spec, containing, { ...opts, ...po }, host).resolvedModule; + if (r && r.isExternalLibraryImport) r = undefined; + } + if (!r) r = ts.resolveModuleName(spec, ANCHOR, opts, host).resolvedModule; + } + return r; +} +function isProjectSpec(spec, containing) { + if (spec.startsWith('.') || spec.startsWith('/')) return true; + const r = resolveSpec(spec, containing); + return !!(r && path.resolve(r.resolvedFileName).startsWith(SRC + path.sep) && !r.resolvedFileName.includes(`${path.sep}node_modules${path.sep}`)); +} +host.resolveModuleNameLiterals = (lits, containing, redirected, opts) => lits.map(lit => ({ resolvedModule: resolveSpec(lit.text, containing, opts) })); +const program = ts.createProgram(DENO_CFG ? [...files, path.join(HERE, 'deno-shims', 'deno.d.ts')] : files, options, host); +const checker = program.getTypeChecker();phase('program'); + +const srcFiles = program.getSourceFiles().filter(sf => path.resolve(sf.fileName).startsWith(SRC + path.sep)); + +if (!NO_TYPECHECK) { + const diags = ts.getPreEmitDiagnostics(program).filter(d => d.file && srcFiles.includes(d.file) + && !/\.(js|mjs|cjs|jsx)$/.test(d.file.fileName)); + if (diags.length) { + for (const d of diags.slice(0, 8)) { + const { line } = d.file.getLineAndCharacterOfPosition(d.start || 0); + process.stderr.write(`REFUSED (does not typecheck): ${path.relative(SRC, d.file.fileName)}:${line + 1} ${ts.flattenDiagnosticMessageText(d.messageText, ' ')}\n`); + } + process.exit(2); + } +} + +const rel = f => path.relative(SRC, path.resolve(f)).split(path.sep).join('/'); +const loc = n => { const sf = n.getSourceFile(); const p = sf.getLineAndCharacterOfPosition(n.getStart(sf)); return `${rel(sf.fileName)}:${p.line + 1}:${p.character + 1}`; }; +const inPkg = (decl, pkgs) => { const f = path.resolve(decl.getSourceFile().fileName); return pkgs.some(p => f.includes(`${path.sep}node_modules${path.sep}${p}${path.sep}`)); }; +// ───────────────────────────────────────────────────────────────────────────── +// CALL-CHAIN ORACLE (callchain harness). Compiler-resolved caller->callee edges over the whole project. +// Rows (TSV): +// fn KEY KIND NAME ENDLINE every function-like with a body, plus each module (KEY rel:1:1) +// edge CALLER CALLEE KIND SITE FEATS KIND call|new|deco|tag|closure|fnref|impl|virt +// unres CALLER SITE REASON CALLEE_TEXT FEATS the compiler names no project declaration it can follow +// lib CALLER SITE LIB CALLEE_TEXT resolved into a library / lib.d.ts (chain boundary) +// ───────────────────────────────────────────────────────────────────────────── +const isSrcDecl = d => d && path.resolve(d.getSourceFile().fileName).startsWith(SRC + path.sep) && !d.getSourceFile().fileName.includes("/node_modules/") && !d.getSourceFile().isDeclarationFile; +const isFnNode = n => (ts.isFunctionDeclaration(n) || ts.isFunctionExpression(n) || ts.isArrowFunction(n) + || ts.isMethodDeclaration(n) || ts.isConstructorDeclaration(n) || ts.isGetAccessorDeclaration(n) + || ts.isSetAccessorDeclaration(n)) && !!n.body; +const isJsFile = f => /\.(js|mjs|cjs|jsx)$/.test(f); +const endLine = n => n.getSourceFile().getLineAndCharacterOfPosition(n.getEnd()).line + 1; +function fnName(n) { + if (n.name) return n.name.getText(); + if (ts.isConstructorDeclaration(n)) return 'constructor'; + const p = n.parent; + if (p && ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) return p.name.text; + if (p && (ts.isPropertyAssignment(p) || ts.isPropertyDeclaration(p))) return p.name.getText(); + return ts.isArrowFunction(n) ? '' : ''; +} +function encl(n) { + for (let p = n.parent; p; p = p.parent) if (isFnNode(p)) return p; + return null; +} +const keyOf = fnOrNull => fnOrNull ? loc(fnOrNull) : null; +const modKey = sf => `${rel(sf.fileName)}:1:1`; +const callerKey = n => { const f = encl(n); return f ? loc(f) : modKey(n.getSourceFile()); }; +const rows = []; +const emit = (...a) => rows.push(a.map(x => String(x ?? '').replace(/[\t\n]/g, ' ')).join('\t')); +const short = n => n.getText().replace(/\s+/g, ' ').slice(0, 80); + +// ── class hierarchy in the project: ancestor symbol -> implementing/extending class decls ── +const resolveSym = s => (s && (s.flags & ts.SymbolFlags.Alias)) ? checker.getAliasedSymbol(s) : s; +const descendants = new Map(); // ancestor decl node -> Set(class decl) +function heritageDecls(cls) { + const outD = []; + for (const h of cls.heritageClauses || []) for (const t of h.types) { + let s; try { s = resolveSym(checker.getSymbolAtLocation(t.expression)); } catch { } + for (const d of s?.declarations || []) if (ts.isClassLike(d) || ts.isInterfaceDeclaration(d)) outD.push(d); + } + return outD; +} +const allClasses = []; +for (const sf of srcFiles) (function v(n) { if (ts.isClassLike(n)) allClasses.push(n); ts.forEachChild(n, v); })(sf); +for (const c of allClasses) { + const seen = new Set(); const stack = heritageDecls(c); + while (stack.length) { + const a = stack.pop(); if (seen.has(a)) continue; seen.add(a); + if (!descendants.has(a)) descendants.set(a, new Set()); descendants.get(a).add(c); + stack.push(...heritageDecls(a)); + } +} +const memberName = d => d.name && (ts.isIdentifier(d.name) || ts.isStringLiteral(d.name) || ts.isPrivateIdentifier(d.name)) ? d.name.text : null; +function implsOf(decl) { + // decl: a member of an interface / class (abstract or concrete). Returns concrete overriding members in subclasses. + const owner = decl.parent; const nm = memberName(decl); const res = []; + if (!owner || !nm || !descendants.has(owner)) return res; + for (const c of descendants.get(owner)) for (const m of c.members || []) { + if (memberName(m) === nm && isFnNode(m) && !(ts.getCombinedModifierFlags(m) & ts.ModifierFlags.Static)) res.push(m); + if (memberName(m) === nm && ts.isPropertyDeclaration(m) && m.initializer && (ts.isArrowFunction(m.initializer) || ts.isFunctionExpression(m.initializer))) res.push(m.initializer); + } + return res; +} +// ── features of a call site, for break classification ── +function rootOf(e) { + while (true) { + if (ts.isPropertyAccessExpression(e) || ts.isElementAccessExpression(e)) e = e.expression; + else if (ts.isCallExpression(e)) e = e.expression; + else if (ts.isParenthesizedExpression(e) || ts.isAwaitExpression(e) || ts.isNonNullExpression(e) || ts.isAsExpression(e)) e = e.expression; + else return e; + } +} +function siteFeats(node, calleeExpr) { + const f = []; + const sf = node.getSourceFile(); + if (isJsFile(sf.fileName)) f.push('js'); + if (!calleeExpr) return f; + const txt = calleeExpr.getText(); + if (/(^|\W)(c|ctx|context)\.(get|var)\b/.test(txt) || /\bc\.env\b/.test(txt)) f.push('ctxdi'); + if (/\bawait import\(|\bimport\(/.test(txt)) f.push('dynimport'); + let ce = calleeExpr; + while (ts.isParenthesizedExpression(ce) || ts.isAwaitExpression(ce) || ts.isNonNullExpression(ce) || ts.isAsExpression(ce)) ce = ce.expression; + if (ts.isCallExpression(ce)) f.push('callresult'); + if (ts.isElementAccessExpression(ce)) f.push('elementaccess'); + if (node.questionDotToken || (ce.questionDotToken)) f.push('optional'); + const r = rootOf(calleeExpr); + if (r.kind === ts.SyntaxKind.ThisKeyword) { + for (let q = node.parent; q; q = q.parent) { + if (ts.isArrowFunction(q)) continue; + if (isFnNode(q) || ts.isClassStaticBlockDeclaration?.(q)) { + if ((ts.getCombinedModifierFlags(q) & ts.ModifierFlags.Static) || ts.isClassStaticBlockDeclaration?.(q)) f.push('staticthis'); + if (ts.isArrowFunction(node.parent) || true) { let a = node.parent; let viaArrow = false; while (a && a !== q) { if (ts.isArrowFunction(a)) viaArrow = true; a = a.parent; } if (viaArrow) f.push('arrowthis'); } + break; + } + } + // this.x.m(): x a constructor parameter property or assigned from a ctor parameter -> DI + if (ts.isPropertyAccessExpression(calleeExpr) && ts.isPropertyAccessExpression(calleeExpr.expression)) { + const fld = calleeExpr.expression.name.text; + let s; try { s = checker.getSymbolAtLocation(calleeExpr.expression.name); } catch { } + for (const d of s?.declarations || []) { + if (ts.isParameter(d) && ts.isConstructorDeclaration(d.parent)) f.push('ctordi'); + if (ts.isPropertyDeclaration(d) && (d.decorators || ts.getDecorators?.(d))?.length) f.push('ctordi'); + } + void fld; + } + f.push('this'); + } + if (ts.isIdentifier(r)) { + let s; try { s = checker.getSymbolAtLocation(r); } catch { } + if (s && (s.flags & ts.SymbolFlags.Alias)) { + // re-export: the import names a module that is not where the declaration lives + const imp = s.declarations?.[0]; + let decl = resolveSym(s)?.declarations?.[0]; + let im = imp; while (im && !ts.isImportDeclaration(im) && !ts.isImportEqualsDeclaration(im)) im = im.parent; + if (im && ts.isImportDeclaration(im) && !isProjectSpec(im.moduleSpecifier.text, sf.fileName)) f.push('librt'); + if (im && ts.isImportEqualsDeclaration(im)) f.push('librt?'); + if (im && ts.isImportDeclaration(im) && decl) { + const r2 = resolveSpec(im.moduleSpecifier.text, sf.fileName); + if (r2 && path.resolve(r2.resolvedFileName) !== path.resolve(decl.getSourceFile().fileName)) f.push('reexport'); + } + } + for (const d of (s && !(s.flags & ts.SymbolFlags.Alias) ? s.declarations : []) || []) { + if (ts.isVariableDeclaration(d) && d.initializer && /import\(/.test(d.initializer.getText())) f.push('dynimport'); + const direct = ce === r; // the callee IS the identifier: a function value is called + if (ts.isParameter(d)) f.push(direct ? 'param' : 'recv-param'); + if (ts.isParameter(d) && !d.type && (ts.isArrowFunction(d.parent) || ts.isFunctionExpression(d.parent)) + && d.parent.parent && (ts.isCallExpression(d.parent.parent) || ts.isNewExpression(d.parent.parent))) f.push('ctxparam'); + if (ts.isBindingElement(d)) f.push(direct ? 'destructured' : 'recv-destructured'); + let vd = d; while (vd && !ts.isVariableDeclaration(vd) && !ts.isParameter(vd)) vd = vd.parent; + if (vd && ts.isVariableDeclaration(vd) && vd.initializer && /(^|\W)(c|ctx|context)\.(get|var)\b|\bc\.env\b/.test(vd.initializer.getText().slice(0, 200))) f.push('ctxdi'); + if (ts.isVariableDeclaration(d) && d.initializer && /\brequire\(\s*['"][^.\/]/.test(d.initializer.getText())) f.push('librt'); + if (ts.isVariableDeclaration(d) && d.initializer && /\brequire\(/.test(d.initializer.getText())) f.push('require'); + } + } + return [...new Set(f)]; +} +const edgeSeen = new Map(); +function addEdge(caller, calleeNode, kind, site, feats) { + const k = `${caller}\t${loc(calleeNode)}\t${kind}\t${loc(site)}`; + if (edgeSeen.has(k)) return; + edgeSeen.set(k, 1); + emit('edge', caller, loc(calleeNode), kind, loc(site), feats.join(',')); +} +const libName = d => { + const f = path.resolve(d.getSourceFile().fileName); + const m = f.match(/node_modules\/((?:@[^/]+\/)?[^/]+)/); + return m ? m[1] : (f.includes('/typescript/lib/') ? 'ts-lib' : (f.endsWith('.d.ts') ? 'dts:' + rel(f) : 'other')); +}; +function classify(node, caller, calleeExpr, kind) { + // R21 (hono torture chains/): a function read out of a table or an array by ELEMENT ACCESS. The compiler names one + // declaration even when several are possible (functions of one signature collapse into one type), so its answer + // is kept only for a literal key on an object; a key the program does not decide is `dynkey`, and an element of a + // (non-tuple) array is `arrayelem`: both unresolved here, left to the run-time trace + let cx = calleeExpr; + while (cx && (ts.isParenthesizedExpression(cx) || ts.isNonNullExpression(cx) || ts.isAsExpression(cx))) cx = cx.expression; + if (cx && ts.isElementAccessExpression(cx)) { + let kt, ot; try { kt = checker.getTypeAtLocation(cx.argumentExpression); ot = checker.getTypeAtLocation(cx.expression); } catch { } + const lit = kt && (kt.flags & (ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral)); + const arr = ot && checker.isArrayType && checker.isArrayType(ot); + if (!lit || arr) { emit('unres', caller, loc(node), lit ? 'arrayelem' : 'dynkey', short(calleeExpr), siteFeats(node, calleeExpr).join(',')); return; } + } + let sig; try { sig = checker.getResolvedSignature(node); } catch { sig = undefined; } + let d = sig?.declaration; + const feats = siteFeats(node, calleeExpr); + if (!d) { + if (ts.isNewExpression(node)) { + // implicit constructor: the class declares none; nothing in project code runs except field initialisers + let s; try { s = resolveSym(checker.getSymbolAtLocation(node.expression)); } catch { } + const cd = s?.declarations?.find(x => ts.isClassLike(x)); + if (cd && isSrcDecl(cd)) return; // no body to enter + if (cd) { emit('lib', caller, loc(node), libName(cd), short(node.expression)); return; } + } + let t; try { t = checker.getTypeAtLocation(calleeExpr || node); } catch { } + const reason = !t ? 'notype' : (t.flags & ts.TypeFlags.Any) ? 'any' : (t.flags & ts.TypeFlags.Unknown) ? 'unknown' : 'nosig'; + emit('unres', caller, loc(node), reason, short(calleeExpr || node), feats.join(',')); + return; + } + if (!isSrcDecl(d)) { emit('lib', caller, loc(node), libName(d), short(calleeExpr || node)); return; } + if (ts.isJSDocSignature?.(d) || ts.isFunctionTypeNode(d) || ts.isCallSignatureDeclaration(d) || ts.isConstructorTypeNode(d) || ts.isJSDocFunctionType?.(d)) { + emit('unres', caller, loc(node), 'fnvalue', short(calleeExpr || node), feats.join(',')); return; + } + const isAbstract = (ts.isMethodDeclaration(d) && !d.body) || ts.isMethodSignature(d) || ts.isPropertySignature(d) || ts.isConstructSignatureDeclaration?.(d); + if (isAbstract) { + const impls = implsOf(d); + if (!impls.length) { emit('unres', caller, loc(node), 'iface-noimpl', short(calleeExpr || node), [...feats, 'iface'].join(',')); return; } + for (const m of impls) addEdge(caller, m, 'impl', node, [...feats, 'iface']); + return; + } + if (isFnNode(d)) { + addEdge(caller, d, kind, node, feats); + if (ts.isMethodDeclaration(d)) for (const m of implsOf(d)) addEdge(caller, m, 'virt', node, [...feats, 'virt']); + return; + } + if (ts.isFunctionDeclaration(d) && !d.body) { // overload signature: the implementation is the body sibling + const impl = d.parent && (d.parent.statements || []).find(x => ts.isFunctionDeclaration(x) && x.body && x.name?.text === d.name?.text); + if (impl) { addEdge(caller, impl, kind, node, feats); return; } + } + emit('unres', caller, loc(node), 'decl:' + ts.SyntaxKind[d.kind], short(calleeExpr || node), feats.join(',')); +} +for (const sf of srcFiles) { + emit('fn', modKey(sf), 'MODULE', '', sf.getLineAndCharacterOfPosition(sf.getEnd()).line + 1); + const visit = (node) => { + if (isFnNode(node)) { + emit('fn', loc(node), ts.SyntaxKind[node.kind], fnName(node), endLine(node)); + // a function handed over as an argument: the enclosing function passes it (callback / higher-order hop) + const p = node.parent; + if ((ts.isCallExpression(p) || ts.isNewExpression(p)) && (p.arguments || []).includes(node)) + addEdge(callerKey(node), node, 'closure', p, siteFeats(p, p.expression)); + } + // a function REFERENCE handed over as an argument (app.get('/', handler), arr.map(this.f)) + if ((ts.isCallExpression(node) || ts.isNewExpression(node)) && node.arguments) { + for (const a of node.arguments) { + if (!(ts.isIdentifier(a) || ts.isPropertyAccessExpression(a))) continue; + let s; try { s = resolveSym(checker.getSymbolAtLocation(ts.isIdentifier(a) ? a : a.name)); } catch { } + for (const d of s?.declarations || []) { + let fnD = isFnNode(d) ? d : (ts.isVariableDeclaration(d) && d.initializer && isFnNode(d.initializer) ? d.initializer : null); + if (fnD && isSrcDecl(fnD)) addEdge(callerKey(node), fnD, 'fnref', node, siteFeats(node, node.expression)); + } + } + } + if (ts.isCallExpression(node)) { + if (node.expression.kind !== ts.SyntaxKind.ImportKeyword) + classify(node, callerKey(node), node.expression, 'call'); + } else if (ts.isNewExpression(node)) classify(node, callerKey(node), node.expression, 'new'); + else if (ts.isDecorator(node)) classify(node, callerKey(node), node.expression, 'deco'); + else if (ts.isTaggedTemplateExpression(node)) classify(node, callerKey(node), node.tag, 'tag'); + ts.forEachChild(node, visit); + }; + ts.forEachChild(sf, visit); +} + +// ── package entry exports (non-HTTP entries): each workspace package's entry module ── +for (const [pkgName, d] of workspace) { + let ent = exportsTarget(d, ''); + if (!ent) for (const c of ['src/index.ts', 'index.ts', 'src/index.js', 'index.js', 'lib/index.js']) if (fs.existsSync(path.join(d, c))) { ent = path.join(d, c); break; } + if (!ent) { try { const mn = JSON.parse(fs.readFileSync(path.join(d, 'package.json'), 'utf8')).main; if (mn && fs.existsSync(path.join(d, mn))) ent = path.join(d, mn); } catch { } } + if (!ent) continue; + const sf = program.getSourceFile(ent) || program.getSourceFiles().find(x => path.resolve(x.fileName) === path.resolve(ent)); + if (!sf || !srcFiles.includes(sf)) continue; + const ms = checker.getSymbolAtLocation(sf); if (!ms) continue; + for (const ex of checker.getExportsOfModule(ms)) { + const s = resolveSym(ex); + for (const dd of s?.declarations || []) { + if (!isSrcDecl(dd)) continue; + if (isFnNode(dd)) emit('pkgexport', loc(dd), pkgName, ex.name); + else if (ts.isVariableDeclaration(dd) && dd.initializer && isFnNode(dd.initializer)) emit('pkgexport', loc(dd.initializer), pkgName, ex.name); + else if (ts.isClassDeclaration(dd)) for (const m of dd.members) { + const fl = ts.getCombinedModifierFlags(m); + if (isFnNode(m) && !(fl & (ts.ModifierFlags.Private | ts.ModifierFlags.Protected)) && !(m.name && ts.isPrivateIdentifier(m.name))) + emit('pkgexport', loc(m), pkgName, ex.name + '.' + (memberName(m) || 'constructor')); + } + } + } +} +process.stdout.write(rows.join('\n') + '\n'); +process.stderr.write(`cc-oracle: ${srcFiles.length} files, ${rows.length} rows, ${((Date.now() - T0) / 1000).toFixed(1)}s\n`); diff --git a/graph/test/typescript/hono/truth/chain-runtime.mjs b/graph/test/typescript/hono/truth/chain-runtime.mjs new file mode 100644 index 000000000..cbe1c2963 --- /dev/null +++ b/graph/test/typescript/hono/truth/chain-runtime.mjs @@ -0,0 +1,161 @@ +#!/usr/bin/env node +// ───────────────────────────────────────────────────────────────────────────── +// Hono torture oracle: the RUNTIME half for call CHAINS (chains/ suite). +// +// The fixture is copied, every call site and function is instrumented by the repository's TypeScript runtime +// oracle (../../runtime-oracle/instrument.mjs + runtime.cjs: each call site records the declaration that actually +// ran), every module that exports a Hono app is loaded with the pinned `hono`, and each `chain` row's request is +// sent to every exported app with `app.request(path, { method })`. The observed edges are +// (function enclosing the site -> function entered); a framework hop such as middleware -> handler is observed too, +// because the handler is entered from the middleware's own `await next()` site. +// +// usage: node chain-runtime.mjs [--edges] [--routes ] [--requests ] +// A `body VERB PATH JSON` row of the chains file sends that JSON body (content-type application/json) with that request. +// stdout: `runtime chains over ` | `runtime skip `; one `rtedge FROM TO` line per +// observed project edge with --edges; exit 1 when a hop of a chain row was not observed, or an `edge .. rt` row of +// the golden was not observed. +// ───────────────────────────────────────────────────────────────────────────── +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const RT = path.resolve(HERE, '../../runtime-oracle'); +const SRC = path.resolve(process.argv[2]); +const CHAINS = fs.readFileSync(process.argv[3], 'utf8').split('\n').filter(l => l && !l.startsWith('#')).map(l => l.split('\t')); +const EDGES = process.argv.includes('--edges'); +// --routes : also request every route the static oracle lists (a sample value per parameter), so +// the trace covers every handler, not only the chains the golden names +const RI = process.argv.indexOf('--routes'); +const ROUTES = RI > 0 ? fs.readFileSync(process.argv[RI + 1], 'utf8').split('\n').map(l => l.split('\t')).filter(r => r[0] === 'route') : []; +const sample = p => p.split('/').map(s => s.startsWith(':') ? 'x1' : s === '*' ? 'x' : s).join('/') || '/'; + +const chains = CHAINS.filter(r => r[0] === 'chain' && r[2] !== '-'); +const rtEdges = CHAINS.filter(r => r[0] === 'edge' && r[3] === 'rt'); +if (!chains.length && !rtEdges.length && !ROUTES.length && !(process.argv.includes('--requests') && fs.existsSync(process.argv[process.argv.indexOf('--requests') + 1]))) { console.log('runtime skip no chain with a request'); process.exit(0); } + +const W = fs.mkdtempSync(path.join(os.tmpdir(), 'hono-chain-')); +const cleanup = () => { try { fs.rmSync(W, { recursive: true, force: true }); } catch { } }; +fs.cpSync(SRC, W, { recursive: true }); +const realW = fs.realpathSync(W); +// a JavaScript fixture (the JS twin suite): the repository's runtime instrumenter rewrites TypeScript files only, so +// each `.js` is traced as a `.ts` of the same text (JavaScript is TypeScript syntax; node strips no types from it, +// and runtime-hooks.mjs resolves `./x.js` to `./x.ts`); every key is spelled back with `.js` below +const renamed = new Set(); +(function toTs(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) toTs(p); + else if (e.name.endsWith('.js')) { const t = p.replace(/\.js$/, '.ts'); fs.renameSync(p, t); renamed.add(path.relative(realW, t).split(path.sep).join('/')); } + } +})(realW); +const unTs = rel => renamed.has(rel) ? rel.replace(/\.ts$/, '.js') : rel; +const T = path.join(realW, '.ax-tables'); +fs.mkdirSync(T); +const ins = spawnSync(process.execPath, [path.join(RT, 'instrument.mjs'), '--src', realW, '--out', realW, '--tables', T], { encoding: 'utf8' }); +if (ins.status !== 0) { console.log(`runtime skip instrumenter failed: ${(ins.stderr || '').split('\n')[0]}`); cleanup(); process.exit(0); } +// the pinned packages are linked AFTER instrumenting: library code is never rewritten +fs.symlinkSync(path.join(HERE, 'node_modules'), path.join(realW, 'node_modules')); +if (!fs.existsSync(path.join(realW, 'package.json'))) fs.writeFileSync(path.join(realW, 'package.json'), '{"type":"module"}'); + +const files = []; +(function walk(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) walk(p); else if (/\.(ts|mts|js|mjs)$/.test(e.name) && !e.name.endsWith('.d.ts') && !/(\.test\.|\.spec\.|client)/.test(e.name)) files.push(p); + } +})(realW); +// `body VERB PATH JSON` rows: the request carries that JSON body (a route behind a json validator is only entered +// when the body passes it); every other request has none +// --requests : the --edges run (no chains file) also sends that file's chain requests, with its bodies; +// a partial route is in no `route` row, so its chain's request is the only one that reaches it +const QI = process.argv.indexOf('--requests'); +const QROWS = QI > 0 && fs.existsSync(process.argv[QI + 1]) ? fs.readFileSync(process.argv[QI + 1], 'utf8').split('\n').filter(l => l && !l.startsWith('#')).map(l => l.split('\t')) : []; +const bodies = new Map([...CHAINS, ...QROWS].filter(r => r[0] === 'body').map(r => [`${r[1]}\t${r[2]}`, r.slice(3).join('\t')])); +const requests = [...new Set([...[...chains, ...QROWS.filter(r => r[0] === 'chain' && r[2] !== '-')].map(r => `${r[2]}\t${r[3]}`), + ...ROUTES.filter(r => r[1] !== 'ANY').map(r => `${r[1]}\t${sample(r[2])}`)])]; +const driver = ` +import { register } from 'node:module'; +import { pathToFileURL } from 'node:url'; +register(${JSON.stringify(pathToFileURL(path.join(HERE, 'runtime-hooks.mjs')).href)}); +// the tracer runtime (CommonJS) is loaded by a dynamic import, which runs it exactly as a require would +await import(${JSON.stringify(pathToFileURL(path.join(RT, 'runtime.cjs')).href)}); +const { HonoBase } = await import(${JSON.stringify(pathToFileURL(path.join(HERE, 'node_modules/hono/dist/hono-base.js')).href)}); +const apps = new Set(); let err = null; +for (const f of ${JSON.stringify(files.sort())}) { + try { const ns = await import(pathToFileURL(f).href); for (const v of Object.values(ns)) if (v instanceof HonoBase) apps.add(v); } + catch (e) { err = f + ': ' + String(e.message || e).split('\\n')[0]; } +} +if (!apps.size) { console.log('NOAPP ' + (err || '')); } +const bodies = ${JSON.stringify(Object.fromEntries(bodies))}; +for (const rq of JSON.parse(process.env.AX_REQUESTS)) { + const [method, p] = rq.split('\\t'); + const init = rq in bodies ? { method, body: bodies[rq], headers: { 'content-type': 'application/json' } } : { method }; + for (const app of apps) { try { await app.request(p, init); } catch (e) { console.log('REQERR ' + p + ' ' + e.message); } } +} +globalThis.__axFlush && globalThis.__axFlush(); +`; +fs.writeFileSync(path.join(realW, '.ax-driver.mjs'), driver); +// one traced process per call: `requests` in order, each to every exported app; a fresh trace dir per call +let nrun = 0; +const traceRun = (rqs) => { + const out = path.join(realW, `.ax-trace${nrun++}`); fs.mkdirSync(out); + const run = spawnSync(process.execPath, [path.join(realW, '.ax-driver.mjs')], { cwd: realW, encoding: 'utf8', env: { ...process.env, AX_TRACE_OUT: out, AX_REQUESTS: JSON.stringify(rqs) } }); + const noapp = (run.stdout || '').split('\n').find(l => l.startsWith('NOAPP')); + if (run.status !== 0 || noapp) return { skip: noapp ? noapp.slice(6) : (run.stderr || '').split('\n').find(Boolean) }; + return { out }; +}; +const first = traceRun(requests); +if (first.skip !== undefined) { console.log(`runtime skip not loadable (${first.skip})`); cleanup(); process.exit(0); } + +// id tables -> `::` keys, the same spelling as the static oracles +const tsv = f => fs.readFileSync(path.join(T, f), 'utf8').split('\n').slice(1).filter(Boolean).map(l => l.split('\t')); +const relOf = f => unTs(path.relative(realW, path.resolve(realW, f)).split(path.sep).join('/')); +const declKey = new Map(tsv('decls.tsv').map(r => [r[0], `${relOf(r[1])}:${r[2]}:${r[3]}`])); +const siteFrom = new Map(tsv('sites.tsv').map(r => [r[0], r[8]])); +const siteLoc = new Map(tsv('sites.tsv').map(r => [r[0], `${relOf(r[1])}:${r[2]}:${r[3]}`])); +// a function expression handed over as an argument at a site in FROM (callbacks.tsv): when the host runs it later +// (a promise continuation, a timer) no site is open, so it is entered `unlinked`; the hop FROM -> it is then +// observed as "handed over by FROM, and ran" +const handed = new Set(tsv('callbacks.tsv').map(r => `${declKey.get(siteFrom.get(r[0]))}\t${declKey.get(r[1])}`)); +const readTrace = (out) => { + const t = { seen: new Set(), seenAt: new Set(), entered: new Set(), unlinked: new Set() }; + for (const f of fs.readdirSync(out)) for (const l of fs.readFileSync(path.join(out, f), 'utf8').split('\n')) { + const c = l.split('\t'); + if (c[0] === 'unlinked' || c[0] === 'pair') { const d = declKey.get(c[2]); if (d) { t.entered.add(d); if (c[0] === 'unlinked') t.unlinked.add(d); } } + if (c[0] !== 'pair') continue; + const from = declKey.get(siteFrom.get(c[1])), to = declKey.get(c[2]); + if (from && to) { t.seen.add(`${from}\t${to}`); t.seenAt.add(`${from}\t${to}\t${siteLoc.get(c[1])}`); } + } + return t; +}; +const { seen, seenAt, entered, unlinked } = readTrace(first.out); +// with the call site: a callback a LIBRARY invokes (`xs.map(cb)`) is attributed to whatever site is open, so the +// checker keeps a run-time edge only at a site the compiler itself could not resolve +if (EDGES) for (const e of [...seenAt].sort()) console.log(`rtedge\t${e}`); +const bad = []; +let hops = 0, viaLib = 0; +for (const r of chains) { + const fns = r.slice(4); + let alone = null; + for (let i = 0; i + 1 < fns.length; i++) { + hops++; const k = `${fns[i]}\t${fns[i + 1]}`; + if (seen.has(k) || (handed.has(k) && entered.has(fns[i + 1]))) continue; + // a hop through LIBRARY code that awaits before it continues (a json validator reads the body, then calls + // next): no project site is open when the next function is entered, so it is `unlinked`. It is observed when a + // process that sends ONLY this chain's request runs both functions, the second entered from library code. + if (unlinked.has(fns[i + 1])) { + if (!alone) { const t = traceRun([`${r[2]}\t${r[3]}`]); alone = t.out ? readTrace(t.out) : { entered: new Set(), unlinked: new Set() }; } + if (alone.entered.has(fns[i]) && alone.unlinked.has(fns[i + 1])) { viaLib++; continue; } + } + bad.push(`chain ${r[1]} hop ${i}: ${fns[i]} -> ${fns[i + 1]} not observed at run time`); + } +} +for (const r of rtEdges) if (!seen.has(`${r[1]}\t${r[2]}`)) bad.push(`edge ${r[1]} -> ${r[2]} (rt) not observed at run time`); +cleanup(); +if (bad.length) { for (const b of bad) console.log(`runtime DISAGREES ${b}`); process.exit(1); } +console.log(`runtime chains ${hops} hops over ${chains.length} chains, ${rtEdges.length} rt edges${viaLib ? `, ${viaLib} hops entered from library code in a one-request run` : ''}`); diff --git a/graph/test/typescript/hono/truth/deno-shims/deno.d.ts b/graph/test/typescript/hono/truth/deno-shims/deno.d.ts new file mode 100644 index 000000000..8181be2d6 --- /dev/null +++ b/graph/test/typescript/hono/truth/deno-shims/deno.d.ts @@ -0,0 +1,8 @@ +// The slice of the Deno runtime's global API a Hono-on-Deno fixture uses, so the oracle can typecheck it +// under the TypeScript compiler (no Deno toolchain is involved; the shapes follow Deno's own declarations). +declare namespace Deno { + type ServeHandler = (request: Request, info?: unknown) => Response | Promise + function serve(handler: ServeHandler): unknown + function serve(options: { port?: number; hostname?: string }, handler: ServeHandler): unknown + const env: { get(key: string): string | undefined } +} diff --git a/graph/test/typescript/hono/truth/deno-shims/middleware.d.ts b/graph/test/typescript/hono/truth/deno-shims/middleware.d.ts new file mode 100644 index 000000000..1f52edf05 --- /dev/null +++ b/graph/test/typescript/hono/truth/deno-shims/middleware.d.ts @@ -0,0 +1,7 @@ +// `https://deno.land/x/hono@v3.x/middleware.ts` re-exported every built-in middleware from one module. +export { cors } from 'hono/cors' +export { logger } from 'hono/logger' +export { etag } from 'hono/etag' +export { secureHeaders } from 'hono/secure-headers' +export { basicAuth } from 'hono/basic-auth' +export { jwt } from 'hono/jwt' diff --git a/graph/test/typescript/hono/truth/hono-oracle.mjs b/graph/test/typescript/hono/truth/hono-oracle.mjs new file mode 100644 index 000000000..a2715ceb7 --- /dev/null +++ b/graph/test/typescript/hono/truth/hono-oracle.mjs @@ -0,0 +1,1918 @@ +#!/usr/bin/env node +// ───────────────────────────────────────────────────────────────────────────── +// Hono torture oracle: the STATIC half of the ground truth. +// +// Independent of the engine by construction: it uses the TypeScript compiler API and the +// real `hono` package pinned in ./package.json (never the axiom parser, never the IR). It +// walks every registration in PROGRAM ORDER and replays Hono's own semantics, as read from +// hono-base.js of the pinned version: +// +// - `new Hono()` / `new OpenAPIHono()` (the class must be DECLARED in the pinned package; +// a local class that happens to be called Hono is not an app); +// - `basePath(p)` returns a clone that SHARES the route list, with base = mergePath(base, p); +// - a verb / `all` / `on` / `use` registers one entry per handler, `use` with method ALL and +// default path `*`, a path-less verb continues the instance's last path; +// - `route(p, sub)` COPIES sub's entries present AT THAT MOMENT under mergePath(base, p); +// - `mount(p, fetch)` registers ALL mergePath(base, p, '*') to a foreign handler. +// +// Which middleware applies to which handler is decided by Hono's OWN router (SmartRouter of +// the pinned package) matched against a concrete sample of the handler's path, in +// registration order: never by a re-implementation of the pattern language. +// +// usage: node hono-oracle.mjs [--json] +// Output (TSV on stdout, one relation per first column; locations are +// `::` of the function node, 1-based): +// route VERB FULLPATH HANDLER APP ORDER +// mw MW HANDLER ORDER (ORDER = position in the handler's middleware chain) +// entry FN http +// ctx SETTER_FN READER_FN KEY +// rpc FROM_FN VERB PATH HANDLER +// request FROM_FN VERB PATH HANDLER +// mount PATH TARGET +// unknown SITE REASON +// Exit 2 (refusal) when the program does not typecheck: an unscored case is not a pass. +// ───────────────────────────────────────────────────────────────────────────── +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +// the compiler is the oracle's OWN pinned one, reached through the suite's shared loader (version-guarded) +const { loadTypeScript } = await import(new URL('../../ground-truth/load-typescript.mjs', import.meta.url).href); +const ts = loadTypeScript(HERE, { toolName: 'hono-oracle' }); +const NM = path.join(HERE, 'node_modules'); +const { SmartRouter } = await import(path.join(NM, 'hono/dist/router/smart-router/index.js')); +const { RegExpRouter } = await import(path.join(NM, 'hono/dist/router/reg-exp-router/index.js')); +const { TrieRouter } = await import(path.join(NM, 'hono/dist/router/trie-router/index.js')); + +const SRC = path.resolve(process.argv[2] || '.'); +const NO_TYPECHECK = process.argv.includes('--no-typecheck'); +const STORES = process.argv.includes('--stores'); +// --partial-paths (hono-7-05): also print `ppath HANDLER VERB KNOWNPATH` for a route under a dynamic mount prefix, +// the composed path with `{}` for each piece the program does not show (SPEC 3.2 KnownPath). Opt-in per case (a +// `partial-paths` file in the case dir), so the partial rows of every other golden are unchanged +const PARTIAL_PATHS = process.argv.includes('--partial-paths'); +const DEBUG = !!process.env.HONO_ORACLE_DEBUG; +const T0 = Date.now(); +const phase = name => { if (DEBUG) process.stderr.write(`phase ${name} at ${((Date.now() - T0) / 1000).toFixed(1)}s\n`); }; + +// ── program ───────────────────────────────────────────────────────────────── +const EXT = /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/; +function walkDir(d, out = []) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) walkDir(p, out); + else if (EXT.test(e.name) && !e.name.endsWith('.d.ts')) out.push(p); + } + return out; +} +const files = walkDir(SRC).sort(); +const options = { + target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext, + moduleResolution: ts.ModuleResolutionKind.Bundler, strict: true, allowJs: true, checkJs: false, + noEmit: true, skipLibCheck: true, esModuleInterop: true, resolveJsonModule: true, + jsx: ts.JsxEmit.ReactJSX, jsxImportSource: 'hono/jsx', types: [], lib: ['lib.es2022.d.ts', 'lib.dom.d.ts'], + allowImportingTsExtensions: true, +}; +const host = ts.createCompilerHost(options, true); +const ANCHOR = path.join(HERE, 'anchor.ts'); // resolve bare packages from the oracle's own node_modules +// ── Deno: an import map (deno.json / deno.jsonc / import_map.json `imports`, exact and prefix keys) and +// jsr: / npm: / deno.land URL specifiers, each mapped to the PINNED package of the same name. This is a +// module-resolution host for the oracle only; it says nothing about how the engine should resolve them. +// every deno.json / deno.jsonc / import_map.json in the fixture (a Deno project need not sit at the root) +const denoCfgs = []; +(function scanDeno(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) scanDeno(p); else if (['deno.json', 'deno.jsonc', 'import_map.json'].includes(e.name)) denoCfgs.push(p); + } +})(SRC); +const DENO_CFG = denoCfgs.length > 0; +let importMap = {}; +for (const f of denoCfgs) { + try { + const j = JSON.parse(fs.readFileSync(f, 'utf8').replace(/^\s*\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '')); + importMap = { ...importMap, ...(j.imports || {}) }; + const im = j.importMap && path.join(path.dirname(f), j.importMap); + if (im && fs.existsSync(im)) importMap = { ...importMap, ...JSON.parse(fs.readFileSync(im, 'utf8')).imports }; + } catch { } +} +function canonicalSpec(spec) { + if (importMap[spec]) spec = importMap[spec]; + else { + const k = Object.keys(importMap).filter(k => k.endsWith('/') && spec.startsWith(k)).sort((a, b) => b.length - a.length)[0]; + if (k) spec = importMap[k] + spec.slice(k.length); + } + let m; + if ((m = spec.match(/^jsr:\/?@hono\/hono(?:@[^/]*)?(\/.*)?$/)) || (m = spec.match(/^@hono\/hono(\/.*)?$/))) return 'hono' + (m[1] || ''); + if ((m = spec.match(/^npm:\/?((?:@[^/@]+\/)?[^/@]+)(?:@[^/]*)?(\/.*)?$/))) return m[1] + (m[2] || ''); + if ((m = spec.match(/^jsr:\/?(@hono\/[^/@]+)(?:@[^/]*)?(\/.*)?$/))) return m[1] + (m[2] || ''); + if ((m = spec.match(/^https:\/\/deno\.land\/x\/hono(?:@[^/]*)?\/(.*)$/))) { + if (m[1] === 'mod.ts') return 'hono'; + if (m[1] === 'middleware.ts') return path.join(HERE, 'deno-shims', 'middleware.d.ts'); + return 'hono/' + m[1].replace(/^middleware\//, '').replace(/\/index\.ts$|\.ts$/, ''); + } + return spec; +} +const libLabel = ms => { const c = canonicalSpec(ms); return c.startsWith('/') ? 'hono/middleware' : c; }; +// tsconfig `paths` / `baseUrl` of the nearest tsconfig.json above the importing file (inside the fixture): +// an aliased project import (`@/lib/app`) resolves to the project file, as the project's compiler would +const _pathsCache = new Map(); +function pathsOpts(containing) { + let d = path.dirname(path.resolve(containing)); + const seen = []; + while (d.startsWith(SRC)) { + if (_pathsCache.has(d)) { const v = _pathsCache.get(d); seen.forEach(x => _pathsCache.set(x, v)); return v; } + seen.push(d); + const f = path.join(d, 'tsconfig.json'); + if (fs.existsSync(f)) { + let v = null; + try { + const cf = ts.readConfigFile(f, ts.sys.readFile); + const pc = ts.parseJsonConfigFileContent(cf.config || {}, ts.sys, d); + if (pc.options.paths || pc.options.baseUrl) v = { paths: pc.options.paths, baseUrl: pc.options.baseUrl, pathsBasePath: pc.options.pathsBasePath || d }; + } catch { v = null; } + seen.forEach(x => _pathsCache.set(x, v)); return v; + } + const up = path.dirname(d); if (up === d) break; d = up; + } + seen.forEach(x => _pathsCache.set(x, null)); return null; +} +// workspace packages: a package.json with a name anywhere in the fixture (not under node_modules) makes +// `` and `/` resolve to that package's files, as a workspace install links them +const workspace = new Map(); +(function scanWs(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) scanWs(p); + else if (e.name === 'package.json') { try { const n = JSON.parse(fs.readFileSync(p, 'utf8')).name; if (n) workspace.set(n, d); } catch { } } + } +})(SRC); +function exportsTarget(d, sub) { + // package.json `exports`: "./sub" -> a string, or a conditions object (types / import / default) + try { + const ex = JSON.parse(fs.readFileSync(path.join(d, 'package.json'), 'utf8')).exports; + if (!ex) return null; + const key = sub ? './' + sub : '.'; + let t = typeof ex === 'string' && key === '.' ? ex : ex[key]; + // a subpath pattern (`"./*"`, `"./adapters/*"`) lists every subpath it matches: substitute the matched part + if (t === undefined && typeof ex === 'object') for (const [k, v] of Object.entries(ex)) { + const i = k.indexOf('*'); if (i < 0 || !key.startsWith(k.slice(0, i)) || !key.endsWith(k.slice(i + 1)) || key.length < k.length - 1) continue; + const m = key.slice(i, key.length - (k.length - i - 1)); + let vv = v; if (vv && typeof vv === 'object') vv = vv.types || vv.import || vv.default || vv.require; + if (typeof vv === 'string') { t = vv.split('*').join(m); break; } + } + if (t && typeof t === 'object') t = t.types || t.import || t.default || t.require; + if (typeof t !== 'string') return null; + // O3b: an export that points at an unbuilt output file (`./dist/x.js`, `./dist/x.d.ts`) is served from the + // package's source in a checkout: the same path under src/, with a source extension + if (!fs.existsSync(path.join(d, t))) { + const stem = t.replace(/^\.?\//, '').replace(/^(dist|build|out|lib)\//, '').replace(/\.d\.(ts|mts|cts)$|\.(js|mjs|cjs|ts|mts|cts)$/, ''); + for (const base of ['src/', '']) for (const ext of ['.ts', '.tsx', '.mts', '.js', '.mjs', '/index.ts', '/index.js']) { + const c = path.join(d, base + stem + ext); + if (fs.existsSync(c)) return c; + } + } + return path.join(d, t); + } catch { return null; } +} +// the moduleResolution of the program a file belongs to: its nearest tsconfig.json inside the fixture, else the oracle's +const _mrCache = new Map(); +function moduleResolutionOf(containing) { + let d = path.dirname(path.resolve(containing)); + while (d.startsWith(SRC)) { + if (_mrCache.has(d)) return _mrCache.get(d); + const f = path.join(d, 'tsconfig.json'); + if (fs.existsSync(f)) { + let v = options.moduleResolution; + try { const pc = ts.parseJsonConfigFileContent(ts.readConfigFile(f, ts.sys.readFile).config || {}, ts.sys, d); v = ts.getEmitModuleResolutionKind(pc.options); } catch { } + _mrCache.set(d, v); return v; + } + const up = path.dirname(d); if (up === d) break; d = up; + } + return options.moduleResolution; +} +function workspaceOpts(spec, containing) { + for (const [n, d] of workspace) if (spec === n || spec.startsWith(n + '/')) { + const sub = spec === n ? '' : spec.slice(n.length + 1); + const t = exportsTarget(d, sub); + if (t) return { baseUrl: d, paths: { [spec]: [t] }, pathsBasePath: d }; + // SPEC R22a: a package whose `exports` does not list this subpath resolves only where the TypeScript compiler + // resolves it. node10 ignores `exports` and reads the package directory itself; bundler, node16 and nodenext + // enforce `exports`, so the import is unbound (no synthetic `src/` paths for it) + let hasExports = false; + try { hasExports = JSON.parse(fs.readFileSync(path.join(d, 'package.json'), 'utf8')).exports !== undefined; } catch { } + if (hasExports) { + const mr = containing ? moduleResolutionOf(containing) : options.moduleResolution; + if (mr !== ts.ModuleResolutionKind.Node10 && mr !== ts.ModuleResolutionKind.Classic) return null; + return { baseUrl: d, moduleResolution: ts.ModuleResolutionKind.Node10, paths: { [spec]: [sub ? path.join(d, sub) : d] }, pathsBasePath: d }; + } + return { baseUrl: d, paths: { [n]: [d, path.join(d, 'src')], [n + '/*']: [path.join(d, '*'), path.join(d, 'src', '*')] }, pathsBasePath: d }; + } + return null; +} +// ONE resolver for every project-side lookup (program building, module order, require), so a module the +// program contains is never evaluated out of order because a second lookup could not find it +function resolveSpec(rawSpec, containing, opts = options) { + const spec = canonicalSpec(rawSpec); + let r = ts.resolveModuleName(spec, containing, opts, host).resolvedModule; + if (!r && !spec.startsWith('.') && !spec.startsWith('/')) { + for (const po of [pathsOpts(containing), workspaceOpts(spec, containing)]) { + if (r || !po) continue; + r = ts.resolveModuleName(spec, containing, { ...opts, ...po }, host).resolvedModule; + if (r && r.isExternalLibraryImport) r = undefined; + } + if (!r) r = ts.resolveModuleName(spec, ANCHOR, opts, host).resolvedModule; + } + return r; +} +function isProjectSpec(spec, containing) { + if (spec.startsWith('.') || spec.startsWith('/')) return true; + const r = resolveSpec(spec, containing); + return !!(r && path.resolve(r.resolvedFileName).startsWith(SRC + path.sep) && !r.resolvedFileName.includes(`${path.sep}node_modules${path.sep}`)); +} +host.resolveModuleNameLiterals = (lits, containing, redirected, opts) => lits.map(lit => ({ resolvedModule: resolveSpec(lit.text, containing, opts) })); +const program = ts.createProgram(DENO_CFG ? [...files, path.join(HERE, 'deno-shims', 'deno.d.ts')] : files, options, host); +const checker = program.getTypeChecker();phase('program'); + +const srcFiles = program.getSourceFiles().filter(sf => path.resolve(sf.fileName).startsWith(SRC + path.sep)); + +if (!NO_TYPECHECK) { + const diags = ts.getPreEmitDiagnostics(program).filter(d => d.file && srcFiles.includes(d.file) + && !/\.(js|mjs|cjs|jsx)$/.test(d.file.fileName)); + if (diags.length) { + for (const d of diags.slice(0, 8)) { + const { line } = d.file.getLineAndCharacterOfPosition(d.start || 0); + process.stderr.write(`REFUSED (does not typecheck): ${path.relative(SRC, d.file.fileName)}:${line + 1} ${ts.flattenDiagnosticMessageText(d.messageText, ' ')}\n`); + } + process.exit(2); + } +} + +const rel = f => path.relative(SRC, path.resolve(f)).split(path.sep).join('/'); +const loc = n => { const sf = n.getSourceFile(); const p = sf.getLineAndCharacterOfPosition(n.getStart(sf)); return `${rel(sf.fileName)}:${p.line + 1}:${p.character + 1}`; }; +const inPkg = (decl, pkgs) => { const f = path.resolve(decl.getSourceFile().fileName); return pkgs.some(p => f.includes(`${path.sep}node_modules${path.sep}${p}${path.sep}`)); }; +const isSrcDecl = d => d && path.resolve(d.getSourceFile().fileName).startsWith(SRC + path.sep); + +// ── abstract values ───────────────────────────────────────────────────────── +// app: { k:'app', store, base, path, id } (a basePath clone shares store) +// str: { k:'str', v } +// fn: { k:'fn', node } user function +// libfn: { k:'libfn', name, site } a function a library call produced (cors(), zValidator()) +// list: { k:'list', items } createHandlers(...), arrays +// route: { k:'routedef', method, path } createRoute({...}) +// client: { k:'client', app, segs } hc() / testClient(app) and its property paths +// factory:{ k:'factory' } +// obj: { k:'obj', props: Map } +// unk: { k:'unk', why } +const UNK = why => ({ k: 'unk', why }); +// undef: { k:'undef' } a property an object literal the program shows does not have +// (`input.routes` when definePlugin was given `{ id, register }`): a loop over it runs no times, `x ?? y` is y. +// Only for a CLOSED literal (no unknown spread, no computed or accessor member) and a property name that no +// assignment `a. = ..` anywhere in the program writes; otherwise unknown, as before +const UNDEF = { k: 'undef' }; +let storeSeq = 0, entrySeq = 0, altSeq = 0, mountSeq = 0; +const stores = []; +function newApp(node) { + const store = { id: ++storeSeq, entries: [], mounted: false, origin: loc(node), notFound: null, onError: null }; + stores.push(store); + return { k: 'app', store, base: '/', path: '/', origin: store.origin }; +} +// mergePath, transcribed from hono/dist/utils/url.js of the pinned version +function mergePath(base, sub, ...rest) { + if (rest.length) sub = mergePath(sub, ...rest); + return `${base?.[0] === '/' ? '' : '/'}${base}${sub === '/' ? '' : `${base?.at(-1) === '/' ? '' : '/'}${sub?.[0] === '/' ? sub.slice(1) : sub}`}`; +} + +const out = { regby: new Set(), unserved: new Set(), partial: new Set(), ppath: new Set(), submount: [], route: [], mw: [], entry: new Set(), ctx: new Set(), rpc: new Set(), request: new Set(), unknown: new Set() }; +// unknown rows: SITE REASON FN (REASON from SPEC section 4's closed list; FN = the method it is attributed to) +const siteFn = new Map(); +function unknownAt(node, reason, fnKey) { out.unknown.add(`${loc(node)}\t${reason}\t${fnKey || enclosingFn(node)}`); } +const handlerKey = v => v.k === 'fn' ? loc(v.node) : v.k === 'libfn' ? `lib:${v.name}@${v.site}` : null; + +function lexicalCond(node) { + for (let n = node.parent; n && !ts.isFunctionLike(n) && !ts.isSourceFile(n); n = n.parent) { + if (ts.isForOfStatement(n) || ts.isForStatement(n) || ts.isForInStatement(n) || ts.isWhileStatement(n) || ts.isDoStatement(n)) return 'loop_registration'; + if (ts.isIfStatement(n) || ts.isConditionalExpression(n)) return 'conditional_registration'; + } + return null; +} +function addEntry(app, method, p, hv, kind, site, node) { + if (app.dyn && kind === 'mw' && p.k === 'str') { + // middleware on a rebased holder: kept aside for the routes later mounted into it (partialMount) + const hs0 = hv.k === 'list' ? hv.items : [hv]; + app.store.dynMws = app.store.dynMws || []; + for (const h of hs0) { + const k = handlerKey(h); + if (k) app.store.dynMws.push({ seq: ++entrySeq, method, path: p.v, key: k, kind, val: h, anyBase: p.v === '*' || p.v === '/*', alt: hv.k === 'alt' ? hv.alt : undefined }); + // a middleware the program cannot name (a loop over a run-time list) is a marker in the order, as on a root + else app.store.dynMws.push({ seq: ++entrySeq, method, path: p.v, key: null, kind: 'dyn', val: h, anyBase: p.v === '*' || p.v === '/*' }); + } + return; + } + if (app.dyn) { + if (kind === 'handler') { + const k = handlerKey(hv), V = method === 'ALL' ? 'ANY' : method; + out.partial.add(`${k}\t${V}\t${app.dyn}`); unknownAt(node, app.dyn, k); + // SPEC 3.3: a route registered straight on a rebased holder keeps its decidable chain: the holder's own + // middleware registered before it whose scope matches inside the holder (all its paths share the one unknown + // prefix); a run-time middleware list among them makes the chain dynamic_middleware_list + if (k && p.k === 'str') { + const before = (app.store.dynMws || []).filter(m => m.method === 'ALL' || m.method === method); + const router = new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] }); + before.forEach((m, j) => router.add(m.method, m.anyBase ? '*' : m.path, j)); + let matched; try { matched = new Set(router.match(method === 'ALL' ? 'GET' : method, samplePath(p.v))[0].map(x => x[0])); } catch { matched = new Set(); } + let at = -1, lastAlt, dynamic = false; + before.forEach((m, j) => { + if (!matched.has(j)) return; + if (m.kind === 'dyn') { dynamic = true; return; } + if (!(m.alt && m.alt === lastAlt)) at++; + lastAlt = m.alt; partialMw.add(`${m.key}\t${k}\t${V}\t${at}`); + }); + if (dynamic) out.unknown.add(`${loc(node)}\tdynamic_middleware_list\t${k}`); + } + } + return; + } + if (p.k !== 'str') { const k = handlerKey(hv); out.partial.add(`${k}\t${method === 'ALL' ? 'ANY' : method}\tdynamic_route_path`); unknownAt(node, 'dynamic_route_path', k); return; } + const full = mergePath(app.base, p.v); + const hs = hv.k === 'list' ? hv.items : hv.k === 'alt' ? hv.items : [hv]; + const alt = hv.k === 'alt' ? `a${++altSeq}` : undefined; + for (const h of hs) { + const key = handlerKey(h); + if (!key) { + // a middleware the program cannot name (a loop over a run-time list, a non-literal spread): a marker in the + // registration order, so every chain it may join is declared dynamic_middleware_list (SPEC 3.3, hono-1-06) + if (kind === 'mw') app.store.entries.push({ seq: ++entrySeq, method, path: full, key: null, kind: 'dyn', site, val: h }); + else unknownAt(node, 'unresolved_handler'); + continue; + } + app.store.entries.push({ seq: ++entrySeq, method, path: full, key, kind, site, val: h, regFn: node ? enclosingFn(node) : '?', alt, loopTag: loopTagNow() }); + if (h.k === 'fn') handlerFns.add(h.node); + // SPEC 3.1: a registration written inside a loop or behind a condition (lexically, within its own function) + const lc = condDepth && node ? lexicalCond(node) : null; + if (lc) unknownAt(node, lc, h.k === 'fn' ? key : undefined); + } +} + +// ── environment: values keyed by DECLARATION node ─────────────────────────── +const env = new Map(); +const evaluating = new Set(); +function declOf(id) { + let s = checker.getSymbolAtLocation(id); + if (!s) return null; + if (s.flags & ts.SymbolFlags.Alias) { try { s = checker.getAliasedSymbol(s); } catch { } } + return s.valueDeclaration || (s.declarations && s.declarations[0]) || null; +} +function valueOfDecl(d) { + if (!d) return UNK('no_declaration'); + if (env.has(d)) return env.get(d); + if (!isSrcDecl(d)) return { k: 'libdecl', decl: d }; + if (ts.isFunctionDeclaration(d) || ts.isFunctionExpression(d) || ts.isArrowFunction(d) || ts.isMethodDeclaration(d)) return { k: 'fn', node: d }; + if (ts.isVariableDeclaration(d) && d.initializer && !evaluating.has(d)) { + // lazily, for a const read before its module ran (memoised: no double registration) + evaluating.add(d); const v = evalExpr(d.initializer); evaluating.delete(d); env.set(d, v); return v; + } + if (ts.isBindingElement(d)) { + // `const { a } = ` / `const { a } = require('./m')`: the member of the evaluated initializer + const vd = d.parent && d.parent.parent; + if (vd && ts.isVariableDeclaration(vd) && vd.initializer && ts.isObjectBindingPattern(d.parent)) { + // O15: a destructured name whose initializer reads it back (through an object shorthand) is a cycle: + // the value is unknown, never a stack overflow + if (evaluating.has(d)) { noteCycle(d); return UNK('cycle'); } + evaluating.add(d); + let src; try { src = env.has(vd) ? env.get(vd) : evalExpr(vd.initializer); } finally { evaluating.delete(d); } + env.set(vd, src); // O30: the initializer is evaluated once per declaration, not once per destructured name + const prop = (d.propertyName || d.name).getText(); + let v = null; + if (src.k === 'obj' && src.props.has(prop)) { const p = src.props.get(prop); if (!p.val) p.val = evalExpr(p.node); v = p.val; } + else if (src.k === 'module') { const ed = moduleExportDecl(src.sf, prop); if (ed) v = valueOfDecl(ed); } // O16: `const { x } = await import('./m')` + // O15: memoised like a const (a call frame's own bindings are reset per call by inline), so a chain of + // destructures is evaluated once, not once per read + env.set(d, v || UNK('destructured')); + return env.get(d); + } + return UNK('destructured'); + } + if (ts.isPropertyAccessExpression(d) && d.parent && ts.isBinaryExpression(d.parent) && d.parent.left === d) return env.get(d.parent) ?? evalExpr(d.parent.right); // `module.exports.a = fn` + if (ts.isExportAssignment(d)) return env.get(d) ?? evalExpr(d.expression); + if (ts.isShorthandPropertyAssignment(d)) { const vs = checker.getShorthandAssignmentValueSymbol(d); return vs ? valueOfDecl(vs.valueDeclaration) : UNK('shorthand'); } + if (ts.isPropertyAssignment(d)) return evalExpr(d.initializer); + if (ts.isBinaryExpression(d)) return env.get(d) ?? evalExpr(d.right); + if (ts.isSourceFile(d)) return { k: 'module', sf: d }; + return UNK('opaque_declaration'); +} + +// the leftmost identifier of `a.b.c(...)`/`a()` when it is bound by an import from a package: a library +// call even when the package cannot be resolved (it is still kept in the chain, never dropped) +function rootImport(callee) { + let n = callee; + while (ts.isPropertyAccessExpression(n) || ts.isCallExpression(n) || ts.isElementAccessExpression(n)) n = n.expression; + if (!ts.isIdentifier(n)) return null; + const s = checker.getSymbolAtLocation(n); + for (const d of (s && s.declarations) || []) { + const decl = ts.isImportSpecifier(d) ? d.parent.parent.parent : ts.isImportClause(d) ? d.parent : ts.isNamespaceImport(d) ? d.parent.parent : null; + if (!decl || !decl.moduleSpecifier) continue; + const ms = decl.moduleSpecifier.text; + if (isProjectSpec(ms, d.getSourceFile().fileName)) return null; + return `${libLabel(ms)}.${callee.getText().replace(/\s+/g, '').replace(/\(.*$/s, '')}`; + } + return null; +} +const reassignCache = new Map(); +function isReassigned(d) { + if (reassignCache.has(d)) return reassignCache.get(d); + const sym = checker.getSymbolAtLocation(d.name); let hit = false; + (function v(n) { + if (hit) return; + const target = ts.isBinaryExpression(n) && n.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && n.operatorToken.kind <= ts.SyntaxKind.LastAssignment ? n.left + : (ts.isPrefixUnaryExpression(n) || ts.isPostfixUnaryExpression(n)) && (n.operator === ts.SyntaxKind.PlusPlusToken || n.operator === ts.SyntaxKind.MinusMinusToken) ? n.operand : null; + if (target && ts.isIdentifier(target) && checker.getSymbolAtLocation(target) === sym) hit = true; + ts.forEachChild(n, v); + })(d.getSourceFile()); + reassignCache.set(d, hit); return hit; +} +function libName(callee) { + // `cors` imported from 'hono/cors' -> 'hono/cors.cors' + const id = ts.isPropertyAccessExpression(callee) ? callee.name : callee; + let s = checker.getSymbolAtLocation(id); + if (!s) return rootImport(callee); + const decls = s.declarations || []; + for (const d of decls) { + const ms = ts.isImportSpecifier(d) ? d.parent.parent.parent.moduleSpecifier.text : ts.isImportClause(d) ? d.parent.moduleSpecifier.text : null; + // a project module (relative, aliased, workspace): a library call only when that module re-exports a library + // function (O14 `export { cors } from 'hono/cors'`) or exports a member of a library call's result (O10) + if (ms && isProjectSpec(ms, d.getSourceFile().fileName)) return libViaProject(s); + if (ts.isImportSpecifier(d)) return `${libLabel(ms)}.${(d.propertyName || d.name).text}`; + if (ts.isImportClause(d)) return `${libLabel(ms)}.default`; + } + // O10: `const { upgradeWebSocket } = createBunWebSocket()`: a member of a library call's result is a library function + const lb = decls.find(x => ts.isBindingElement(x) && x.parent.parent.initializer && ts.isCallExpression(x.parent.parent.initializer) + && x.parent.parent.initializer.expression.getText() !== 'require'); + if (lb) { const inner = libName(lb.parent.parent.initializer.expression); if (inner) return `${inner}().${(lb.propertyName || lb.name).getText()}`; } + // `const { cors } = require('hono/cors')`: named by the required specifier, before alias resolution + const bd = decls.find(x => ts.isBindingElement(x) && x.parent.parent.initializer && ts.isCallExpression(x.parent.parent.initializer) + && x.parent.parent.initializer.expression.getText() === 'require' && ts.isStringLiteralLike(x.parent.parent.initializer.arguments[0])); + if (bd) { + const rs = bd.parent.parent.initializer.arguments[0].text; + if (isProjectSpec(rs, bd.getSourceFile().fileName)) return libViaRequire(bd.parent.parent.initializer, (bd.propertyName || bd.name).getText()); + return `${libLabel(rs)}.${(bd.propertyName || bd.name).getText()}`; + } + if (s.flags & ts.SymbolFlags.Alias) { try { s = checker.getAliasedSymbol(s); } catch { } } + const d = s.valueDeclaration || (s.declarations && s.declarations[0]); + if (d && !isSrcDecl(d)) { + const f = path.resolve(d.getSourceFile().fileName); const m = f.match(/node_modules\/((?:@[^/]+\/)?[^/]+)/); + return `${m ? m[1] : 'lib'}.${s.name}`; + } + // `const { cors } = require('hono/cors')` + if (d && ts.isBindingElement(d) && d.parent.parent.initializer && ts.isCallExpression(d.parent.parent.initializer) + && d.parent.parent.initializer.expression.getText() === 'require') { + return `${d.parent.parent.initializer.arguments[0].text}.${(d.propertyName || d.name).getText()}`; + } + return null; +} +// a binding that names a library function: `const { f } = libCall()` (O10) or `const { f } = require('pkg')` +function libOfBinding(d) { + if (!d || !ts.isBindingElement(d)) return null; + const init = d.parent && d.parent.parent && d.parent.parent.initializer; + if (!init || !ts.isCallExpression(init)) return null; + const nm = (d.propertyName || d.name).getText(); + if (init.expression.getText() === 'require') { + const a = init.arguments[0]; + if (!a || !ts.isStringLiteralLike(a)) return null; + return isProjectSpec(a.text, d.getSourceFile().fileName) ? libViaRequire(init, nm) : `${libLabel(a.text)}.${nm}`; + } + const inner = libName(init.expression); + return inner ? `${inner}().${nm}` : null; +} +// an import from a PROJECT module that ends at a library function: re-exported (`export { cors } from 'hono/cors'`, +// O14), or a project binding of one (`export const { upgradeWebSocket } = createBunWebSocket()`, O10) +function libViaProject(sym) { + let s = sym; + for (let i = 0; i < 12 && s && (s.flags & ts.SymbolFlags.Alias); i++) { + for (const d of s.declarations || []) { + const ed = ts.isExportSpecifier(d) ? d.parent.parent : null; + if (ed && ed.moduleSpecifier && !isProjectSpec(ed.moduleSpecifier.text, d.getSourceFile().fileName)) + return `${libLabel(ed.moduleSpecifier.text)}.${(d.propertyName || d.name).text}`; + } + let n; try { n = checker.getImmediateAliasedSymbol(s); } catch { n = null; } + if (!n || n === s) break; + s = n; + } + if (s && (s.flags & ts.SymbolFlags.Alias)) { try { s = checker.getAliasedSymbol(s); } catch { } } + const d = s && (s.valueDeclaration || (s.declarations && s.declarations[0])); + if (!d) return null; + if (!isSrcDecl(d)) { const m = path.resolve(d.getSourceFile().fileName).match(/node_modules\/((?:@[^/]+\/)?[^/]+)/); return `${m ? m[1] : 'lib'}.${s.name}`; } // `export * from 'pkg'` + return libOfBinding(d); +} +// a member of a PROJECT CommonJS module's exports that is a library function (`module.exports = { upgradeWebSocket }`) +function libViaRequire(reqCall, name) { + const v = requireValue(reqCall); + const p = v.k === 'obj' && v.props.get(name); + if (!p || !p.node) return null; + let id = p.node; + if (ts.isIdentifier(id) && id.parent && ts.isShorthandPropertyAssignment(id.parent)) { + const vs = checker.getShorthandAssignmentValueSymbol(id.parent); + return libOfBinding(vs && (vs.valueDeclaration || (vs.declarations && vs.declarations[0]))); + } + if (ts.isIdentifier(id)) return libOfBinding(declOf(id)); + return null; +} +// SPEC R2: a receiver whose DECLARED type is the app class (a property, field, getter, parameter) whose value +// the program does not show is an app of unknown prefix +function isTypedApp(expr) { + let t; + try { t = checker.getTypeAtLocation(expr); } catch { return false; } + const sym = t && (t.getSymbol() || t.aliasSymbol); + const d = sym && sym.declarations && sym.declarations[0]; + return !!(d && isHonoClassDecl(d)); +} +function unresolvedAppCall(name, e) { + const partial = (key, verb) => { out.partial.add(`${key}\t${verb}\tunresolved_app_value`); unknownAt(e, 'unresolved_app_value', key); }; + if (name === 'route') { + const sub = evalExpr(e.arguments[1]); + if (sub.k !== 'app') { unknownAt(e, 'unresolved_mount'); return UNK('app'); } + // O23: inside a plugin method that a host calls over a list (the O11 pass), the mount is a list mount: the engine's + // R13 reason, unresolved_mount; elsewhere a typed receiver of unknown value is unresolved_app_value (R2) + partialMount(sub, pluginPass ? 'unresolved_mount' : 'unresolved_app_value', e, []); + return UNK('app'); + } + if (VERBS.includes(name) || name === 'on' || name === 'openapi') { + const hs = argVals(e.arguments.slice(name === 'on' ? 2 : 1)); + const h = name === 'openapi' ? evalExpr(e.arguments[1]) : hs[hs.length - 1]; + const k = h && handlerKey(h); + if (k) { partial(k, name === 'all' ? 'ANY' : name === 'on' || name === 'openapi' ? '?' : name.toUpperCase()); if (h.k === 'fn') handlerFns.add(h.node); } + return UNK('app'); + } + return UNK('app'); +} +function isHonoClassDecl(d) { + return d && (ts.isClassDeclaration(d) || ts.isVariableDeclaration(d)) && d.name + && ['Hono', 'OpenAPIHono', 'HonoBase'].includes(d.name.getText()) && inPkg(d, ['hono', '@hono/zod-openapi']); +} +function classDeclOfNew(expr) { + let s = checker.getSymbolAtLocation(expr); + if (!s) return null; + if (s.flags & ts.SymbolFlags.Alias) { try { s = checker.getAliasedSymbol(s); } catch { } } + return s.valueDeclaration || (s.declarations && s.declarations[0]); +} + +// ── expressions ───────────────────────────────────────────────────────────── +let depth = 0; +// O15: a bound on nested evaluation. Every value is computed by recursion over declarations, so a cycle the +// memo sets do not catch would overflow the stack; past the bound the value is unknown (a declared gap) +let evalDepth = 0; +const EVAL_DEPTH_MAX = 1200; +const cycles = new Set(); +function noteCycle(n) { const l = loc(n); if (!cycles.has(l)) { cycles.add(l); if (DEBUG) process.stderr.write(`O15: evaluation cycle cut at ${l}\n`); } } +let evalCount = 0; +const inlineStack = [], hot = new Map(); +function evalExpr(e) { + if (DEBUG) { + if (e && evalCount < 3000000) { const l = loc(e); hot.set(l, (hot.get(l) || 0) + 1); } + if (++evalCount % 5000000 === 0) process.stderr.write(`O15 progress: ${evalCount} evaluations; inlined: ${inlineStack.join(' > ')}; hottest: ${[...hot].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([k, n]) => k + ' x' + n).join(', ')}\n`); + } + if (evalDepth >= EVAL_DEPTH_MAX) { if (e) noteCycle(e); return UNK('eval_depth'); } + evalDepth++; + try { return evalExpr0(e); } finally { evalDepth--; } +} +function evalExpr0(e) { + if (!e) return UNK('none'); + while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isSatisfiesExpression?.(e) || ts.isNonNullExpression(e) || ts.isTypeAssertionExpression?.(e)) e = e.expression; + if (ts.isStringLiteral(e) || ts.isNoSubstitutionTemplateLiteral(e)) return { k: 'str', v: e.text }; + if (ts.isTemplateExpression(e)) { + let s = e.head.text; + for (const sp of e.templateSpans) { const v = evalExpr(sp.expression); if (v.k !== 'str') return UNK('template_part'); s += v.v + sp.literal.text; } + return { k: 'str', v: s }; + } + if (ts.isBinaryExpression(e) && e.operatorToken.kind === ts.SyntaxKind.PlusToken) { + const a = evalExpr(e.left), b = evalExpr(e.right); + return a.k === 'str' && b.k === 'str' ? { k: 'str', v: a.v + b.v } : UNK('concat_part'); + } + if (ts.isBinaryExpression(e) && (e.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken || e.operatorToken.kind === ts.SyntaxKind.BarBarToken)) { + // `x ?? []`: the left value when the program shows it, else unknown (a run-time value may be there) + const a = evalExpr(e.left); + if (a.k === 'undef') return evalExpr(e.right); + return a.k === 'unk' ? UNK('nullish') : a; + } + if (ts.isBinaryExpression(e) && e.operatorToken.kind === ts.SyntaxKind.EqualsToken) { + let v = evalExpr(e.right); env.set(e, v); + // SPEC R8a/R8b: an app holder re-pointed at a basePath clone of the SAME app under a condition is rebased only at + // run time: every route registered through it afterwards is partial (dynamic_mount_prefix), never exact + const rebase = (old) => (condDepth > 0 && v.k === 'app' && old && old.k === 'app' && old.store === v.store && old.base !== v.base && !v.dyn) + ? (v = { ...v, dyn: 'dynamic_mount_prefix' }) : v; + // SPEC 2 [iter2] flow through fields: `this.f = ` makes `this.f` that app in every method of the class + if (ts.isPropertyAccessExpression(e.left) && e.left.expression.kind === ts.SyntaxKind.ThisKeyword) { + const fd = declOf(e.left.name); if (fd && isSrcDecl(fd)) env.set(fd, rebase(env.get(fd))); + } + // R8b: the same for a `let` variable (`let app = new Hono(); if (base) app = app.basePath(base)`): the binding + // follows the assignment, so later registrations go through the (rebased) clone + if (ts.isIdentifier(e.left)) { + const vd = declOf(e.left); + if (vd && ts.isVariableDeclaration(vd) && isSrcDecl(vd) && !(vd.parent.flags & ts.NodeFlags.Const) && env.has(vd) && v.k === 'app') env.set(vd, rebase(env.get(vd))); + } + return v; + } + if (ts.isArrowFunction(e) || ts.isFunctionExpression(e)) return { k: 'fn', node: e }; + if (e.kind === ts.SyntaxKind.NullKeyword) return UNDEF; // `null` and `undefined` are both an absent value here + if (ts.isIdentifier(e)) { + if (e.text === 'undefined') return UNDEF; + const d = declOf(e); + if (d && ts.isParameter(d)) return env.has(d) ? env.get(d) : UNK('parameter'); + if (d && ts.isVariableDeclaration(d) && !(d.parent.flags & ts.NodeFlags.Const) && !env.has(d)) return UNK('mutable'); + const v = valueOfDecl(d); + if (v.k === 'str' && d && ts.isVariableDeclaration(d) && !(d.parent.flags & ts.NodeFlags.Const) && isReassigned(d)) return UNK('reassigned_let'); + return v; + } + if (ts.isArrayLiteralExpression(e)) { + const items = []; + for (const x of e.elements) { + if (ts.isSpreadElement(x)) { const v = evalExpr(x.expression); if (v.k === 'list') items.push(...v.items); else items.push(v); } + else items.push(evalExpr(x)); + } + return { k: 'list', items }; + } + if (ts.isObjectLiteralExpression(e)) { + const props = new Map(); + let open = false; + for (const p of e.properties) { + if (p.name && ts.isComputedPropertyName(p.name)) open = true; + if (ts.isGetAccessor(p) || ts.isSetAccessor(p)) open = true; + if (ts.isPropertyAssignment(p)) { + const pr = { node: p.initializer }; + // a nested object literal is evaluated now, while the parameters of an enclosing helper call are bound + // (`({ content: { 'application/json': { schema } } })`, hono-3-04); a parameter read keeps its argument + // inside a call being inlined every property is read NOW, as JavaScript does: read later, after the call's + // locals are reset, `{ handler: routes }` would evaluate the local's initializer again (a second, empty app) + if (ts.isObjectLiteralExpression(p.initializer) || depth > 0) pr.val = evalExpr(p.initializer); + else if (ts.isIdentifier(p.initializer)) { + const d = declOf(p.initializer); if (d && paramArgNode.has(d)) pr.argNode = paramArgNode.get(d); + // a local of the function being inlined (`{ handler: routes }` returned by a factory) is read NOW: read + // later, after the call's locals are reset, it would evaluate its initializer again (a second app) + } + props.set(p.name.getText().replace(/^['"]|['"]$/g, ''), pr); + } + else if (ts.isShorthandPropertyAssignment(p)) { + const vs = checker.getShorthandAssignmentValueSymbol(p); + const d = vs && (vs.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(vs) : vs); + const dd = d && (d.valueDeclaration || (d.declarations && d.declarations[0])); + const pr = { node: p.name, val: d ? valueOfDecl(dd) : UNK('shorthand') }; + if (dd && paramArgNode.has(dd)) pr.argNode = paramArgNode.get(dd); + props.set(p.name.text, pr); + } + else if (ts.isMethodDeclaration(p)) props.set(p.name.getText(), { val: { k: 'fn', node: p } }); + else if (ts.isSpreadAssignment(p)) { const v = evalExpr(p.expression); if (v.k === 'obj') { if (v.open) open = true; for (const [k, x] of v.props) props.set(k, x); } else if (v.k !== 'undef') open = true; } // `{ ...helper(schema), required: true }` + } + // O24: an app written into an entry of a route list (`[{ path, handler: app }]`) is served only if something + // mounts that entry; remember the entry so an app nothing mounts or serves is not reported as a root + if (e.parent && ts.isArrayLiteralExpression(e.parent)) for (const [, pr] of props) if (pr.val && pr.val.k === 'app' && !pr.val.store.listEntry) pr.val.store.listEntry = pr.node || e; + return { k: 'obj', props, node: e, open }; + } + if (ts.isPropertyAccessExpression(e) || ts.isElementAccessExpression(e)) { + const recv = calleeRecv.has(e.expression) ? calleeRecv.get(e.expression) : evalExpr(e.expression); + let name = ts.isPropertyAccessExpression(e) ? e.name.text : (ts.isStringLiteralLike(e.argumentExpression) ? e.argumentExpression.text : null); + if (name == null && ts.isElementAccessExpression(e) && recv.k === 'obj') { const kv = evalExpr(e.argumentExpression); if (kv.k === 'str') name = kv.v; } // `mods[path]` in a for..in + if (recv.k === 'client') return { ...recv, segs: [...recv.segs, name == null ? HOLE : name] }; // a dynamic key is one segment + if (recv.k === 'obj' && name != null && recv.props.has(name)) { const p = recv.props.get(name); if (!p.val) p.val = evalExpr(p.node); return p.val; } + if (recv.k === 'obj' && recv.open === false && name != null && ts.isObjectLiteralExpression(recv.node) && !assignedPropNames().has(name)) return UNDEF; + if (recv.k === 'undef') return UNDEF; // `x?.y` on an absent x (a plain read would throw: nothing runs either way) + if (recv.k === 'module' && name != null) { + const ed = moduleExportDecl(recv.sf, name); // through `export { x } from './x'` barrels + if (ed) return valueOfDecl(ed); + const s = checker.getSymbolAtLocation(e.name || e.argumentExpression); return s ? valueOfDecl(s.valueDeclaration) : UNK('module_member'); + } + if (recv.k === 'app' && name === 'fetch') { recv.store.fetchRead = true; return { k: 'fetch', app: recv }; } + // O17: `const createAdminMiddleware = adminFactory.createMiddleware` keeps the factory's method + if (recv.k === 'factory' && ['createMiddleware', 'createHandlers', 'createApp'].includes(name)) return { k: 'factoryMethod', factory: recv, name }; + if (ts.isPropertyAccessExpression(e)) { + const d = declOf(e.name); + if (d && isSrcDecl(d) && (ts.isPropertyDeclaration(d) || ts.isPropertySignature(d))) { + if (env.has(d)) return env.get(d); // a field assigned an app (`this.app = createApp()`) + if (ts.isPropertyDeclaration(d) && d.initializer && !evaluating.has(d)) { evaluating.add(d); const v = evalExpr(d.initializer); evaluating.delete(d); env.set(d, v); return v; } + } else if (d && isSrcDecl(d) && ts.isGetAccessorDeclaration(d) && d.body && depth < 8) return inline(d, []); // a getter is a call + else if (d && isSrcDecl(d)) return valueOfDecl(d); + } + return UNK('member'); + } + if (ts.isNewExpression(e)) { + const d = classDeclOfNew(e.expression); + if (isHonoClassDecl(d)) return newApp(e); + // a subclass of Hono declared in the project + if (d && ts.isClassDeclaration(d) && d.heritageClauses) { + for (const h of d.heritageClauses) for (const t of h.types) if (isHonoClassDecl(classDeclOfNew(t.expression))) return newApp(e); + } + if (d && ts.isClassDeclaration(d) && isSrcDecl(d) && depth < 8) { + for (const m of d.members) if (ts.isPropertyDeclaration(m) && m.initializer && !env.has(m)) { evaluating.add(m); env.set(m, evalExpr(m.initializer)); evaluating.delete(m); } + const ctor = d.members.find(m => ts.isConstructorDeclaration(m) && m.body); + if (ctor && !inlinedFns.has(ctor)) inline(ctor, e.arguments || []); + return { k: 'instance', cls: d }; + } + return UNK('new_other'); + } + if (ts.isCallExpression(e)) return evalCall(e); + if (ts.isAwaitExpression(e)) return evalExpr(e.expression); + if (ts.isConditionalExpression(e)) { + // `cond ? topoSort(list.filter(..)) : list.filter(..)`: two known lists are one list of their elements, a subset + // of which runs (R13b) + const a = evalExpr(e.whenTrue), b = evalExpr(e.whenFalse); + if (a.k === 'list' && b.k === 'list') { + const items = [...a.items]; for (const x of b.items) if (!items.includes(x)) items.push(x); + const same = a.items.length === b.items.length && a.items.every(x => b.items.includes(x)); + return { k: 'list', items, derived: same ? joinDerived(a.derived, b.derived) : 'filtered' }; + } + return UNK('conditional'); + } + return UNK('expr'); +} + +const VERBS = ['get', 'post', 'put', 'delete', 'options', 'patch', 'query', 'all']; +function argVals(args) { + const vs = []; + for (const a of args) { + if (ts.isSpreadElement(a)) { const v = evalExpr(a.expression); if (v.k === 'list') vs.push(...v.items); else vs.push(UNK('spread')); } + else vs.push(evalExpr(a)); + } + return vs; +} + +// O15: the receiver of `a.b(..)` as evalCall computed it. A user-function lookup evaluates the callee `a.b` again, +// which re-evaluated `a`: twice per link, 2^n for a long builder chain (`.option(..)` x 20) +const calleeRecv = new Map(); +// R12: module lists the program spells literally. `import.meta.glob()` is an object keyed by the +// matched files' paths (eager: the module; lazy: a function returning it), `require.context(dir, deep, /re/)` a +// function over its keys; Object.entries / values / keys / fromEntries over a known object follow the values +// O28: a brace alternative is a glob of its own (`{a,*-b}`, `{x/**,y}`): translate it with the same rules, never +// as escaped literal text (a bare `*` there made an invalid regex: "Nothing to repeat"). Braces may nest. +function globBody(pat) { + let r = ''; + for (let i = 0; i < pat.length; i++) { + const ch = pat[i]; + if (ch === '*' && pat[i + 1] === '*') { r += pat[i + 2] === '/' ? '(?:.*/)?' : '.*'; i += pat[i + 2] === '/' ? 2 : 1; } + else if (ch === '*') r += '[^/]*'; + else if (ch === '?') r += '[^/]'; + else if (ch === '{') { + let depth = 0, j = i, start = i + 1; const alts = []; + for (; j < pat.length; j++) { + if (pat[j] === '{') depth++; + else if (pat[j] === '}') { if (--depth === 0) break; } + else if (pat[j] === ',' && depth === 1) { alts.push(pat.slice(start, j)); start = j + 1; } + } + if (j >= pat.length) { r += '\\{'; continue; } // an unclosed brace is a literal + alts.push(pat.slice(start, j)); + r += '(?:' + alts.map(globBody).join('|') + ')'; i = j; + } + else r += ch.replace(/[.+^$()|[\]\\{}]/g, '\\$&'); + } + return r; +} +function globRegex(pat) { return new RegExp('^' + globBody(pat) + '$'); } +function filesMatching(fromFile, pats) { + const dir = path.dirname(path.resolve(fromFile)), hits = new Map(); + const pos = pats.filter(p => !p.startsWith('!')), neg = pats.filter(p => p.startsWith('!')).map(p => p.slice(1)); + for (const sf of srcFiles) { + let r = path.relative(dir, path.resolve(sf.fileName)).split(path.sep).join('/'); + if (!r.startsWith('.')) r = './' + r; + if (pos.some(p => globRegex(p).test(r)) && !neg.some(p => globRegex(p).test(r))) hits.set(r, sf); + } + return hits; +} +function moduleListCall(e) { + const c = e.expression; + if (!ts.isPropertyAccessExpression(c)) return null; + const obj = c.expression, nm = c.name.text; + if (ts.isMetaProperty(obj) && nm === 'glob') { + const a = e.arguments[0] && evalExpr(e.arguments[0]); + const pats = a && a.k === 'str' ? [a.v] : a && a.k === 'list' && a.items.every(x => x.k === 'str') ? a.items.map(x => x.v) : null; + if (!pats) return UNK('glob'); + const opt = e.arguments[1] && evalExpr(e.arguments[1]); + const eager = opt && opt.k === 'obj' && opt.props.has('eager') && opt.props.get('eager').node.kind === ts.SyntaxKind.TrueKeyword; + const props = new Map(); + for (const [k, sf] of filesMatching(e.getSourceFile().fileName, pats)) { + globbed.add(sf); evalModule(sf); + const mod = moduleExports(sf); + props.set(k, { val: eager ? mod : { k: 'thunk', val: mod } }); + } + return { k: 'obj', props, node: e }; + } + if (ts.isIdentifier(obj) && obj.text === 'require' && nm === 'context') { + const d = e.arguments[0] && evalExpr(e.arguments[0]), deep = e.arguments[1] && e.arguments[1].kind === ts.SyntaxKind.TrueKeyword; + const re = e.arguments[2] && ts.isRegularExpressionLiteral(e.arguments[2]) ? e.arguments[2].text : null; + if (!d || d.k !== 'str' || !re) return UNK('require_context'); + const m = re.match(/^\/(.*)\/([a-z]*)$/), rx = new RegExp(m[1], m[2]); + const base = path.resolve(path.dirname(e.getSourceFile().fileName), d.v), mods = new Map(); + for (const sf of srcFiles) { + const f = path.resolve(sf.fileName); if (!f.startsWith(base + path.sep)) continue; + const r = './' + path.relative(base, f).split(path.sep).join('/'); + if ((!deep && r.slice(2).includes('/')) || !rx.test(r)) continue; + globbed.add(sf); evalModule(sf); mods.set(r, moduleExports(sf)); + } + return { k: 'reqctx', mods }; + } + // `Object.assign(fn, { meta })` returns its first argument + if (ts.isIdentifier(obj) && obj.text === 'Object' && nm === 'assign' && e.arguments[0]) return evalExpr(e.arguments[0]); + if (ts.isIdentifier(obj) && obj.text === 'Object' && ['entries', 'values', 'keys', 'fromEntries'].includes(nm)) { + const v = e.arguments[0] && evalExpr(e.arguments[0]); + if (nm === 'fromEntries') { + if (!v || v.k !== 'list') return UNK('from_entries'); + const props = new Map(); + for (const it of v.items) if (it.k === 'list' && it.items[0] && it.items[0].k === 'str') props.set(it.items[0].v, { val: it.items[1] || UNK('entry') }); + return { k: 'obj', props, node: e, derived: v.derived }; + } + if (!v || v.k !== 'obj') return UNK('object_' + nm); + const ents = [...v.props].map(([k, p]) => [k, pv_(p)]); + const items = nm === 'entries' ? ents.map(([k, x]) => ({ k: 'list', items: [{ k: 'str', v: k }, x] })) : nm === 'values' ? ents.map(([, x]) => x) : ents.map(([k]) => ({ k: 'str', v: k })); + return { k: 'list', items, derived: v.derived }; + } + return null; +} +const globbed = new Set(), opaqueMounts = []; +let pluginPass = false; +function isModuleListArg(a) { + while (a && (ts.isParenthesizedExpression(a) || ts.isAsExpression(a) || ts.isNonNullExpression(a) || ts.isAwaitExpression(a))) a = a.expression; + return !!a && ts.isPropertyAccessExpression(a) && a.name.text === 'default'; +} +function methodOf(cls, name) { + for (let c = cls, i = 0; c && i < 10; i++) { + const m = c.members.find(x => ts.isMethodDeclaration(x) && x.body && x.name && x.name.getText() === name); + if (m) return m; + const h = c.heritageClauses && c.heritageClauses.find(x => x.token === ts.SyntaxKind.ExtendsKeyword); + const b = h && classDeclOfNew(h.types[0].expression); + c = b && ts.isClassDeclaration(b) && isSrcDecl(b) ? b : null; + } + return null; +} +function factoryCall(f, name, e) { + if (name === 'createApp') { const a = newApp(e); if (f.initApp && depth < 8) inline(f.initApp, [], [a]); return a; } + if (name === 'createMiddleware') return evalExpr(e.arguments[0]); + return { k: 'list', items: argVals(e.arguments) }; // createHandlers +} +// R13: array methods over a KNOWN list follow the values. map/flatMap run the callback per element; a filter, a +// sort, a slice (a subset or a new order) gives the same elements marked `derived`: which of them run, and in which +// order, is decided at run time, so a mount over it is partial (unresolved_mount), never exact +function joinDerived(...ds) { return ds.includes('filtered') ? 'filtered' : ds.includes('reordered') ? 'reordered' : undefined; } +function listMethod(recv, name, e) { + const cb = e.arguments[0] && evalExpr(e.arguments[0]); + const call = (it, i) => cb && cb.k === 'fn' && cb.node.body && depth < 8 ? inline(cb.node, [], [it, { k: 'str', v: String(i) }]) : UNK('callback'); + if (name === 'map') return { k: 'list', items: recv.items.map(call), derived: recv.derived }; + if (name === 'flatMap') return { k: 'list', items: recv.items.flatMap((it, i) => { const v = call(it, i); return v.k === 'list' ? v.items : [v]; }), derived: recv.derived }; + if (name === 'forEach') { recv.items.forEach((it, i) => call(it, i)); return UNK('void'); } + // R13b: a filter keeps a run-time SUBSET (each element's registrations are conditional); a sort / slice / reverse + // keeps the elements in a run-time ORDER + // a null element never survives the usual `filter((p) => !!p)`; and a body that reads it mounts nothing + if (name === 'filter') return { k: 'list', items: recv.items.filter(it => it.k !== 'undef'), derived: 'filtered' }; + if (['sort', 'toSorted', 'slice', 'reverse', 'toReversed'].includes(name)) return { k: 'list', items: recv.items, derived: recv.derived || 'reordered' }; + if (name === 'push' || name === 'unshift') { const vs = argVals(e.arguments); recv.items[name === 'push' ? 'push' : 'unshift'](...vs); recv.derived = joinDerived(recv.derived, 'reordered', ...loopCtx.map(c => c.kind)); return { k: 'str', v: String(recv.items.length) }; } + if (name === 'concat') { const more = argVals(e.arguments); return { k: 'list', items: [...recv.items, ...more.flatMap(v => v.k === 'list' ? v.items : [v])], derived: joinDerived(recv.derived, ...more.map(v => v.derived)) }; } + return null; +} +// property names some assignment `a. = ..` / `a[''] = ..` writes anywhere in the program: a read of such a +// name on an object literal that lacks it may see the written value, so it stays unknown +let assignedProps = null; +function assignedPropNames() { + if (assignedProps) return assignedProps; + assignedProps = new Set(); + for (const sf of srcFiles) (function v(n) { + if (ts.isBinaryExpression(n) && n.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && n.operatorToken.kind <= ts.SyntaxKind.LastAssignment) { + const l = n.left; + if (ts.isPropertyAccessExpression(l)) assignedProps.add(l.name.text); + else if (ts.isElementAccessExpression(l) && ts.isStringLiteralLike(l.argumentExpression)) assignedProps.add(l.argumentExpression.text); + } + if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression) && n.expression.expression.getText() === 'Object' && ['assign', 'defineProperty', 'defineProperties'].includes(n.expression.name.text)) assignedProps.add('*'); + ts.forEachChild(n, v); + })(sf); + if (assignedProps.has('*')) assignedProps = { has: () => true }; // Object.assign(target, ..) can add any name + return assignedProps; +} +function evalCall(e) { + try { return evalCall0(e); } finally { if (ts.isPropertyAccessExpression(e.expression)) calleeRecv.delete(e.expression.expression); } +} +function evalCall0(e) { + const callee = e.expression; + const special = moduleListCall(e); + if (special) return special; + if (ts.isElementAccessExpression(callee)) { const f = evalExpr(callee); if (f.k === 'thunk') return f.val; } + if (ts.isIdentifier(callee) && callee.text === 'require') return requireValue(e); + if (callee.kind === ts.SyntaxKind.ImportKeyword) return requireValue(e); // O16: `await import('./m')` is that module + if (ts.isPropertyAccessExpression(callee)) { + const name = callee.name.text; + const recv = evalExpr(callee.expression); + calleeRecv.set(callee.expression, recv); // O15: read back below instead of evaluating the chain again + if (recv.k === 'app') return appMethod(recv, name, e); + if (recv.k !== 'app' && isTypedApp(callee.expression)) return unresolvedAppCall(name, e); + if (name === 'route' && e.arguments.length >= 2) { + // SPEC 2 [iter2]: a mount argument is never a root, even when the receiver is not recognised + const sub = evalExpr(e.arguments[1]); + if (sub.k === 'app') { partialMount(sub, 'unresolved_mount', e, []); return UNK('route_on_unknown'); } + } + if (recv.k === 'client') return clientCall(recv, name, e); + if (recv.k === 'factory' && ['createApp', 'createMiddleware', 'createHandlers'].includes(name)) return factoryCall(recv, name, e); + if (recv.k === 'list') { const r = listMethod(recv, name, e); if (r) return r; } + if (recv.k === 'undef') return UNDEF; // `routes.map(..)` on an absent list: nothing runs + if (recv.k === 'reqctx' && name === 'keys') return { k: 'list', items: [...recv.mods.keys()].map(v => ({ k: 'str', v })) }; + } + if (testCallbacks(e)) return UNK('test'); + const lname = libName(callee); + if (lname) { + const short = lname.split('.').pop(); + if (/^(hono\/factory|hono)\.createMiddleware$/.test(lname)) return evalExpr(e.arguments[0]); + if (/^hono\/factory\.createFactory$/.test(lname)) { + // SPEC 3.1: initApp's registrations happen first on every app the factory makes + const o = e.arguments[0] && evalExpr(e.arguments[0]); + const ia = o && o.k === 'obj' && o.props.get('initApp'); + const iv = ia && (ia.val || evalExpr(ia.node)); + return { k: 'factory', initApp: iv && iv.k === 'fn' ? iv.node : null }; + } + if (/^hono\/client\.hc$/.test(lname)) { + // JavaScript has no type argument: SPEC 3.5 matches the client against every served app (route_shape) + const js = /\.(js|mjs|cjs|jsx)$/.test(e.getSourceFile().fileName) && !e.typeArguments; + return { k: 'client', app: js ? 'ANY_APP' : clientApp(e), segs: [], via: 'hc' }; + } + if (/^hono\/testing\.testClient$/.test(lname)) { const a = evalExpr(e.arguments[0]); return { k: 'client', app: a.k === 'app' ? a : null, segs: [], via: 'testClient' }; } + if (/^@hono\/zod-openapi\.createRoute$/.test(lname)) return routeDef(e.arguments[0]); + if (/^@hono\/node-server\.serve$/.test(lname)) { serveSite(e); return UNK('server'); } + if (short === 'createRoute' || short === 'serve') return UNK('lib'); + const lf = { k: 'libfn', name: lname, site: loc(e) }; + if (/^(@hono\/zod-validator\.zValidator|hono\/validator\.validator)$/.test(lname) && e.arguments.length >= 2) { + const t = evalExpr(e.arguments[0]); + if (t.k === 'str') lf.validator = { target: t.v, schema: short === 'zValidator' ? e.arguments[1] : null }; + } + if (/^hono\/combine\.(every|some|except)$/.test(lname)) { + // the combinator is the middleware node; the project functions it runs are entry points + const as = argVals(short === 'except' ? e.arguments.slice(1) : e.arguments); + for (const v of as) if (v.k === 'fn') combinedFns.add(loc(v.node)); + if (short === 'except') { + // SPEC 3.1: applies to its scope minus the literal excluded paths + const ex = evalExpr(e.arguments[0]); + const xs = ex.k === 'list' ? ex.items : [ex]; + if (xs.every(x => x.k === 'str')) lf.except = xs.map(x => x.v); + else unknownAt(e, 'dynamic_except'); + } + } + return lf; + } + // a user function called here: inline it (factories, register(app) helpers, middleware factories) + if (ts.isIdentifier(callee) || ts.isPropertyAccessExpression(callee)) { + const f = evalExpr(callee); + if (f.k === 'factoryMethod') return factoryCall(f.factory, f.name, e); + if (f.k === 'thunk') return f.val; + if (f.k === 'reqctx') { const k = evalExpr(e.arguments[0]); return k.k === 'str' && f.mods.has(k.v) ? f.mods.get(k.v) : UNK('require_context_key'); } + // a method called on an instance the program built (`s.controller()` with `s` = new OAuth()): that class's own + // method (or an inherited one), never every implementation of the declared type's method + if (ts.isPropertyAccessExpression(callee) && calleeRecv.has(callee.expression) && calleeRecv.get(callee.expression).k === 'instance' && depth < 8) { + const m = methodOf(calleeRecv.get(callee.expression).cls, callee.name.text); + if (m) return inline(m, e.arguments); + } + if (f.k === 'fn' && f.node.body && depth < 8) return inline(f.node, e.arguments); + if (f.k === 'fn' && !f.node.body && ts.isPropertyAccessExpression(callee) && depth < 8) { + // an abstract / interface method on a receiver the program does not pin down: every project implementation + // may run (hono-2-01), so each is evaluated and their results are all candidates + const impls = implementationsOf(f.node); + const vals = impls.map(m => inline(m, e.arguments)); + return vals.length === 1 ? vals[0] : { k: 'list', items: vals }; + } + } + if (testCallbacks(e)) return UNK('test'); + // O26: the arguments of a call the oracle cannot follow (`expect(await app.request('/x'))`) still run, in place: + // left for a later pass, `app` would be read after the test's locals are reset, a second, empty app (unserved) + for (const a of e.arguments) if (!ts.isFunctionLike(a)) evalExpr(a); + return UNK('call'); +} + +// SPEC R1 (O1): an app built and exercised inside a test callback is a served root, so a test runner's +// callbacks (describe/it/test/hooks, incl. .only/.skip/.each(...)) are evaluated where they are registered +const TEST_FNS = new Set(['describe', 'it', 'test', 'beforeAll', 'beforeEach', 'afterAll', 'afterEach', 'bench', 'suite']); +function testCallbacks(e) { + let n = e.expression; + while (ts.isPropertyAccessExpression(n) || ts.isCallExpression(n)) n = n.expression; + if (!ts.isIdentifier(n) || !TEST_FNS.has(n.text)) return false; + const d = declOf(n); + if (d && isSrcDecl(d) && !ts.isImportSpecifier(d) && !(ts.isFunctionDeclaration(d) && !d.body)) return false; // a project function called `test` (an ambient `declare function it` is the runner's) + for (const a of e.arguments) if ((ts.isArrowFunction(a) || ts.isFunctionExpression(a)) && depth < 8) inline(a, []); + return true; +} +function implementationsOf(decl) { + const owner = decl.parent, name = decl.name && decl.name.getText(), out = []; + if (!owner || !name) return out; + const ownerSym = owner.name && checker.getSymbolAtLocation(owner.name); + for (const sf of srcFiles) (function v(n) { + if (ts.isClassDeclaration(n) && n !== owner) { + const t = checker.getTypeAtLocation(n); + const bases = [...(checker.getBaseTypes ? (t.isClassOrInterface() ? checker.getBaseTypes(t) : []) : []), ...((n.heritageClauses || []).flatMap(h => h.types.map(x => checker.getTypeAtLocation(x))))]; + if (bases.some(b => b.getSymbol() === ownerSym)) for (const m of n.members) if (ts.isMethodDeclaration(m) && m.body && m.name.getText() === name) out.push(m); + } + ts.forEachChild(n, v); + })(sf); + return out; +} +function requireValue(e) { + const s = e.arguments[0] && ts.isStringLiteralLike(e.arguments[0]) ? e.arguments[0].text : null; + if (!s || !isProjectSpec(s, e.getSourceFile().fileName)) return UNK('require_pkg'); + const r = resolveSpec(s, e.getSourceFile().fileName); + const sf = r && program.getSourceFile(r.resolvedFileName); + if (!sf) return UNK('require_unresolved'); + evalModule(sf); + return moduleExports(sf); +} +// the declaration an ES module exports under `name` (through re-exports) +function moduleExportDecl(sf, name) { + const ms = checker.getSymbolAtLocation(sf); + let ex = ms && checker.getExportsOfModule(ms).find(x => x.name === name); + if (!ex) return null; + if (ex.flags & ts.SymbolFlags.Alias) { try { ex = checker.getAliasedSymbol(ex); } catch { } } + return ex.valueDeclaration || (ex.declarations && ex.declarations[0]) || null; +} +function moduleExports(sf) { + for (const st of sf.statements) { + if (ts.isExpressionStatement(st) && ts.isBinaryExpression(st.expression) && st.expression.left.getText() === 'module.exports') return env.get(st.expression) ?? evalExpr(st.expression.right); + } + // O7: `module.exports.a = v` / `exports.a = v` make an exports object of those members + const props = new Map(); + for (const st of sf.statements) { + const be = ts.isExpressionStatement(st) && ts.isBinaryExpression(st.expression) && st.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken ? st.expression : null; + const m = be && be.left.getText().match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)$/); + if (m) props.set(m[1], { node: be.right, val: env.get(be) }); + } + return props.size ? { k: 'obj', props, node: sf } : { k: 'module', sf }; +} + +const inlinedFns = new Set(), handlerFns = new Set(); +const paramArgNode = new Map(); // a parameter of a function being inlined -> the argument expression it is bound to +function localDecls(fnNode) { + const out = []; + (function v(n) { if (n !== fnNode && ts.isFunctionLike(n)) return; if (ts.isVariableDeclaration(n) || ts.isBindingElement(n)) out.push(n); ts.forEachChild(n, v); })(fnNode.body || fnNode); + return out; +} +function inline(fnNode, args, vals) { + inlinedFns.add(fnNode); + depth++; + if (DEBUG) inlineStack.push(loc(fnNode)); + const saved = []; + for (const d of localDecls(fnNode)) { saved.push([d, env.get(d)]); env.delete(d); } // R6: a fresh app per call + const savedArgs = fnNode.parameters.map(p => [p, paramArgNode.get(p)]); + // a parameter passed straight on (`jsonBody(schema, ..)` inside another helper) keeps the ORIGINAL argument + const argNodes = fnNode.parameters.map((p, i) => { + const a = !vals && !p.dotDotDotToken ? args[i] : null; + if (!a) return null; + const d = ts.isIdentifier(a) ? declOf(a) : null; + return d && paramArgNode.has(d) ? paramArgNode.get(d) : a; + }); + fnNode.parameters.forEach((p, i) => { + if (argNodes[i]) paramArgNode.set(p, argNodes[i]); else paramArgNode.delete(p); + saved.push([p, env.get(p)]); + if (vals) env.set(p, vals[i] || UNK('missing_arg')); + else if (p.dotDotDotToken) env.set(p, { k: 'list', items: argVals(args.slice(i)) }); + // a parameter a real call leaves out is undefined (R17: `hit(path)` sends no init, so GET), not unknown + else env.set(p, args[i] ? evalExpr(args[i]) : (p.initializer ? evalExpr(p.initializer) : p.questionToken ? UNDEF : UNK('missing_arg'))); + }); + let ret = UNK('no_return'); + retAlts.push([]); + if (fnNode.body && !ts.isBlock(fnNode.body)) ret = evalExpr(fnNode.body); + else if (fnNode.body) ret = evalBlock(fnNode.body.statements) ?? UNK('no_return'); + // SPEC 3.1 (hono-3-03): a factory whose returns are several middleware (a pass-through arrow in a branch, a library + // call otherwise) yields ALL of them, as alternatives at one chain position + const alts = retAlts.pop(); + const mwLike = v => v && (v.k === 'fn' || v.k === 'libfn'); + if (alts.length && alts.every(mwLike) && (mwLike(ret) || (ret.k === 'unk' && ret.why === 'no_return'))) { + const items = mwLike(ret) ? [...alts, ret] : alts; + ret = items.length === 1 ? items[0] : { k: 'alt', items }; + } + for (const [p, a] of savedArgs) { if (a === undefined) paramArgNode.delete(p); else paramArgNode.set(p, a); } + for (const [p, v] of saved) { if (v === undefined) env.delete(p); else env.set(p, v); } + if (DEBUG) inlineStack.pop(); + depth--; + return ret; +} + +const pv_ = p => p.val || (p.val = evalExpr(p.node)); // an object property's value, memoised +function routeDef(arg) { + const o = evalExpr(arg); + if (o.k !== 'obj') return UNK('route_object'); + const m = o.props.get('method'), p = o.props.get('path'); + const mv = m ? evalExpr(m.node) : UNK('no_method'), pv = p ? evalExpr(p.node) : UNK('no_path'); + const mwp = o.props.get('middleware'); + // SPEC 3.9: the request and response schemas of a route object, by validation target + const schemas = []; + const rq = o.props.get('request'), rqv = rq && (rq.val || evalExpr(rq.node)); + if (rqv && rqv.k === 'obj') { + for (const [prop, target] of [['params', 'param'], ['query', 'query'], ['headers', 'header'], ['cookies', 'cookie']]) { + const x = rqv.props.get(prop); if (x && x.node) schemas.push([target, x.argNode || x.node]); + } + const body = rqv.props.get('body'), bv = body && pv_(body); + const content = bv && bv.k === 'obj' && bv.props.get('content'), cv = content && pv_(content); + if (cv && cv.k === 'obj') for (const [mt, x] of cv.props) { + const mv2 = pv_(x), sc = mv2.k === 'obj' && mv2.props.get('schema'); + if (sc) schemas.push([/json/.test(mt) ? 'json' : /form/.test(mt) ? 'form' : mt, sc.argNode || sc.node]); + } + } + // hono-3-04: a response written by a project helper (`200: jsonContent(User, 'me')`) names the helper's argument + const rs = o.props.get('responses'), rsv = rs && pv_(rs); + if (rsv && rsv.k === 'obj') for (const [, x] of rsv.props) { + const r1 = pv_(x), c1 = r1.k === 'obj' && r1.props.get('content'), cv1 = c1 && pv_(c1); + if (cv1 && cv1.k === 'obj') for (const [, y] of cv1.props) { const yv = pv_(y), sc = yv.k === 'obj' && yv.props.get('schema'); if (sc) schemas.push(['response', sc.argNode || sc.node]); } + } + return { k: 'routedef', method: mv, path: pv, middleware: mwp ? evalExpr(mwp.node) : null, node: arg, schemas }; +} + +function clientApp(e) { + const ta = e.typeArguments && e.typeArguments[0]; + if (!ta) return null; + let t = ta; + for (let i = 0; i < 4 && t; i++) { + if (ts.isTypeQueryNode(t)) { const v = evalExpr(t.exprName); return v.k === 'app' ? v : null; } + if (ts.isTypeReferenceNode(t)) { + let s = checker.getSymbolAtLocation(t.typeName); + if (s && s.flags & ts.SymbolFlags.Alias) s = checker.getAliasedSymbol(s); + const d = s && s.declarations && s.declarations[0]; + t = d && ts.isTypeAliasDeclaration(d) ? d.type : null; + } else break; + } + return null; +} + +function serveSite(e) { + const o = e.arguments[0] && evalExpr(e.arguments[0]); + if (o && o.k === 'obj' && o.props.has('fetch')) evalExpr(o.props.get('fetch').node); +} + +function appMethod(app, name, e) { + const args = e.arguments, site = loc(e); + if (VERBS.includes(name)) { + const vs = argVals(args); + let p, hs; + if (vs[0] && vs[0].k === 'str') { app.path = vs[0].v; p = vs[0]; hs = vs.slice(1); } + else if (vs[0] && vs[0].k === 'unk' && args[0] && isStringTyped(args[0])) { p = vs[0]; hs = vs.slice(1); } + else { p = { k: 'str', v: app.path }; hs = vs; } + hs.forEach((h, i) => addEntry(app, name.toUpperCase(), p, h, i === hs.length - 1 ? 'handler' : 'mw', site, e)); + return app; + } + if (name === 'on') { + const mv = evalExpr(args[0]), pv = evalExpr(args[1]); + const ms = mv.k === 'list' ? mv.items : [mv], ps = pv.k === 'list' ? pv.items : [pv]; + const hs = argVals(args.slice(2)); + if (ms.some(m => m.k !== 'str')) { const k = handlerKey(hs[hs.length - 1] || UNK('')); out.partial.add(`${k}\t?\tdynamic_verb`); unknownAt(e, 'dynamic_verb', k); return app; } + if (ps.some(x => x.k !== 'str')) { for (const m of ms) addEntry(app, m.v.toUpperCase(), UNK('p'), hs[hs.length - 1], 'handler', site, e); return app; } + for (const p of ps) { app.path = p.v; for (const m of ms) hs.forEach((h, i) => addEntry(app, m.v.toUpperCase(), p, h, i === hs.length - 1 ? 'handler' : 'mw', site, e)); } + return app; + } + if (name === 'use') { + const vs = argVals(args); + let p, hs; + if (vs[0] && vs[0].k === 'str') { p = vs[0]; hs = vs.slice(1); } + else if (vs[0] && vs[0].k === 'unk' && args[0] && isStringTyped(args[0])) { for (const h of vs.slice(1)) unknownAt(e, 'dynamic_route_path', handlerKey(h) || undefined); return app; } + else { p = { k: 'str', v: '*' }; hs = vs; } + app.path = p.v; + for (const h of hs) addEntry(app, 'ALL', p, h, 'mw', site, e); + return app; + } + if (name === 'basePath') { + const pv = evalExpr(args[0]); + if (pv.k !== 'str') return { k: 'app', store: app.store, base: app.base, path: '/', origin: app.origin, dyn: 'dynamic_mount_prefix' }; + return { k: 'app', store: app.store, base: mergePath(app.base, pv.v), path: '/', origin: app.origin }; + } + if (name === 'route') { + const pv = evalExpr(args[0]), subv = evalExpr(args[1]); + // a call dispatched over several implementations yields several apps: each is mounted the same way + const subs = subv.k === 'list' ? subv.items.filter(x => x.k === 'app') : [subv]; + if (!subs.length || subs[0].k !== 'app') { unknownAt(e, 'unresolved_mount'); if (isModuleListArg(args[1])) opaqueMounts.push(e); return app; } + for (const sub of subs) mountOne(app, pv, sub, e, site); + return app; + } + return appMethod2(app, name, e); +} +// SPEC 3.3 [iter2]: a partial route (prefix unknown) still has a decidable chain: the sub-app's OWN middleware (matched +// inside the sub-app, whose paths are all under the one unknown prefix) after the parent's `*` / `/*` middleware +// registered before the mount. `mwp` rows: (mw, handler, verb, position); path and app are not decidable +const partialMw = new Set(); +function prefixText(x) { + if (!x) return HOLE; + while (ts.isParenthesizedExpression(x) || ts.isAsExpression(x)) x = x.expression; + if (ts.isTemplateExpression(x)) { let t = x.head.text; for (const sp of x.templateSpans) { const v = evalExpr(sp.expression); t += (v.k === 'str' ? v.v : HOLE) + sp.literal.text; } return t; } + const v = evalExpr(x); return v.k === 'str' ? v.v : HOLE; +} +function partialMount(sub, reason, e, parentMws, knownPrefix) { + sub.store.mounted = true; + const ents = [...sub.store.entries]; + const router = new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] }); + ents.forEach((en, i) => router.add(en.method, en.path, i)); + ents.forEach((en, i) => { + if (en.kind !== 'handler') return; + const V = en.method === 'ALL' ? 'ANY' : en.method; + out.partial.add(`${en.key}\t${V}\t${reason}`); unknownAt(e, reason, en.key); + if (knownPrefix != null && en.key) out.ppath.add(`${en.key}\t${V}\t${mergePath(knownPrefix, en.path).split(HOLE).join('{}')}`); + let matched; try { matched = router.match(en.method === 'ALL' ? 'GET' : en.method, samplePath(en.path))[0].map(x => x[0]); } catch { matched = null; } + if (!matched || !matched.includes(i)) return; + const seq = [...(parentMws || []), ...matched.filter(j => j < i).map(j => ents[j])]; + let at = -1, lastAlt; + // a run-time middleware list before the route makes its partial chain dynamic too + if (seq.some(x => x.kind === 'dyn')) out.unknown.add(`${en.site}\tdynamic_middleware_list\t${en.key}`); + for (const x of seq) { + if (x.kind === 'dyn' || !(x.kind === 'mw' || callsNext(x.val)) || (x.val.except && x.val.except.includes(en.path))) continue; + if (!(x.alt && x.alt === lastAlt)) at++; + lastAlt = x.alt; partialMw.add(`${x.key}\t${en.key}\t${V}\t${at}`); + } + }); +} +// the parent's middleware that applies to every path (`*`, `/*`), registered before now, and the scoped ones that +// cannot be decided against an unknown prefix +function parentStarMws(app, e) { + const all = [...app.store.entries, ...(app.store.dynMws || [])].sort((a, b) => a.seq - b.seq); + const star = []; + for (const m of all) if (m.kind === 'dyn' && m.method === 'ALL' && (m.path === '*' || m.path === '/*' || m.anyBase)) star.push(m); + else if (m.kind === 'mw' && m.method === 'ALL') { + if (m.path === '*' || m.path === '/*' || m.anyBase) star.push(m); + else if (m.val.k === 'fn') out.unknown.add(`${loc(e)}\tpartial_route_scope\t${m.key}`); + } + return star; +} +function mountOne(app, pv, sub, e, site) { + { + sub.store.mounted = true; + // R13b: a mount inside a loop over a filtered / reordered list of KNOWN elements is exact (conditional when + // filtered); only an undecidable path is partial + const why = app.dyn || (pv.k !== 'str' ? 'dynamic_mount_prefix' : null); + if (why) { + // every route of the sub-app is still emitted, partially, with the reason: never dropped; SPEC 3.3 [iter2]: a + // scoped `use` already on this app cannot be decided against routes whose prefix is unknown + const pm = sub.store.entries.some(r => r.kind === 'handler') ? parentStarMws(app, e) : []; + // the known pieces of a dynamic prefix: a template's decidable spans stay, every other piece is a HOLE + const known = app.dyn ? null : mergePath(app.base, prefixText(e.arguments[0])); + partialMount(sub, why, e, pm, known); + return app; + } + // the EFFECTIVE prefix: route() on a basePath'd app mounts under mergePath(base, prefix) (hono-base.js) + out.submount.push(`${mergePath(app.base, pv.v)}\t${loc(e.expression.name)}`); + const target = { ...app, base: mergePath(app.base, pv.v) }; + const ms = ++mountSeq, tag = loopTagNow(), filtered = loopCtx.some(c => c.kind === 'filtered'); + for (const r of [...sub.store.entries]) { + target.store.entries.push({ ...r, seq: ++entrySeq, path: mergePath(target.base, r.path), site: r.site, alt: r.alt && `${r.alt}m${ms}`, loopTag: tag ? [...(r.loopTag || []), ...tag] : r.loopTag }); + if (filtered && r.kind === 'handler') unknownAt(e, 'conditional_registration', r.key); + } + return app; + } +} +function appMethod2(app, name, e) { + const args = e.arguments, site = loc(e); + if (name === 'mount') { + const pv = evalExpr(args[0]); + if (pv.k !== 'str') { unknownAt(e, 'dynamic_mount_prefix'); return app; } + const fv = evalExpr(args[1]); + if (fv.k === 'fn') { + // O8: a mounted foreign handler is a route (ANY prefix/*) with a middleware chain like any other + app.store.foreign = app.store.foreign || []; app.store.foreign.push(loc(fv.node)); + app.store.entries.push({ seq: ++entrySeq, method: 'ALL', path: mergePath(app.base, pv.v, '*'), key: loc(fv.node), kind: 'handler', mount: true, site, val: fv, regFn: enclosingFn(e) }); + } + else unknownAt(e, 'foreign_mount'); + return app; + } + if (name === 'openapi') { + const rd = evalExpr(args[0]); + if (rd.k !== 'routedef' || rd.method.k !== 'str' || rd.path.k !== 'str') { unknownAt(e, rd.k === 'routedef' && rd.method.k !== 'str' ? 'dynamic_verb' : 'dynamic_route_path', handlerKey(evalExpr(args[1])) || undefined); return app; } + const h = evalExpr(args[1]); + const mws = rd.middleware ? (rd.middleware.k === 'list' ? rd.middleware.items : [rd.middleware]) : []; + const p = { k: 'str', v: rd.path.v.replaceAll(/\/{(.+?)}/g, '/:$1') }; + app.path = p.v; + for (const m of mws) addEntry(app, rd.method.v.toUpperCase(), p, m, 'mw', site, e); + addEntry(app, rd.method.v.toUpperCase(), p, h, 'handler', site, e); + if (app.store.entries.length) app.store.entries[app.store.entries.length - 1].routedef = rd; + return app; + } + if (name === 'notFound' || name === 'onError') { + const h = evalExpr(args[0]); + if (h.k === 'fn') app.store[name] = h; + return app; + } + if (name === 'request') { requestCall(app, e); return UNK('response'); } + if (name === 'fetch') { app.store.fetchRead = true; requestCall(app, e, true); return UNK('response'); } + if (name === 'fire') app.store.fetchRead = true; + if (name === 'doc' || name === 'doc31' || name === 'fire') return app; + return UNK('app_method'); +} + +function isStringTyped(n) { const t = checker.getTypeAtLocation(n); return !!(t.flags & (ts.TypeFlags.StringLike)); } + +function enclosingFn(n) { + for (let p = n.parent; p; p = p.parent) if (ts.isFunctionLike(p) && p.body) return loc(p); + return `${rel(n.getSourceFile().fileName)}:1:1`; // the module initializer, as the IR places it +} + +function requestCall(app, e, isFetch) { + // app.request(url, init) | app.request(new Request(url, init)) | app.fetch(new Request(url, init), env) + let urlArg = e.arguments[0], initArg = isFetch ? null : e.arguments[1]; + if (urlArg && ts.isNewExpression(urlArg) && urlArg.expression.getText() === 'Request') { initArg = urlArg.arguments && urlArg.arguments[1]; urlArg = urlArg.arguments && urlArg.arguments[0]; } + else if (isFetch) return; // `fetch(req, env, ctx) { return app.fetch(req, env, ctx) }` forwards a request (R4): no call of its own + let pv = evalExpr(urlArg); + // SPEC 3.5 [iter2]: a template's undecidable hole stands for exactly one segment + if (pv.k !== 'str' && urlArg && ts.isTemplateExpression(urlArg)) { + let t = urlArg.head.text; + for (const sp of urlArg.templateSpans) { const v = evalExpr(sp.expression); t += (v.k === 'str' ? v.v : HOLE) + sp.literal.text; } + pv = { k: 'str', v: t }; + } + if (pv.k !== 'str') { unknownAt(e, 'dynamic_rpc_path'); return; } + const reqPath = /^https?:\/\//.test(pv.v) ? pv.v.replace(/^https?:\/\/[^/]*/, '') || '/' : pv.v; + const method = httpMethodOf(initArg); + pendingRequests.push({ app, method, path: reqPath.split(/[?#]/)[0], from: enclosingFn(e), site: loc(e) }); // R9 +} +// SPEC R17 (O25): the HTTP method a request init gives. No init, an absent one, or a known object without `method` +// is GET (the default); a literal `method` is that verb; anything else (an init the program does not show, a +// non-literal method, a `method` some assignment may set later, hono-6-03) is '*': not decidable, so the request +// joins every route on its path, on any verb, with Confidence method_unknown (base_unknown wins when both are unknown) +function httpMethodOf(initArg) { + const init = initArg && evalExpr(initArg); + if (!init || init.k === 'undef') return 'GET'; + if (init.k !== 'obj') return '*'; + if (init.props.has('method')) { const m = evalExpr(init.props.get('method').node); return m.k === 'str' ? m.v.toUpperCase() : '*'; } + return init.open || assignedPropNames().has('method') ? '*' : 'GET'; +} +const ANY_VERBS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']; +const HOLE = '\u0000'; +const FILE_URL = 'file:'; +const LOCAL_URL = /^https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::[^/?#]*)?([/?#].*)?$/; +// the URL a fetch spells, with HOLE for every piece the program does not show (R14: a non-literal base is a hole) +function urlText(x) { + if (!x) return HOLE; + while (ts.isParenthesizedExpression(x) || ts.isAsExpression(x) || ts.isNonNullExpression(x)) x = x.expression; + if (ts.isStringLiteralLike(x)) return x.text; + if (ts.isTemplateExpression(x)) { let t = x.head.text; for (const sp of x.templateSpans) t += urlText(sp.expression) + sp.literal.text; return t; } + if (ts.isBinaryExpression(x) && x.operatorToken.kind === ts.SyntaxKind.PlusToken) return urlText(x.left) + urlText(x.right); + if (ts.isNewExpression(x) && x.expression.getText() === 'URL' && x.arguments && x.arguments.length >= 1) { + const p = urlText(x.arguments[0]); + if (x.arguments.length === 1 || /^https?:\/\//.test(p)) return p; + // O21: `new URL('../x.ttf', import.meta.url)` is a file next to the module, not a request + const ba = x.arguments[1]; + if (ts.isPropertyAccessExpression(ba) && ts.isMetaProperty(ba.expression) && ba.name.text === 'url') return FILE_URL; + const b = urlText(x.arguments[1]), o = b.match(/^https?:\/\/[^/?#]*/); + return (o ? o[0] : HOLE) + (p.startsWith('/') ? p : '/' + p); + } + const v = evalExpr(x); + return v.k === 'str' ? v.v : HOLE; +} +function localFetch(e) { + const a = e.arguments[0]; + if (!a) return; + const u = urlText(a); + let p = null, conf = ''; + const m = u.match(LOCAL_URL); + const sl = !m && u.match(/^https?:\/\/([A-Za-z0-9_-]+)(?::[^/?#]*)?([/?#].*)?$/); // R14a: a single-label host + if (m) p = m[1] || '/'; + else if (sl && !/^\d+$/.test(sl[1])) { p = sl[2] || '/'; conf = 'base_unknown'; } + else { + // R14: a base the program does not spell (a parameter, an env read, `env.X ?? 'http://localhost:3003'`) may reach + // this program's routes: joined on the path with confidence base_unknown. A literal external host never joins + const r = u.startsWith(HOLE) ? u.replace(/^\u0000+(?::[^/?#]*)?/, '') : /^https?:\/\/\u0000/.test(u) ? u.replace(/^https?:\/\/[^/?#]*/, '') : null; + if (r && r.startsWith('/')) { p = r; conf = 'base_unknown'; } + } + if (p == null) return; + // O21: a base_unknown path with no literal segment (`${base}/${key}`) names no route + if (conf && !p.split(/[?#]/)[0].split('/').some(x => x && x !== HOLE)) return; + const method = httpMethodOf(e.arguments[1]); + pendingRequests.push({ app: 'ANY_APP', method, path: (p.split(/[?#]/)[0]) || '/', from: enclosingFn(e), site: loc(e), local: true, conf }); +} +// a path with holes against a route pattern: a hole, a `:param` (any form) is one segment; a trailing `*` is the rest +function shapeMatch(route, p) { + const r = route.split('/').filter(Boolean), q = p.split('/').filter(Boolean); + for (let i = 0; i < r.length; i++) { + if (r[i] === '*' && i === r.length - 1) return true; + if (i >= q.length) return false; + // hono-5-07: `/api/skills${path}`: a segment of literal text then a hole that may span segments matches a route + // segment starting with that text, and anything after it + if (q[i] !== HOLE && q[i].includes(HOLE) && i === q.length - 1) return r[i].startsWith(q[i].split(HOLE)[0]) || (r[i].startsWith(':') && q[i].indexOf(HOLE) > 0); + if (q[i] === HOLE || r[i].startsWith(':') || r[i] === '*') continue; + if (r[i] !== q[i]) return false; + } + return r.length === q.length; +} +const CLIENT_VERBS = { $get: 'GET', $post: 'POST', $put: 'PUT', $delete: 'DELETE', $patch: 'PATCH', $options: 'OPTIONS' }; +function clientCall(c, name, e) { + if (name in CLIENT_VERBS) pendingRpc.push({ c, method: CLIENT_VERBS[name], from: enclosingFn(e), site: loc(e) }); + return UNK('client_response'); +} +const pendingRequests = [], pendingRpc = []; +const platformFns = new Set(); +const combinedFns = new Set(); + +// ── statements ────────────────────────────────────────────────────────────── +function evalBlock(stmts) { + for (const st of stmts) { const r = evalStmt(st); if (r) return r; } + return null; +} +function evalStmt(st) { + if (ts.isVariableStatement(st)) { + for (const d of st.declarationList.declarations) { + if (!d.initializer || env.has(d)) continue; + if (ts.isIdentifier(d.name)) env.set(d, evalExpr(d.initializer)); + // O30 (hono-7-01): a destructuring declaration evaluates its initializer ONCE; every name it binds reads that + // one value (valueOfDecl), so `const { a, b } = makeApps()` makes one set of apps, not one per name + else env.set(d, evalExpr(d.initializer)); + } + return null; + } + if (ts.isExpressionStatement(st)) { evalExpr(st.expression); return null; } + if (ts.isExportAssignment(st)) { + const v = evalExpr(st.expression); env.set(st, v); + // `export default { fetch: app.fetch, scheduled, queue }`: the platform calls the others too (SPEC 3.6) + if (v.k === 'obj' && v.props.has('fetch')) for (const k of ['scheduled', 'queue']) { + const p = v.props.get(k); if (!p) continue; + const f = p.val || evalExpr(p.node); if (f.k === 'fn') platformFns.add(loc(f.node)); + } + return null; + } + if (ts.isReturnStatement(st)) return st.expression ? evalExpr(st.expression) : UNK('void'); + if (ts.isIfStatement(st)) { + const r0 = condReason; condReason = 'conditional_registration'; condDepth++; + const s0 = entrySeq; + const rt = evalStmt(st.thenStatement); + const s1 = entrySeq; + const re = st.elseStatement ? evalStmt(st.elseStatement) : null; + // if / else each registering ONE middleware on the same app: one of them runs, at one chain position + if (st.elseStatement && s1 - s0 === 1 && entrySeq - s1 === 1) { + const a = stores.flatMap(x => x.entries).find(x => x.seq === s0 + 1), b = stores.flatMap(x => x.entries).find(x => x.seq === s1 + 1); + if (a && b && a.kind === 'mw' && b.kind === 'mw' && a.method === b.method && a.path === b.path && !a.alt && !b.alt + && stores.some(x => x.entries.includes(a) && x.entries.includes(b))) a.alt = b.alt = `a${++altSeq}`; + } + // R15 clause 2: if / else registering DIFFERENT numbers of middleware on one app: each branch starts at the same + // position, and every later position on a chain holding them is decided at run time (dynamic_middleware_list) + if (st.elseStatement && s1 > s0 && entrySeq > s1 && !(s1 - s0 === 1 && entrySeq - s1 === 1)) { + for (const store of stores) { + const tm = store.entries.filter(x => x.seq > s0 && x.seq <= s1 && x.kind === 'mw'); + const em = store.entries.filter(x => x.seq > s1 && x.seq <= entrySeq && x.kind === 'mw'); + if (!tm.length || !em.length || tm.length === em.length) continue; + const g = `b${++altSeq}`; + for (const x of tm) x.br = { g, side: 't' }; + for (const x of em) x.br = { g, side: 'e' }; + } + } + condDepth--; condReason = r0; + // a return inside a branch is one of the function's results (kept as an alternative, see inline) + for (const r of [rt, re]) if (r && retAlts.length) retAlts[retAlts.length - 1].push(r); + return null; + } + if ((ts.isForOfStatement(st) || ts.isForInStatement(st)) && ts.isVariableDeclarationList(st.initializer) && st.initializer.declarations.length === 1) { + let it = evalExpr(st.expression); + // `for (const k in obj)`: the keys of a known object (an import.meta.glob result, R12) + if (ts.isForInStatement(st)) it = it.k === 'obj' ? { k: 'list', items: [...it.props.keys()].map(v => ({ k: 'str', v })), derived: it.derived } : UNK('for_in'); + if (it.k === 'undef') return null; // a loop over an absent property runs no times + if (it.k === 'list') { + // a loop over a known list: the body runs once per element with the variable bound (still a loop registration); + // array and object patterns bind the element's parts (`for (const [, mod] of Object.entries(m))`) + const vd = st.initializer.declarations[0], r0 = condReason, saved = []; + const decls = []; (function ds(n) { if (ts.isIdentifier(n)) return; for (const el of n.elements) if (ts.isBindingElement(el)) { decls.push(el); ds(el.name); } })(vd.name); + for (const d of [vd, ...decls]) saved.push([d, env.get(d)]); + condReason = 'loop_registration'; condDepth++; + const lid = ++loopSeq; + it.items.forEach((item, idx) => { + if (item.k === 'undef') return; // a null element: the body guards it or throws, it mounts nothing + if (it.derived) loopCtx.push({ id: lid, idx, kind: it.derived }); + bindPattern(vd, vd.name, item); evalStmt(st.statement); + if (it.derived) loopCtx.pop(); + }); + condDepth--; condReason = r0; + for (const [d, v] of saved) { if (v === undefined) env.delete(d); else env.set(d, v); } + return null; + } + } + if (ts.isForOfStatement(st) || ts.isForStatement(st) || ts.isForInStatement(st) || ts.isWhileStatement(st)) { const r0 = condReason; condReason = 'loop_registration'; condDepth++; evalStmt(st.statement); condDepth--; condReason = r0; return null; } + if (ts.isBlock(st)) return evalBlock(st.statements); + return null; +} + +let condDepth = 0, condReason = '', loopSeq = 0; +// R13b: the derived (filtered / reordered) loops the evaluation is inside, with the element index of each +const loopCtx = []; +const loopTagNow = () => loopCtx.length ? loopCtx.map(c => `${c.id}:${c.idx}`) : undefined; +function bindPattern(decl, name, v) { + if (ts.isIdentifier(name)) { env.set(decl, v); return; } + if (ts.isArrayBindingPattern(name)) name.elements.forEach((el, i) => { if (ts.isBindingElement(el)) bindPattern(el, el.name, v.k === 'list' && v.items[i] ? v.items[i] : UNK('pattern')); }); + else if (ts.isObjectBindingPattern(name)) for (const el of name.elements) { + const key = (el.propertyName || el.name).getText(), p = v.k === 'obj' && v.props.get(key); + bindPattern(el, el.name, p ? pv_(p) : v.k === 'module' && moduleExportDecl(v.sf, key) ? valueOfDecl(moduleExportDecl(v.sf, key)) : UNK('pattern')); + } +} +const retAlts = []; +const evaluated = new Set(); +function evalModule(sf) { + if (evaluated.has(sf)) return; + evaluated.add(sf); + // imports first, in source order: ES module evaluation order + for (const st of sf.statements) { + const spec = (ts.isImportDeclaration(st) || ts.isExportDeclaration(st)) && st.moduleSpecifier && st.moduleSpecifier.text; + if (!spec || (ts.isImportDeclaration(st) && st.importClause && st.importClause.isTypeOnly)) continue; + const r = resolveSpec(spec, sf.fileName); + const dep = r && program.getSourceFile(r.resolvedFileName); + if (dep && srcFiles.includes(dep)) evalModule(dep); + } + for (const st of sf.statements) evalStmt(st); +} +phase('typechecked'); +for (const sf of srcFiles) evalModule(sf); +phase('modules evaluated'); +// O11: a method of an object literal that nothing in the program calls but that mounts sub-apps (a plugin's +// `register(app) { app.route('/x', sub) }`, called by a host over a run-time plugin list) still runs: its parameters +// are unknown, so the sub-apps it mounts are mounted under an unknown receiver (partial), never roots. It runs before +// the uncalled-function pass below, so a builder it calls makes the mounted app, not a second root +const mountsInside = f => { let hit = false; (function v(n) { if (hit) return; if (n !== f && ts.isFunctionLike(n)) return; if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression) && n.expression.name.text === 'route' && n.arguments.length >= 2) hit = true; ts.forEachChild(n, v); })(f.body); return hit; }; +for (const sf of srcFiles) (function v(n) { + if (ts.isObjectLiteralExpression(n)) for (const p of n.properties) { + const f = ts.isMethodDeclaration(p) ? p : ts.isPropertyAssignment(p) && (ts.isArrowFunction(p.initializer) || ts.isFunctionExpression(p.initializer)) ? p.initializer : null; + if (f && f.body && !inlinedFns.has(f) && !handlerFns.has(f) && mountsInside(f)) { pluginPass = true; inline(f, []); pluginPass = false; } + } + ts.forEachChild(n, v); +})(sf); +// O2: a module-level function nothing in the program calls (a server assembled inside `startServer(opts)`) +// still runs when its caller outside the program calls it: evaluate each such body once, parameters unknown +for (const sf of srcFiles) for (const st of sf.statements) { + const fns = []; + if (ts.isFunctionDeclaration(st) && st.body) fns.push(st); + if (ts.isVariableStatement(st)) for (const d of st.declarationList.declarations) if (d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer))) fns.push(d.initializer); + for (const f of fns) if (!inlinedFns.has(f) && !handlerFns.has(f)) inline(f, []); +} +phase('uncalled functions evaluated'); +// test and client code runs in functions nobody in the program calls (a test runner does): visit every +// `.request(...)` and `.$verb(...)` call not yet seen and evaluate its receiver: a read with no +// registration side effect, so it cannot add a route +const seenSites = new Set([...pendingRequests, ...pendingRpc].map(r => r.site)); +function sweep(n) { + // hono-3-02: the platform `fetch` to this machine (`http://localhost:${port}/x`) is a request to the served apps, + // matched on their composed full paths + if (ts.isCallExpression(n) && ts.isIdentifier(n.expression) && n.expression.text === 'fetch' && !seenSites.has(loc(n))) { + const d = declOf(n.expression); + if (!d || !isSrcDecl(d)) { seenSites.add(loc(n)); localFetch(n); } + } + if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression)) { + const nm = n.expression.name.text; + if ((nm === 'request' || nm === 'fetch' || nm in CLIENT_VERBS) && !seenSites.has(loc(n))) { + seenSites.add(loc(n)); + const recv = evalExpr(n.expression.expression); + if (recv.k === 'app' && (nm === 'request' || nm === 'fetch')) requestCall(recv, n, nm === 'fetch'); + else if (recv.k === 'client') clientCall(recv, nm, n); + } + } + ts.forEachChild(n, sweep); +} +srcFiles.forEach(sweep); + +phase('requests swept'); +// R12.2: when a mount reads its app from a module list the program cannot spell (`mod.default` over a run-time list), +// a default-exported app that no module imports, nothing mounts, and nothing serves (no `fetch` read, no fire()) may be +// one of those modules: its routes are partial (unresolved_mount), never exact roots. The module that performs the +// mount, and every module that imports it, is the entry, never a candidate +if (opaqueMounts.length) { + const imported = new Set(globbed), importsOf = new Map(); + for (const sf of srcFiles) { + const deps = []; + (function v(n) { + let spec = null; + if ((ts.isImportDeclaration(n) || ts.isExportDeclaration(n)) && n.moduleSpecifier && ts.isStringLiteralLike(n.moduleSpecifier)) spec = n.moduleSpecifier.text; + else if (ts.isCallExpression(n) && (n.expression.kind === ts.SyntaxKind.ImportKeyword || (ts.isIdentifier(n.expression) && n.expression.text === 'require')) && n.arguments[0] && ts.isStringLiteralLike(n.arguments[0])) spec = n.arguments[0].text; + if (spec) { const r = resolveSpec(spec, sf.fileName); const d = r && program.getSourceFile(r.resolvedFileName); if (d && srcFiles.includes(d)) { deps.push(d); imported.add(d); } } + ts.forEachChild(n, v); + })(sf); + importsOf.set(sf, deps); + } + const entry = new Set(opaqueMounts.map(e => e.getSourceFile())); + for (let grew = true; grew;) { grew = false; for (const [sf, deps] of importsOf) if (!entry.has(sf) && deps.some(d => entry.has(d))) { entry.add(sf); grew = true; } } + for (const sf of srcFiles) { + if (imported.has(sf) || entry.has(sf)) continue; + for (const st of sf.statements) { + const v = ts.isExportAssignment(st) && !st.isExportEquals ? env.get(st) : null; + if (!v || v.k !== 'app' || v.store.mounted || v.store.fetchRead) continue; + partialMount(v, 'unresolved_mount', opaqueMounts[0], []); + } + } +} +// ── results ───────────────────────────────────────────────────────────────── +// SPEC 3.3 rule 4: a verb registration whose function declares `next` and calls it is middleware +// for the later routes it matches +function callsNext(v) { + if (v.k !== 'fn' || !v.node.parameters || v.node.parameters.length < 2) return false; + const nx = v.node.parameters[1].name; if (!ts.isIdentifier(nx)) return false; + let hit = false; + (function f(n) { if (ts.isCallExpression(n) && ts.isIdentifier(n.expression) && n.expression.text === nx.text) hit = true; ts.forEachChild(n, f); })(v.node.body); + return hit; +} +function samplePath(p) { + // a concrete request path the pattern matches (checked below against the router itself) + return p.split('/').map(seg => { + if (seg === '*') return 'w'; + return seg.replace(/:([A-Za-z0-9_]+)(\{([^}]*)\})?\??/g, (_, n, __, re) => { + if (!re) return 'v1'; + for (const c of ['1', 'a', 'v1', 'x.png', 'abc', '2024']) if (new RegExp(`^(?:${re})$`).test(c)) return c; + return 'v1'; + }); + }).join('/').replace(/\*/g, 'w') || '/'; +} +// O24 / R13: an app that only a route-list entry holds, that nothing mounts, requests, reads `.fetch` of or makes a +// client for, is served at no path: no exact root. Its handlers routed by no other app are partial unresolved_mount +// (a loader the program does not show may mount the entry); handlers another app serves need nothing more +{ + const reqd = new Set([...pendingRequests, ...pendingRpc.map(r => ({ app: r.c.app }))].map(r => r.app && r.app.store).filter(Boolean)); + for (const st of stores) if (st.listEntry && !st.mounted && !st.fetchRead && !reqd.has(st)) st.dropped = true; + const routed = new Set(stores.filter(st => !st.dropped).flatMap(st => st.entries.filter(en => en.kind === 'handler').map(en => en.key))); + for (const st of stores.filter(x => x.dropped)) for (const en of st.entries) { + if (en.kind !== 'handler' || routed.has(en.key)) continue; + const V = en.method === 'ALL' ? 'ANY' : en.method; + out.partial.add(`${en.key}\t${V}\tunresolved_mount`); unknownAt(st.listEntry, 'unresolved_mount', en.key); + } +} +const roots = stores.filter(s => !s.mounted && !s.dropped); +const allFns = new Set(); +const chains = []; // { handler, chain:[keys], store } +for (const st of stores) { + for (const en of st.entries) if (en.val.k === 'fn') allFns.add(en.key); + for (const k of ['notFound', 'onError']) if (st[k]) allFns.add(loc(st[k].node)); + for (const f of st.foreign || []) allFns.add(f); + for (const m of st.dynMws || []) if (m.val.k === 'fn') allFns.add(m.key); // middleware registered on a rebased holder + if (st.mounted || st.dropped) continue; + const router = new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] }); + st.entries.forEach((en, i) => router.add(en.method, en.path, i)); + st.entries.forEach((en, i) => { + if (en.kind !== 'handler') return; + const V = en.method === 'ALL' ? 'ANY' : en.method; + out.route.push(`${V}\t${en.path}\t${en.key}\t${st.origin}\t${i}`); + // SPEC 4 [iter2] route_registered_by: the method enclosing the registering call + out.regby.add(`${en.regFn}\t${en.key}\t${V}\t${en.path}\t${st.origin}`); + const m = en.method === 'ALL' ? 'GET' : en.method; + const sp = samplePath(en.path); + let matched; + try { matched = router.match(m, sp)[0].map(x => x[0]); } catch (err) { matched = null; } + if (!matched || !matched.includes(i)) { out.unknown.add(`${en.site}\tORACLE_UNDECIDED_mw_chain\t${en.key}`); return; } + const chain = [], pos = []; + let dynamic = false, at = -1, lastAlt, brOpen = null; const brs = new Map(); + for (const j of matched) { + if (j === i) break; const x = st.entries[j]; if (x.kind === 'dyn') { dynamic = true; continue; } + // R15 clause 2: an unequal if / else pair: each branch counts from the same base; positions after it continue + // after the longer branch, and the chain is dynamic_middleware_list + if (x.br && (x.kind === 'mw' || callsNext(x.val))) { + const b = brs.get(x.br.g) || { base: at, t: 0, e: 0 }; brs.set(x.br.g, b); + const p = b.base + (++b[x.br.side]); at = Math.max(at, p); lastAlt = undefined; + chain.push(x.key); pos.push(p); brOpen = x.br.g; continue; + } + if (brOpen && (x.kind === 'mw' || callsNext(x.val))) dynamic = true; + // R13b: middleware another element of a filtered / reordered loop brought in may be absent or elsewhere + if (x.loopTag && x.loopTag.some(t => !(en.loopTag || []).includes(t)) && (x.kind === 'mw' || callsNext(x.val))) dynamic = true; + if ((x.kind === 'mw' || callsNext(x.val)) && !(x.val.except && x.val.except.includes(en.path))) { + if (!(x.alt && x.alt === lastAlt)) at++; // alternatives of one factory call share a position (hono-3-03) + lastAlt = x.alt; chain.push(x.key); pos.push(at); + } + } + if (dynamic) out.unknown.add(`${en.site}\tdynamic_middleware_list\t${en.key}`); + // R3: the served root app the chain belongs to is part of the row (one chain per app) + chain.forEach((mk, o) => out.mw.push(`${mk}\t${en.key}\t${V}\t${en.path}\t${pos[o]}\t${st.origin}`)); + chains.push({ handler: en.key, chain, store: st, entry: en }); + }); +} +for (const f of platformFns) allFns.add(f); +// a handler registered on a recognised app is an http entry point even when its path is only partly +// known (orchestrator ruling, iteration 1): the framework still calls it +for (const r of out.partial) { const k = r.split('\t')[0]; if (!k.startsWith('lib:')) allFns.add(k); } +for (const f of combinedFns) allFns.add(f); +for (const f of allFns) out.entry.add(`${f}\thttp`); + +// ctx: c.set(K) in a function of a chain -> c.get(K) / c.var.K in a later function of the same chain +const sets = new Map(), gets = new Map(); // fnloc -> Set(key) +function isContext(n) { + // untyped JavaScript: the first parameter of a function the router calls (a registered handler or middleware) + if (ts.isIdentifier(n)) { + const d = declOf(n); + if (d && ts.isParameter(d) && d.parent.parameters[0] === d && allFns.has(loc(d.parent))) return true; + } + const t = checker.getTypeAtLocation(n); + const s = t.getSymbol() || t.aliasSymbol; + const d = s && s.declarations && s.declarations[0]; + return !!(d && s.name === 'Context' && inPkg(d, ['hono'])); +} +// within ONE function a key flows to itself only when a read comes after a set (SPEC 3.4, j == i) +const firstSet = new Map(), lastGet = new Map(); +function notePos(f, k, isSet, pos) { + const key = f + '\t' + k; + if (isSet) { if (!firstSet.has(key) || pos < firstSet.get(key)) firstSet.set(key, pos); } + else if (!lastGet.has(key) || pos > lastGet.get(key)) lastGet.set(key, pos); +} +const selfFlows = (f, k) => firstSet.has(f + '\t' + k) && lastGet.has(f + '\t' + k) && firstSet.get(f + '\t' + k) < lastGet.get(f + '\t' + k); +// a set written after the middleware called `next` runs once every later function on the chain has +// returned: it is read back only in its own function (fnloc -> Set(key) of the sets made before `next`) +const setsBeforeNext = new Map(); +// the function whose context `c` is: a read or a write in a callback nested in it (`db.transaction(async +// (tx) => c.get(K))`) runs during the request, on that function's behalf +function ctxFnNode(c, n) { + const d = ts.isIdentifier(c) && declOf(c); + if (d && ts.isParameter(d) && ts.isFunctionLike(d.parent) && d.parent.body) return d.parent; + let fn = n.parent; + while (fn && !(ts.isFunctionLike(fn) && fn.body)) fn = fn.parent; + return fn; +} +const ctxFn = (c, n) => { const fn = ctxFnNode(c, n); return fn ? loc(fn) : enclosingFn(n); }; +function afterNext(n, c) { + const fn = ctxFnNode(c, n); + const p = fn && fn.parameters && fn.parameters[1]; + if (!p || !ts.isIdentifier(p.name)) return false; + const nextDecl = p; + let found = false; + // only a `next()` that runs on every path to the set: not in a branch, a loop, a try or a nested function + const guard = (x) => ts.isIfStatement(x) || ts.isConditionalExpression(x) || ts.isSwitchStatement(x) || ts.isIterationStatement(x, false) + || ts.isTryStatement(x) || ts.isFunctionLike(x) + || (ts.isBinaryExpression(x) && [ts.SyntaxKind.AmpersandAmpersandToken, ts.SyntaxKind.BarBarToken, ts.SyntaxKind.QuestionQuestionToken].includes(x.operatorToken.kind)); + (function walk(x) { + if (found || x.getStart() >= n.getStart() || guard(x)) return; + if (ts.isCallExpression(x) && ts.isIdentifier(x.expression) && declOf(x.expression) === nextDecl && x.getEnd() <= n.getStart()) { found = true; return; } + ts.forEachChild(x, walk); + })(fn.body); + return found; +} +function noteGet(f, k, pos) { if (!gets.has(f)) gets.set(f, new Set()); gets.get(f).add(k); notePos(f, k, false, pos); } +const isCtxVar = (e) => ts.isPropertyAccessExpression(e) && e.name.text === 'var' && isContext(e.expression); +function scanCtx(n) { + if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression) && ['set', 'get'].includes(n.expression.name.text) + && n.arguments[0] && ts.isStringLiteralLike(n.arguments[0]) && isContext(n.expression.expression)) { + const isSet = n.expression.name.text === 'set'; + const m = isSet ? sets : gets; + const f = ctxFn(n.expression.expression, n); if (!m.has(f)) m.set(f, new Set()); m.get(f).add(n.arguments[0].text); + if (isSet && !afterNext(n, n.expression.expression)) { if (!setsBeforeNext.has(f)) setsBeforeNext.set(f, new Set()); setsBeforeNext.get(f).add(n.arguments[0].text); } + notePos(f, n.arguments[0].text, isSet, n.getStart()); + } + if (ts.isPropertyAccessExpression(n) && isCtxVar(n.expression)) noteGet(ctxFn(n.expression.expression, n), n.name.text, n.getStart()); + // `const { K } = c.var`: each destructured property is a read of that key + if (ts.isVariableDeclaration(n) && n.initializer && ts.isObjectBindingPattern(n.name) && isCtxVar(n.initializer)) { + for (const el of n.name.elements) { + const k = el.propertyName ? el.propertyName.getText() : (ts.isIdentifier(el.name) ? el.name.text : null); + if (k && !el.dotDotDotToken) noteGet(ctxFn(n.initializer.expression, n), k, n.initializer.getStart()); + } + } + ts.forEachChild(n, scanCtx); +} +srcFiles.forEach(scanCtx); +for (const { handler, chain } of chains) { + const seq = [...chain, handler]; + seq.forEach((s, i) => { + for (const k of sets.get(s) || []) for (let j = i; j < seq.length; j++) if ((gets.get(seq[j]) || new Set()).has(k) + && (j > i ? (setsBeforeNext.get(s) || new Set()).has(k) : selfFlows(s, k))) out.ctx.add(`${s}\t${seq[j]}\t${k}`); + }); +} +// SPEC R23: a partial route's DECIDED chain (its `mwp` rows; a may-apply middleware is not in it) carries context keys +// exactly as an exact chain does: a setter at position p flows to a reader at a later position or to the handler +const pchains = new Map(); // handler -> [{ fn, at }] +{ const routed = new Set(out.route.map(r => r.split('\t')[2])); + for (const r of partialMw) { const [m, h, , at] = r.split('\t'); if (routed.has(h)) continue; + if (!pchains.has(h)) pchains.set(h, []); pchains.get(h).push({ fn: m, at: +at }); } } +for (const [h, ms] of pchains) { + const seq = [...ms, { fn: h, at: Infinity }]; + for (const a of seq) for (const k of sets.get(a.fn) || []) for (const b of seq) + if ((gets.get(b.fn) || new Set()).has(k) && (b.at > a.at || (b.fn === a.fn && selfFlows(a.fn, k)))) out.ctx.add(`${a.fn}\t${b.fn}\t${k}`); +} +// a reader whose key no function earlier on any of its chains sets: SPEC 3.4 no_setter_on_chain +for (const [r, keys] of gets) for (const k of keys) { + if ([...out.ctx].some(x => x.split('\t')[1] === r && x.split('\t')[2] === k)) continue; + if (!chains.some(c => c.handler === r || c.chain.includes(r)) && !pchains.has(r) && ![...pchains.values()].some(ms => ms.some(m => m.fn === r))) continue; + out.unknown.add(`${r}\tno_setter_on_chain\t${r}`); +} + +// rpc and app.request: matched by Hono's router on the target app's store +function routerFor(st) { + if (!st._router) { st._router = new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] }); st.entries.forEach((en, i) => st._router.add(en.method, en.path, i)); } + return st._router; +} +const verbOk = (en, m) => m === '*' || en.method === m || en.method === 'ALL'; +// R17: the first handler Hono's router picks for this path, per verb (every verb when the method is '*') +function firstHandlers(st, m, p) { + const out_ = []; + for (const v of m === '*' ? ANY_VERBS : [m === 'HEAD' ? 'GET' : m]) { + let hs; try { hs = routerFor(st).match(v, p)[0].map(x => st.entries[x[0]]); } catch { hs = []; } + const h = hs.find(x => x.kind === 'handler'); if (h && !out_.includes(h)) out_.push(h); + } + return out_; +} +const holeRows = (r, entries, p) => { + const hs = entries.filter(en => en.kind === 'handler' && verbOk(en, r.method) && shapeMatch(en.path, p)); + const shown = p.split(HOLE).join('${}'); + if (!hs.length) { out.unknown.add(`${r.site}\tdynamic_rpc_path\t${r.from}`); return; } + for (const h of hs) (r.c ? out.rpc : out.request).add(`${r.from}\t${r.method}\t${shown}\t${h.key}${r.method === '*' ? '\tmethod_unknown' : ''}`); +}; +for (const r of pendingRequests) { + if (r.app === 'ANY_APP') { + // a request to this machine: every served root app may answer; no row when none does (it may be another process) + const isTest = f => /(\.test\.|\.spec\.|__tests__\/)/.test(f); + for (const st of stores.filter(x => !x.mounted && !x.dropped)) { + const cf = r.conf ? `\t${r.conf}` : r.method === '*' ? '\tmethod_unknown' : ''; + // O21: a request whose base is unknown is not joined to a test file's app from outside test code + if (r.conf && isTest(st.origin) && !isTest(r.site)) continue; + if (r.path.includes(HOLE)) { for (const h of st.entries.filter(en => en.kind === 'handler' && verbOk(en, r.method) && shapeMatch(en.path, r.path))) out.request.add(`${r.from}\t${r.method}\t${r.path.split(HOLE).join('${}')}\t${h.key}${cf}`); continue; } + // O21: an unknown-base request reaching only a catch-all handler is no route match + for (const h of firstHandlers(st, r.method, r.path)) if (!(r.conf && /(^|\/)\*$/.test(h.path))) out.request.add(`${r.from}\t${r.method}\t${r.path}\t${h.key}${cf}`); + } + continue; + } + if (r.path.includes(HOLE)) { holeRows(r, r.app.store.entries, r.path); continue; } + const hs = firstHandlers(r.app.store, r.method, r.path); + for (const h of hs) out.request.add(`${r.from}\t${r.method}\t${r.path}\t${h.key}${r.method === '*' ? '\tmethod_unknown' : ''}`); + if (!hs.length) out.unserved.add(`${r.from}\t${r.method} ${r.path}`); +} +for (const r of pendingRpc) { + if (!r.c.app) { out.unknown.add(`${r.site}\tunresolved_rpc_app_type\t${r.from}`); continue; } + const segs = r.c.segs.filter(s => s !== 'index'); + const p = '/' + segs.join('/'); + // the client spells the PATTERN; it is served by the handler registered under exactly that pattern + const cand = r.c.app === 'ANY_APP' ? stores.filter(st => !st.mounted && !st.dropped).flatMap(st => st.entries) : r.c.app.store.entries; + if (p.includes(HOLE)) { holeRows(r, cand, p); continue; } + const hs = cand.filter(en => en.kind === 'handler' && (en.method === r.method || en.method === 'ALL') && en.path === p); + const h = hs[0]; + for (const x of hs.slice(1)) if (r.c.app === 'ANY_APP') out.rpc.add(`${r.from}\t${r.method}\t${p}\t${x.key}`); + if (h) out.rpc.add(`${r.from}\t${r.method}\t${p}\t${h.key}`); + else out.unserved.add(`${r.from}\t${r.method} ${p}`); +} + +// ── SPEC 3.9: route_schema and valid_read ────────────────────────────────── +// A schema is named by its DECLARATION: a const's name (`::` of the identifier, as the +// IR places a variable), or `expr@` for an inline schema. Composition carries it: every project +// schema const a schema is built from (extend/merge/pick/omit/partial, z.array(B), fields, .openapi()) is a +// base, and the route is reached from each base too. +function schemaKey(n) { + if (!n) return { key: 'expr@?', init: undefined }; // a createRoute schema slot with no expression node (stress-2 guard) + if (n.parent && ts.isShorthandPropertyAssignment(n.parent) && n.parent.name === n) { + // `{ schema }` shorthand: the schema is the variable the shorthand names + const vs = checker.getShorthandAssignmentValueSymbol(n.parent); const d = vs && vs.valueDeclaration; + if (d && ts.isVariableDeclaration(d) && isSrcDecl(d) && d.initializer) return { key: loc(d.name), init: d.initializer }; + } + while (ts.isParenthesizedExpression(n) || ts.isAsExpression(n) || ts.isSatisfiesExpression?.(n)) n = n.expression; + if (ts.isIdentifier(n) || ts.isPropertyAccessExpression(n)) { + const d = declOf(ts.isPropertyAccessExpression(n) ? n.name : n); + if (d && ts.isVariableDeclaration(d) && isSrcDecl(d) && d.initializer) return { key: loc(d.name), init: d.initializer }; + } + return { key: `expr@${loc(n)}`, init: n }; +} +function schemaBases(init, seen = new Set()) { + const out = []; + if (!init) return out; // stress-2 guard + (function v(n) { + if (ts.isIdentifier(n) && !(ts.isPropertyAccessExpression(n.parent) && n.parent.name === n)) { + const d = declOf(n); + if (d && ts.isVariableDeclaration(d) && isSrcDecl(d) && d.initializer && !seen.has(d) + && !ts.isArrowFunction(d.initializer) && !ts.isFunctionExpression(d.initializer)) { // O19: a helper is no schema + seen.add(d); + if (/\bz\.|\.(extend|merge|pick|omit|partial|openapi)\(/.test(d.initializer.getText())) { out.push(loc(d.name)); out.push(...schemaBases(d.initializer, seen)); } + } + } + ts.forEachChild(n, v); + })(init); + return out; +} +const schemaRows = new Set(), validRows = new Set(); +for (const { handler, chain, store, entry } of chains) { + const byTarget = new Map(); + const add = (target, node) => { const sk = schemaKey(node); byTarget.set(target, sk.key); for (const k of [sk.key, ...schemaBases(sk.init)]) schemaRows.add(`${handler}\t${target}\t${k}`); }; + for (const mk of chain) { + const mv = store.entries.find(x => x.key === mk); + const vd = mv && mv.val.validator; + if (vd) { if (vd.schema) add(vd.target, vd.schema); else byTarget.set(vd.target, null); } + } + if (entry.routedef) for (const [t, n] of entry.routedef.schemas) if (t !== 'response') add(t, n); else { const sk = schemaKey(n); for (const k of [sk.key, ...schemaBases(sk.init)]) schemaRows.add(`${handler}\t${t}\t${k}`); } + entry.validTargets = byTarget; +} +function scanValid(n) { + if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression) && n.expression.name.text === 'valid' + && ts.isPropertyAccessExpression(n.expression.expression) && n.expression.expression.name.text === 'req' + && isContext(n.expression.expression.expression) && n.arguments[0] && ts.isStringLiteralLike(n.arguments[0])) { + const f = enclosingFn(n), t = n.arguments[0].text; + for (const c of chains) if (c.handler === f) { + if (c.entry.validTargets.has(t)) { const sk = c.entry.validTargets.get(t); if (sk !== null) validRows.add(`${loc(n)}\t${f}\t${t}\t${sk === null ? '-' : sk}`); } + else out.unknown.add(`${loc(n)}\tvalid_without_validator\t${f}`); + } + } + ts.forEachChild(n, scanValid); +} +srcFiles.forEach(scanValid); + +phase('results'); +const lines = []; +for (const r of new Set(out.route)) lines.push(`route\t${r}`); // O29: first occurrence only +for (const r of new Set(out.mw)) lines.push(`mw\t${r}`); +for (const r of [...out.entry].sort()) lines.push(`entry\t${r}`); +for (const r of [...out.ctx].sort()) lines.push(`ctx\t${r}`); +for (const r of [...out.rpc].sort()) lines.push(`rpc\t${r}`); +for (const r of [...out.request].sort()) lines.push(`request\t${r}`); +for (const r of new Set(out.submount)) lines.push(`submount\t${r}`); +for (const r of [...schemaRows].sort()) lines.push(`schema\t${r}`); +for (const r of [...validRows].sort()) lines.push(`validread\t${r}`); +// O12: a handler with a route row is not also partial (nor its partial reason rows) +{ + const routed = new Set(out.route.map(r => r.split('\t')[2])); + const PARTIAL_REASONS = new Set(['unresolved_app_value', 'unresolved_mount', 'dynamic_mount_prefix', 'dynamic_route_path', 'dynamic_verb']); + for (const r of [...out.partial]) if (routed.has(r.split('\t')[0])) out.partial.delete(r); + for (const r of [...out.unknown]) { const c = r.split('\t'); if (PARTIAL_REASONS.has(c[1]) && routed.has(c[2])) out.unknown.delete(r); } +} +for (const r of [...out.partial].sort()) lines.push(`partial\t${r}`); +// a handler with a route row has no partial row (O12 above), so no partial path either +if (PARTIAL_PATHS) { const routed = new Set(out.route.map(r => r.split('\t')[2])); for (const r of [...out.ppath].sort()) if (!routed.has(r.split('\t')[0])) lines.push(`ppath\t${r}`); } +{ const routed = new Set(out.route.map(r => r.split('\t')[2])); for (const r of [...partialMw].sort()) if (!routed.has(r.split('\t')[1])) lines.push(`mwp\t${r}`); } +for (const r of [...out.regby].sort()) lines.push(`regby\t${r}`); +for (const r of [...out.unserved].sort()) lines.push(`unserved\t${r}`); +for (const r of [...out.unknown].sort()) lines.push(`unknown\t${r}`); +// --stores: every store's full entry list in registration order, for the runtime cross-check +// (a mount's runtime handler is hono's wrapper: shown as a library entry; a dynamic marker is no runtime entry) +if (STORES) for (const st of stores) st.entries.filter(en => en.kind !== 'dyn').forEach((en, i) => lines.push(`store\t${st.origin}#${st.id}\t${st.mounted ? 'mounted' : st.dropped ? 'unserved' : 'root'}\t${i}\t${en.method}\t${en.path}\t${en.mount ? 'lib:mount' : en.key}\t${en.kind}\t${en.alt || ''}`)); +// streamed: one joined string exceeds V8's maximum string length on a 400-route project (stress-2 guard) +// O29: every row is printed ONCE. The same (route|mw|submount) row is reached again for each store that shares a +// registration (a sub-app mounted under several parents, a builder called per test); goldens are sets, so this changes +// no committed expectation, but a row repeated 1000x inflated count-based scores and wrote a 1.1 GB file +{ const seen = new Set(); let buf = []; for (const l of lines) { if (seen.has(l)) continue; seen.add(l); buf.push(l); if (buf.length >= 20000) { fs.writeSync(1, buf.join('\n') + '\n'); buf = []; } } if (buf.length) fs.writeSync(1, buf.join('\n') + '\n'); } diff --git a/graph/test/typescript/hono/truth/package.json b/graph/test/typescript/hono/truth/package.json new file mode 100644 index 000000000..6e8380adb --- /dev/null +++ b/graph/test/typescript/hono/truth/package.json @@ -0,0 +1,14 @@ +{ + "name": "hono-torture-oracle", + "private": true, + "description": "Independent ground truth for the Hono torture suites: the TypeScript compiler API plus the real hono package. Never imports the axiom parser.", + "type": "module", + "dependencies": { + "typescript": "5.9.3", + "hono": "4.13.13", + "@hono/zod-openapi": "1.6.3", + "zod": "4.1.13", + "@hono/zod-validator": "0.9.1", + "@hono/node-server": "2.1.3" + } +} diff --git a/graph/test/typescript/hono/truth/runtime-check.mjs b/graph/test/typescript/hono/truth/runtime-check.mjs new file mode 100644 index 000000000..7a866b13d --- /dev/null +++ b/graph/test/typescript/hono/truth/runtime-check.mjs @@ -0,0 +1,173 @@ +#!/usr/bin/env node +// ───────────────────────────────────────────────────────────────────────────── +// Hono torture oracle: the RUNTIME half. +// +// Runs the fixture with the pinned `hono` and reads what Hono itself built: `app.routes` of every +// Hono instance a module exports, in registration order, each handler mapped back to its source +// function through V8's [[FunctionLocation]] (node strips TypeScript types in place, so positions +// are the source's own). The static oracle's store for that app must hold the SAME sequence of +// (method, full path, handler). This is the strongest truth for route / basePath / mount: it is +// not a model of Hono, it is Hono. +// +// usage: node runtime-check.mjs +// stdout: `runtime agree ` | `runtime skip `; exit 1 on disagreement. +// ───────────────────────────────────────────────────────────────────────────── +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { register } from 'node:module'; +import inspector from 'node:inspector'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const { loadTypeScript } = await import(new URL('../../ground-truth/load-typescript.mjs', import.meta.url).href); +const ts = loadTypeScript(HERE, { toolName: 'hono-runtime-check' }); +const SRC = path.resolve(process.argv[2]); +const STATIC = fs.readFileSync(process.argv[3], 'utf8'); + +const files = []; +(function walk(d) { + for (const e of fs.readdirSync(d, { withFileTypes: true })) { + if (e.name === 'node_modules' || e.name.startsWith('.')) continue; + const p = path.join(d, e.name); + if (e.isDirectory()) walk(p); else if (/\.(ts|mts|js|mjs|cjs)$/.test(e.name) && !e.name.endsWith('.d.ts')) files.push(p); + } +})(SRC); +if (fs.readdirSync(SRC, { recursive: true }).some(f => /\.(tsx|jsx)$/.test(f))) { console.log('runtime skip jsx'); process.exit(0); } +// a fixture that only exists to be parsed (a test file, a client, a worker entry) can opt out by name +const SKIP = /(\.test\.|\.spec\.|client)/; + +// work copy: the fixture plus the oracle's node_modules, so `hono` is the pinned package +const W = fs.mkdtempSync(path.join(os.tmpdir(), 'hono-rt-')); +fs.cpSync(SRC, W, { recursive: true }); +fs.symlinkSync(path.join(HERE, 'node_modules'), path.join(W, 'node_modules')); +if (!fs.existsSync(path.join(W, 'package.json'))) fs.writeFileSync(path.join(W, 'package.json'), '{"type":"module"}'); +register(pathToFileURL(path.join(HERE, 'runtime-hooks.mjs')).href); + +const session = new inspector.Session(); +session.connect(); +const scripts = new Map(); +session.on('Debugger.scriptParsed', m => scripts.set(m.params.scriptId, m.params.url)); +const post = (m, p) => new Promise((res, rej) => session.post(m, p, (e, r) => e ? rej(e) : res(r))); +await post('Debugger.enable'); + +const { HonoBase } = await import(pathToFileURL(path.join(HERE, 'node_modules/hono/dist/hono-base.js')).href); +const COMPOSED = '__COMPOSED_HANDLER'; // hono/dist/utils/constants.js +const realW = fs.realpathSync(W); +const exported = new Set(); +let loadErr = null; +for (const f of files.map(f => path.join(realW, path.relative(SRC, f))).sort()) { + if (SKIP.test(path.basename(f))) continue; + try { + const ns = await import(pathToFileURL(f).href); + // a CommonJS fixture gets hono's cjs build, a different class object: recognise the instance by shape too + for (const v of Object.values(ns)) if (v instanceof HonoBase || (v && Array.isArray(v.routes) && v.router && typeof v.fetch === 'function')) exported.add(v); + } catch (e) { loadErr = `${path.relative(realW, f)}: ${String(e.message || e).split('\n')[0]}`; } +} +if (!exported.size) { console.log(`runtime skip ${loadErr ? 'not loadable (' + loadErr + ')' : 'no exported Hono instance'}`); cleanup(); process.exit(0); } + +// function -> static key `::` of the innermost function node containing V8's position +const sfCache = new Map(); +function keyAt(file, line0, col0) { + if (!sfCache.has(file)) sfCache.set(file, ts.createSourceFile(file, fs.readFileSync(file, 'utf8'), ts.ScriptTarget.Latest, true)); + const sf = sfCache.get(file); + const pos = sf.getPositionOfLineAndCharacter(line0, col0); + let best = null; + (function visit(n) { + if (n.getStart(sf) <= pos && pos < n.end) { + if (ts.isFunctionLike(n) && n.body) best = n; + ts.forEachChild(n, visit); + } + })(sf); + if (!best) return null; + const p = sf.getLineAndCharacterOfPosition(best.getStart(sf)); + return `${path.relative(realW, file).split(path.sep).join('/')}:${p.line + 1}:${p.character + 1}`; +} +async function fnKey(fn) { + if (fn[COMPOSED]) fn = fn[COMPOSED]; + globalThis.__probe = fn; + const { result } = await post('Runtime.evaluate', { expression: 'globalThis.__probe' }); + const { internalProperties } = await post('Runtime.getProperties', { objectId: result.objectId, ownProperties: true }); + const fl = (internalProperties || []).find(p => p.name === '[[FunctionLocation]]'); + if (!fl) return 'lib'; + const url = scripts.get(fl.value.value.scriptId) || ''; + if (!url.startsWith('file:')) return 'lib'; + const file = fileURLToPath(url); + if (!file.startsWith(realW + path.sep) || file.includes(`${path.sep}node_modules${path.sep}`)) return 'lib'; + return keyAt(file, fl.value.value.lineNumber, fl.value.value.columnNumber) || 'lib'; +} + +// static stores: origin -> [{method,path,key}] +const stores = new Map(); +for (const l of STATIC.split('\n')) { + const c = l.split('\t'); + if (c[0] !== 'store') continue; + if (!stores.has(c[1])) stores.set(c[1], []); + const st = stores.get(c[1]), last = st[st.length - 1]; + // alternatives of one factory call (a branch returns one middleware, the rest another): one run registers ONE + // of them, so the group is a single static entry that any of its keys satisfies + if (c[8] && last && last.alt === c[8]) { last.keys.push(c[6]); continue; } + st.push({ method: c[4], path: c[5], key: c[6], keys: [c[6]], alt: c[8] || '' }); +} +// a registration the static half declared undetermined (a run-time path) is not in its store: the +// runtime value is one execution's answer, not the program's +const undetermined = new Set(STATIC.split('\n').filter(l => l.startsWith('partial\t')).map(l => l.split('\t')[1])); +// a registration behind a condition or in a loop: one run takes one path; compare only the rest +const conditional = new Set(STATIC.split('\n').filter(l => /^unknown\t.*\t(conditional|loop)_registration\t/.test(l)).map(l => l.split('\t')[3])); +for (const k of conditional) undetermined.add(k); +// hono-7-05: a middleware the static half places ONLY on partial routes (`mwp` rows, never an `mw` row) was registered on +// a sub-app mounted under a run-time prefix: its runtime path is that one execution's prefix, so it is not compared +{ + const placed = new Set(STATIC.split('\n').filter(l => l.startsWith('mw\t')).map(l => l.split('\t')[1])); + for (const l of STATIC.split('\n')) if (l.startsWith('mwp\t') && !placed.has(l.split('\t')[1])) undetermined.add(l.split('\t')[1]); +} +const staticRouteKeys = new Set(STATIC.split('\n').filter(l => l.startsWith('route\t')).map(l => l.split('\t')[3]).filter(k => !k.startsWith('lib'))); +for (const [, st] of stores) for (let i = st.length - 1; i >= 0; i--) if (st[i].keys.some(k => conditional.has(k))) st.splice(i, 1); +function aligns(rt, st) { + // user functions must align one for one; a runtime library entry the static model does not + // spell (a validator a library inserts on its own) may be skipped, never a user function + let i = 0, j = 0, n = 0; + while (i < rt.length && j < st.length) { + const a = rt[i], b = st[j]; + const same = a.method === b.method && a.path === b.path && b.keys.some(k => a.key === k || (a.key === 'lib' && k.startsWith('lib:'))); + if (same) { i++; j++; n++; continue; } + if (a.key === 'lib') { i++; continue; } + return { ok: false, at: `runtime #${i} ${a.method} ${a.path} ${a.key} vs static #${j} ${b.method} ${b.path} ${b.key}` }; + } + while (i < rt.length && rt[i].key === 'lib') i++; + return i === rt.length && j === st.length ? { ok: true, n } : { ok: false, at: `length runtime ${rt.length - i} left, static ${st.length - j} left` }; +} +let compared = 0, bad = []; +const ppaths = new Map(STATIC.split('\n').filter(l => l.startsWith('ppath\t')).map(l => { const c = l.split('\t'); return [`${c[1]}\t${c[2]}`, c[3]]; })); +const ppathSeen = new Map(), ppathOk = new Set(); +const seen = new Set(); +for (const app of exported) { + if (seen.has(app.routes)) continue; seen.add(app.routes); + const rt = []; + for (const r of app.routes) { const key = await fnKey(r.handler); r.handlerKey = key; if (!undetermined.has(key)) rt.push({ method: r.method, path: r.path, key }); } + // hono-7-05: a partial route's known path (`ppath`, --partial-paths) must match a path this run registered for it, a + // `{}` standing for the run-time piece (one or more segments); the sub-app's own unprefixed copy is not that path + for (const r of app.routes) { + const k = `${r.handlerKey}\t${r.method === 'ALL' ? 'ANY' : r.method}`, pp = ppaths.get(k); + if (!pp) continue; + const re = new RegExp('^' + pp.split('{}').map(x => x.replace(/[.*+?^$()|[\]\\]/g, '\\$&')).join('[^/]+(?:/[^/]+)*') + '$'); + if (!ppathSeen.has(k)) ppathSeen.set(k, []); + if (re.test(r.path)) ppathOk.add(k); else ppathSeen.get(k).push(r.path); + } + if (!rt.length) continue; // every registration of this app is one the static half declared undetermined + // an app whose every ROUTE the static half declared undetermined (partial): its middleware alone is no route list + // to compare (the static half keeps a partial route's chain as `mwp` rows, without a store) + if (rt.every(r => !staticRouteKeys.has(r.key)) && app.routes.some(r => undetermined.has(r.handlerKey))) continue; + let best = null; + for (const [origin, st] of stores) { const a = aligns(rt, st); if (a.ok) { best = a; break; } best = best || { ...a, origin }; } + if (best && best.ok) compared += best.n; + else bad.push(`no static store matches an exported app: ${best ? best.at : 'no stores'}\n runtime: ${rt.map(r => `${r.method} ${r.path} ${r.key}`).join(' | ')}`); +} +for (const [k, paths] of ppathSeen) if (!ppathOk.has(k)) bad.push(`partial path ${ppaths.get(k)} of ${k.split('\t')[0]} matches no runtime path (${paths.join(', ')})`); +const ppathChecked = ppathOk.size; +cleanup(); +if (bad.length) { console.log(`runtime DISAGREE\n ${bad.join('\n ')}`); process.exit(1); } +if (compared < 1) { console.log('runtime skip every exported route is declared undetermined by the static half'); process.exit(0); } +console.log(`runtime agree ${compared} entries over ${seen.size} app(s)${ppaths.size ? `, ${ppathChecked}/${ppaths.size} partial paths matched` : ''}`); +process.exit(0); +function cleanup() { try { fs.rmSync(W, { recursive: true, force: true }); } catch { } } diff --git a/graph/test/typescript/hono/truth/runtime-hooks.mjs b/graph/test/typescript/hono/truth/runtime-hooks.mjs new file mode 100644 index 000000000..c3be5718e --- /dev/null +++ b/graph/test/typescript/hono/truth/runtime-hooks.mjs @@ -0,0 +1,20 @@ +// Module resolution hooks for the runtime cross-check: a fixture written for a bundler imports +// `./users` (no extension) or `./users.js` meaning `./users.ts`. Node's own resolver refuses both; +// this tries the candidates a bundler would, in its order, and nothing else. +import fs from 'node:fs'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const CANDIDATES = ['', '.ts', '.mts', '.js', '.mjs', '/index.ts', '/index.js']; +export async function resolve(specifier, context, next) { + if ((specifier.startsWith('./') || specifier.startsWith('../')) && context.parentURL) { + const base = new URL(specifier, context.parentURL); + const p = fileURLToPath(base); + const stems = [p]; + if (/\.js$/.test(p)) stems.push(p.replace(/\.js$/, '.ts')); + for (const s of stems) for (const c of CANDIDATES) { + const f = s + c; + try { if (fs.statSync(f).isFile()) return next(pathToFileURL(f).href, context); } catch { } + } + } + return next(specifier, context); +} diff --git a/graph/test/typescript/tools/normalize_edges.py b/graph/test/typescript/tools/normalize_edges.py index 9807d7574..33528f3b0 100644 --- a/graph/test/typescript/tools/normalize_edges.py +++ b/graph/test/typescript/tools/normalize_edges.py @@ -284,8 +284,10 @@ def main(): continue # a function the site HANDS OVER (`xs.map(cb)`) is not a call the compiler lists at that # site, nor is the handler a publish reaches through a keyed registry (`event_dispatch`): the - # pairs are scored against the compiler, the .edges golden still carries both - if f[5] in ('callback_registered', 'event_dispatch'): + # pairs are scored against the compiler, the .edges golden still carries both. A function handed + # to a PROJECT function (`apply(upper, s)`, `callback_handed`) is the same hand-over: the compiler + # resolves that site to `apply`, which the pairs already score, never to `upper` + if f[5] in ('callback_registered', 'callback_handed', 'event_dispatch'): continue seen.add(f"{n.label(f[1])} -> {n.label(f[3])}") else: diff --git a/graph/typescript/engine/call-edge-generation/call_chain.dl b/graph/typescript/engine/call-edge-generation/call_chain.dl index 890a08ad5..f46673609 100644 --- a/graph/typescript/engine/call-edge-generation/call_chain.dl +++ b/graph/typescript/engine/call-edge-generation/call_chain.dl @@ -134,6 +134,51 @@ call_chain_edge(ce, caller, "-", m, "client", "callback_registered", kind) :- caller != m, invocation_site(ce, kind). +// …and a function handed to a PROJECT function (`withRetry(2, () => load(id))`, `tryit(purge)`): the +// site hands it over exactly as it does to a library one, and the compiler names the hop. The callee's +// body, which runs it, keeps its own edge (fn_value_call); this one is the site's, so it carries the +// hand-over and nothing from another caller. +// +// Only where the hand-over can run it. A getter read (`new Context(Request.empty)`) hands over what the +// getter RETURNS, not the getter. A body that never reads the parameter (`on(_e, _listener) {}`), or +// only compares it (`c === undefined`), cannot run what it was given. And a keyed registry's slot +// (keyed_registry.dl) is run by the publish on the same key, not by the subscribe that files it. +call_chain_edge(ce, caller, "-", m, "client", "callback_handed", kind) :- + cb_handed_arg(ce, pos, m), + cb_handed_live(ce, pos), + call_from(ce, caller), + caller != m, + invocation_site(ce, kind). + +.decl cb_handed_arg(c0:symbol, c1:symbol, c2:symbol) // (call, argument position, function handed there) +.decl cb_handed_live(c0:symbol, c1:symbol) // (call, position): a body that runs the call may run it +.decl cb_param_runs(c0:symbol) // a parameter whose value the body can call or pass on +.decl cb_ref_inert(c0:symbol) // a reference that only tests the value +.decl cb_inert_op(c0:symbol) +cb_handed_arg(ce, pos, m) :- call_runs_client_body(ce), + expr_child("client", ce, "ARGUMENT", pos, a), + !expr_kind("client", "CALL_EXPRESSION", _, a), + expr_callable(a, m), + !method_is_accessor(m), + method_prov(m, "client"). +// a position with no parameter of its own: a rest parameter's tail, or `arguments` +cb_handed_live(ce, pos) :- cb_handed_arg(ce, pos, _), call_runs_method(ce, b), method_prov(b, "client"), + !param_decl("client", _, pos, _, b, _). +cb_handed_live(ce, pos) :- cb_handed_arg(ce, pos, _), call_runs_method(ce, b), method_prov(b, "client"), + param_decl("client", _, pos, _, b, p), !kr_registry_param(p), cb_param_runs(p). +cb_param_runs(p) :- expr_referenced("client", "PARAMETER", p, e), !cb_ref_inert(e). +// a parameter property (`constructor(private readonly onTimeout: () => void)`) is also a field: the class +// runs it through `this.onTimeout` wherever the field is read, though the constructor never names it +cb_param_runs(p) :- param_declares_field("client", f, p), expr_holder(_, f). +cb_ref_inert(e) :- expr_referenced("client", "PARAMETER", _, e), expr_child("client", x, _, _, e), + expr_operator("client", op, x), cb_inert_op(op). +cb_inert_op("==="). +cb_inert_op("!=="). +cb_inert_op("=="). +cb_inert_op("!="). +cb_inert_op("typeof"). +cb_inert_op("!"). + // …and a function written inside a JSX `{…}` (resolution/value-flow.dl, jsx_handed_value). The `{…}` is // the site: an intrinsic tag has no call site of its own, and the expression positions the edge. call_chain_edge(r, caller, "-", m, "client", "callback_registered", "JSX_COMPONENT_CALL") :- diff --git a/graph/typescript/engine/config-resolution/entry-points.dl b/graph/typescript/engine/config-resolution/entry-points.dl index 638f4121d..95058f93c 100644 --- a/graph/typescript/engine/config-resolution/entry-points.dl +++ b/graph/typescript/engine/config-resolution/entry-points.dl @@ -29,11 +29,16 @@ // parser's general name column and holds the identifier for an IDENTIFIER_REFERENCE, // so reading it unguarded turns variables into strings. cfg_path_arg(ce) :- expr_child("client", ce, "ARGUMENT", _, a), - expr_literal_type("client", "STRING", a), + cfg_string_literal_type(t), expr_literal_type("client", t, a), expr_literal_value("client", v, a), strlen(v) >= 1, substr(v, 0, 1) = "/". +// a backtick string with no `${}` is a string as much as a quoted one is +.decl cfg_string_literal_type(c0:symbol) +cfg_string_literal_type("STRING"). +cfg_string_literal_type("NO_SUBSTITUTION_TEMPLATE"). + // ── a NAMED function passed by reference as an argument ───────────────────── // `callback_arg` holds only for an ARROW_FUNCTION or FUNCTION_EXPRESSION written at // the site, because it reads `expr_anon_decl` -- the declaration an expression diff --git a/graph/typescript/engine/config-resolution/http-router-apps.dl b/graph/typescript/engine/config-resolution/http-router-apps.dl new file mode 100644 index 000000000..2e29dcd35 --- /dev/null +++ b/graph/typescript/engine/config-resolution/http-router-apps.dl @@ -0,0 +1,1205 @@ +// ============================================================================ +// CONFIG-RESOLUTION · HTTP ROUTER APPLICATIONS (which values are apps) +// +// An application object is built once (`new X()` of a class a knob names, imported +// from the module the knob names) and then carries a LIST of registrations: routes, +// middleware, mounted sub-applications. This file answers "which expressions hold an +// app, and which list do registrations on them land in"; http-router-routes.dl turns +// the lists into the route table. +// +// ── THE LIST, NOT THE OBJECT ──────────────────────────────────────────────── +// `basePath(p)` returns a NEW object that shares the original's route list, its own +// registrations prefixed by p. So an app value is (List, Base): the list a registration +// lands in, and the prefix it gets there. A list is identified by the expression that +// created it: +// * a construction `new X()`; +// * a CALL of a function that constructs and returns one (`createApp()`): every call +// is its own list, which INCLUDES the registrations the function made on the one it +// constructed (the template), at the call's position; +// * a PARAMETER an app is passed into (`registerUsers(app)`): its registrations are +// included into each passing caller's list, at the call's position, under the +// passed value's base. A parameter declared with the app class and passed nothing +// is a list of its own, whose paths cannot be completed. +// +// ── TWO STRATA ────────────────────────────────────────────────────────────── +// hr_app(Expr, List) knows no strings. It is what decides which path arguments are +// worth evaluating (rd_demand), so it may not depend on the evaluation itself, or the +// program would read a string to decide whether to read that string. hr_val(Expr, +// List, Base) repeats the same flow with the base attached, after rd_val. +// +// Framework names live in knobs.dl only (router_*). +// ============================================================================ + +// ── a specifier as the package it names ───────────────────────────────────── +// `npm:x@4/sub` and `jsr:@s/x@^4/sub` are `x/sub` and `@s/x/sub`; a URL under a knob +// prefix is the package (`/mod.ts`) or its subpath; anything else is itself. +.decl hr_spec_raw(c0:symbol) +hr_spec_raw(raw) :- rd_import_path(_, raw). +.decl hr_unscheme(c0:symbol, c1:symbol) +hr_unscheme(raw, x) :- hr_spec_raw(raw), router_spec_scheme(s), strlen(raw) > strlen(s), + substr(raw, 0, strlen(s)) = s, x = substr(raw, strlen(s), strlen(raw) - strlen(s)). +.decl hr_ver_at(c0:symbol, c1:number) +hr_ver_at(x, i) :- hr_unscheme(_, x), i = range(1, strlen(x)), substr(x, i, 1) = "@". +.decl hr_slash_after(c0:symbol, c1:number, c2:number) +hr_slash_after(x, i, j) :- hr_ver_at(x, i), j = range(i, strlen(x)), substr(x, j, 1) = "/". +.decl hr_ver_end(c0:symbol, c1:number, c2:number) +hr_ver_end(x, i, j) :- hr_ver_at(x, i), j = min y : { hr_slash_after(x, i, y) }. +hr_ver_end(x, i, strlen(x)) :- hr_ver_at(x, i), !hr_slash_after(x, i, _). +.decl hr_spec(c0:symbol, c1:symbol) +hr_spec(raw, raw) :- hr_spec_raw(raw). +hr_spec(raw, x) :- hr_unscheme(raw, x), !hr_ver_at(x, _). +hr_spec(raw, y) :- hr_unscheme(raw, x), hr_ver_at(x, i), hr_ver_end(x, i, j), + y = cat(substr(x, 0, i), substr(x, j, strlen(x) - j)). +.decl hr_url_rest(c0:symbol, c1:symbol, c2:symbol) +hr_url_rest(raw, pkg, rest) :- hr_spec_raw(raw), router_spec_url(pre, pkg), strlen(raw) > strlen(pre), + substr(raw, 0, strlen(pre)) = pre, rest = substr(raw, strlen(pre), strlen(raw) - strlen(pre)). +.decl hr_url_path(c0:symbol, c1:symbol, c2:symbol) +hr_url_path(raw, pkg, rest) :- hr_url_rest(raw, pkg, rest), substr(rest, 0, 1) = "/". +hr_url_path(raw, pkg, r2) :- hr_url_rest(raw, pkg, rest), substr(rest, 0, 1) = "@", + j = min y : { y = range(0, strlen(rest)), substr(rest, y, 1) = "/" }, r2 = substr(rest, j, strlen(rest) - j). +hr_spec(raw, pkg) :- hr_url_path(raw, pkg, "/mod.ts"). +.decl hr_import_spec(c0:symbol, c1:symbol) +hr_import_spec(ih, s) :- rd_import_path(ih, raw), hr_spec(raw, s). + +// ── does this program import the framework at all? ────────────────────────── +// Every app, client and validator above is recognised through an import of a module a knob +// names, so a program that imports none of them has no route table. hr_on() holds when one +// is imported; each rule below that would otherwise read the whole program (every call, every +// identifier, every return) is guarded by it, so on any other program they cost nothing. When +// it holds the rules are exactly the unguarded ones. +.decl hr_knob_spec(c0:symbol) +hr_knob_spec(s) :- router_app_class(s, _). +hr_knob_spec(s) :- router_factory(s, _). +hr_knob_spec(s) :- router_rpc_client(s, _). +hr_knob_spec(s) :- router_test_client(s, _). +hr_knob_spec(s) :- router_route_def(s, _). +hr_knob_spec(s) :- router_validator(s, _). +hr_knob_spec(s) :- router_validator_fn(s, _). +hr_knob_spec(s) :- router_mw_wrapper(s, _). +hr_knob_spec(s) :- router_mw_combinator(s, _). +hr_knob_spec(s) :- router_mw_except(s, _). +.decl hr_on() +hr_on() :- hr_import_spec(_, s), hr_knob_spec(s). + +// ── the class an app is built from ────────────────────────────────────────── +.decl hr_class_ref(c0:symbol) +hr_class_ref(f) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, f), + import_binding("client", _, _, orig, _, ih), orig != "", + hr_import_spec(ih, spec), router_app_class(spec, orig). +hr_class_ref(f) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, f), + import_binding("client", _, local, "", _, ih), + hr_import_spec(ih, spec), router_app_class(spec, local). +// `import * as h from '…'; new h.X()` +hr_class_ref(f) :- hr_on(), property_access_name(f, n), + expr_child("client", f, "RECEIVER", _, r), + expr_referenced("client", "IMPORT_BINDING", ih, r), + import_binding("client", "NAMESPACE", _, _, _, ih), + hr_import_spec(ih, spec), router_app_class(spec, n). + +.decl hr_new(c0:symbol) +hr_new(e) :- call_site("client", "CONSTRUCTOR_CALL", _, _, _, e, _), + expr_child("client", e, "METHOD_NAME", _, f), hr_class_ref(f). + +// the const an identifier denotes, here or through an import +.decl hr_denotes_var(c0:symbol, c1:symbol) +hr_denotes_var(e, v) :- hr_on(), expr_referenced("client", "VARIABLE", v, e). +hr_denotes_var(e, v) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, e), + import_binds(ih, "client", "VARIABLE", v). +// `import routes from './routes'; export { routes as apiRoutes }` in a barrel, imported as `apiRoutes`: the +// barrel re-exports its own DEFAULT import under an alias, which the generic export surface reads only for +// named imports +hr_denotes_var(e, v) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, e), import_binding("client", _, _, orig, _, ih), orig != "", + import_target_module(ih, _, m), export_decl(_, orig, ln, ek, m, h), export_kind_is_local_name(ek), export_source(_, "", _, h), + ln != "", import_binding("client", ik, ln, _, m, ih2), import_kind_binds_default(ik), import_binds(ih2, "client", "VARIABLE", v). +// `const { app } = await import('./server')`: the module's export, as a static import gives it +hr_denotes_var(e, v) :- hr_on(), expr_referenced("client", "VARIABLE", d, e), var_dynamic_import_binding(d, "VARIABLE", v). + +// a resolved call of a project function (not a handler handed to a registration) +.decl hr_call_of(c0:symbol, c1:symbol) +hr_call_of(ce, w) :- hr_on(), call_chain_edge(ce, _, "-", w, "client", st, _), st != "callback_registered". +// `const { auth } = middlewares` / `const { auth } = this.middlewares` where `middlewares` is a namespace +// import (`import * as middlewares from './middlewares'`, kept in a field): a call of `auth` calls the +// module's export, a function or a const holding one +.decl hr_ns_val(c0:symbol, c1:symbol) +hr_ns_val(x, m) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, x), import_binds_namespace(ih, "client", m). +hr_ns_val(x, m) :- ts_field_access_target(x, f), field_initializer("client", i, f), hr_ns_val(i, m). +hr_ns_val(x, m) :- expr_kind("client", k, _, x), expr_kind_is_transparent(k), expr_child("client", x, _, _, c), hr_ns_val(c, m). +.decl hr_ns_destr_fn(c0:symbol, c1:symbol) +hr_ns_destr_fn(d, w) :- var_binding("client", _, "PROPERTY", src, i, d), i != "", hr_ns_val(i, m), + module_export_any("client", m, src, "METHOD", w). +hr_ns_destr_fn(d, w) :- var_binding("client", _, "PROPERTY", src, i, d), i != "", hr_ns_val(i, m), + module_export_any("client", m, src, "VARIABLE", v), var_initializer("client", _, fx, v), expr_anon_decl("client", w, fx). +.decl hr_has_chain_call(c0:symbol) +hr_has_chain_call(ce) :- hr_on(), call_chain_edge(ce, _, "-", _, "client", _, _). +hr_call_of(ce, w) :- call_site("client", "FUNCTION_CALL", _, _, _, ce, _), !hr_has_chain_call(ce), + expr_child("client", ce, "METHOD_NAME", _, f), expr_referenced("client", "VARIABLE", d, f), hr_ns_destr_fn(d, w). + +// A MOUNT ARGUMENT whose call the call graph could not resolve (`s.controller()` on an element of +// a loop over objects of several classes, `g.build()` on a loop variable): the project methods of +// that name. Only for the second argument of a mount, where the alternative is worse: the app the +// method builds would otherwise be served at its own paths, as a root (SPEC 2, a mount argument is +// never a root). A call resolved to a declaration with overrides takes the overrides too. +.decl hr_mount_arg(c0:symbol) +hr_mount_arg(x) :- hr_on(), call_site("client", "METHOD_CALL", rn, _, _, ce, _), router_mount_app(rn), + expr_child("client", ce, "ARGUMENT", "1", x). +hr_mount_arg(x) :- hr_mount_arg(e), expr_kind("client", k, _, e), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"), + expr_child("client", e, _, _, x). +.decl hr_has_call(c0:symbol) +hr_has_call(x) :- hr_mount_arg(x), hr_call_of(x, _). +.decl hr_callee(c0:symbol, c1:symbol) +hr_callee(ce, w) :- hr_call_of(ce, w). +hr_callee(x, w) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", cn, _, _, x, _), !hr_has_call(x), + !hr_elem_typed(x), method_decl("client", cn, _, _, w), hr_arity_ok(x, w), hr_name_type_ok(x, cn, w). +// …of those, the ones the call can take: as many parameters as it passes arguments, at least, and visible on the +// receiver's declared class or overriding it there (`this.admin.getController()` on a field declared `AdminController` +// reaches no other controller's method; `strategy.getController(auth, opts)` reaches no zero-parameter one) +.decl hr_nargs(c0:symbol, c1:number) +hr_nargs(x, n) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", _, _, _, x, _), n = count : { expr_child("client", x, "ARGUMENT", _, _) }. +.decl hr_nparams(c0:symbol, c1:number) +hr_nparams(w, n) :- hr_on(), method_decl("client", _, _, _, w), n = count : { param_decl("client", _, _, _, w, _) }. +.decl hr_arity_ok(c0:symbol, c1:symbol) +hr_arity_ok(x, w) :- hr_nargs(x, a), call_site("client", "METHOD_CALL", cn, _, _, x, _), method_decl("client", cn, _, _, w), hr_nparams(w, n), n >= a. +.decl hr_name_type_ok(c0:symbol, c1:symbol, c2:symbol) +hr_name_type_ok(x, cn, w) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", cn, _, _, x, _), !hr_rtyped(x), method_decl("client", cn, _, _, w). +hr_name_type_ok(x, cn, w) :- hr_rtype(x, tt), call_site("client", "METHOD_CALL", cn, _, _, x, _), method_in_scope(tt, cn, _, w). +hr_name_type_ok(x, cn, w) :- hr_rtype(x, tt), call_site("client", "METHOD_CALL", cn, _, _, x, _), method_decl("client", cn, _, _, w), + method_owner("client", s, w), type_ancestor(s, tt). +// …the method of each element's class, when the receiver is a loop variable over a const array whose +// elements have a type (`[new PingRoutes()]`): a name fallback would also take a class the array never holds +.decl hr_elem_type(c0:symbol, c1:symbol) +hr_elem_type(x, tt) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", _, _, r, x, _), expr_referenced("client", "VARIABLE", v, r), + for_binding_iterable(v, it), hr_arr(it, arr), expr_child("client", arr, _, _, el), expr_type(el, _, tt). +.decl hr_elem_typed(c0:symbol) +hr_elem_typed(x) :- hr_elem_type(x, _). +hr_callee(x, w) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", cn, _, _, x, _), !hr_has_call(x), + hr_elem_type(x, tt), method_in_scope(tt, cn, _, w). +hr_callee(x, w) :- hr_mount_arg(x), hr_call_of(x, w0), method_dispatch_candidate(w0, w, _), method_prov(w, "client"), hr_disp_ok(x, w). +// …an override declared in the receiver's own static type or below it: `this.admin.getController()` on a field +// typed AdminController, which inherits the base method, reaches no other controller's override +.decl hr_rtype(c0:symbol, c1:symbol) +hr_rtype(x, tt) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", _, _, r, x, _), expr_type(r, _, tt). +// …or the class a field read is declared with (`adminController?: AdminController`) +hr_rtype(x, tt) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", _, _, r, x, _), ts_field_access_target(r, f), + field_type_ref("client", tr, f), type_ref_resolves("client", tr, tt), method_owner("client", tt, _). +// …or the class of what is written into the field (`this.adminController = new AdminController(..)`) +hr_rtype(x, tt) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", _, _, r, x, _), ts_field_access_target(r, f), + hr_field_write(f, v), call_site("client", "CONSTRUCTOR_CALL", _, _, _, v, _), expr_type(v, _, tt), method_owner("client", tt, _). +hr_rtype(x, tt) :- hr_mount_arg(x), call_site("client", "METHOD_CALL", _, _, r, x, _), ts_field_access_target(r, f), + hr_field_write(f, v), call_site("client", "CONSTRUCTOR_CALL", cn, _, _, v, _), type_decl("client", cn, _, _, _, _, tt), method_owner("client", tt, _). +.decl hr_rtyped(c0:symbol) +hr_rtyped(x) :- hr_rtype(x, _). +.decl hr_disp_ok(c0:symbol, c1:symbol) +hr_disp_ok(x, w) :- hr_rtype(x, tt), hr_call_of(x, w0), method_dispatch_candidate(w0, w, _), method_owner("client", s, w), + (s = tt ; type_ancestor(s, tt)). +hr_disp_ok(x, w) :- hr_mount_arg(x), !hr_rtyped(x), hr_call_of(x, w0), method_dispatch_candidate(w0, w, _). +// A mount argument whose call reaches SEVERAL methods that each build the app they return (`c.getController()` over +// a loop of controllers of several classes): each candidate's app is its own list (SPEC ruling R6), mounted on its +// own; merging them into the one list of the call would put one class's middleware before another class's routes +.decl hr_fresh_cand(c0:symbol, c1:symbol, c2:symbol) +hr_fresh_cand(x, w, t) :- hr_mount_arg(x), hr_callee(x, w), hr_ret_cand(w, t), expr_enclosing_method(t, w). +.decl hr_multi(c0:symbol) +hr_multi(x) :- hr_fresh_cand(x, w1, _), hr_fresh_cand(x, w2, _), w1 < w2. +// the element of the iterated array each candidate is the method of (`[new Reports(), new Exports()]`): the loop mounts +// them in the array's order, and a candidate no element holds is not mounted +.decl hr_cand_elem(c0:symbol, c1:symbol, c2:symbol) +hr_cand_elem(x, w, i) :- hr_fresh_cand(x, w, _), call_site("client", "METHOD_CALL", cn, _, r, x, _), expr_referenced("client", "VARIABLE", v, r), + for_binding_iterable(v, it), hr_arr(it, arr), expr_child("client", arr, _, i, el), expr_type(el, _, tt), method_in_scope(tt, cn, _, w), + strlen(i) <= 4. +.decl hr_x_has_elem(c0:symbol) +hr_x_has_elem(x) :- hr_cand_elem(x, _, _). +// (call, candidate's list, order among the candidates) +.decl hr_each_cand(c0:symbol, c1:symbol, c2:symbol) +hr_each_cand(x, t, o) :- hr_multi(x), hr_fresh_cand(x, w, t), hr_cand_elem(x, w, i), o = cat(substr("0000", 0, 4 - strlen(i)), i). +hr_each_cand(x, t, "9999") :- hr_multi(x), hr_fresh_cand(x, _, t), !hr_x_has_elem(x). + +// A returned list whose creating expression is evaluated inside the function itself +// (expr_enclosing_method) is fresh per call; anything else (a module-level app, a +// parameter) is the same list every time. +// what a function returns: its returned expression, never a part of it. method_returns_expr +// also lists the call sites INSIDE a returned expression (`return new X().basePath('/v1')` +// lists the `new` too), and reading those made the base-less inner value a second return. +.decl hr_ret_nested(c0:symbol) +hr_ret_nested(e) :- hr_on(), method_returns_expr(w, e), expr_child("client", p, _, _, e), method_returns_expr(w, p). +.decl hr_ret_expr(c0:symbol, c1:symbol) +hr_ret_expr(w, e) :- hr_on(), method_returns_expr(w, e), !hr_ret_nested(e). +.decl hr_ret_cand(c0:symbol, c1:symbol) +hr_ret_cand(w, t) :- hr_ret_expr(w, e), hr_app(e, t). + +// a parameter typed with the app class itself (`(app: X) => …`, `app: X`) +.decl hr_typed_slot(c0:symbol) +hr_typed_slot(p) :- hr_on(), param_type_ref("client", r, p), + type_ref("client", _, _, tn, _, _, _, r), type_ref_module("client", m, r), + import_binding("client", _, tn, orig, m, ih), orig != "", + hr_import_spec(ih, spec), router_app_class(spec, orig). +// …or one at the same position of a function that implements a signature declaring it so +// (`definePlugin({ register(app) { app.route(..) } })` where the input type says `register(app: Hono)`) +hr_typed_slot(p) :- hr_on(), param_decl("client", _, pos, _, m, p), method_dispatch_candidate(sig, m, _), + param_decl("client", _, pos, _, sig, ps), ps != p, param_type_ref("client", r, ps), + type_ref("client", _, _, tn, _, _, _, r), type_ref_module("client", mm, r), + import_binding("client", _, tn, orig, mm, ih), orig != "", + hr_import_spec(ih, spec), router_app_class(spec, orig). + +// ── a factory and the apps it makes ───────────────────────────────────────── +// (factory call): `createFactory(...)` imported from its module +.decl hr_factory_call(c0:symbol) +hr_factory_call(f) :- hr_on(), call_site("client", "FUNCTION_CALL", _, _, _, f, _), + expr_child("client", f, "METHOD_NAME", _, n), expr_referenced("client", "IMPORT_BINDING", ih, n), + import_binding("client", _, _, orig, _, ih), hr_import_spec(ih, spec), router_factory(spec, orig). +// an expression holding that factory: the call, or a const it initialises +.decl hr_factory_val(c0:symbol, c1:symbol) +hr_factory_val(f, f) :- hr_factory_call(f). +hr_factory_val(r, f) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), hr_factory_val(i, f). +// …returned by a project function (`function createTierFactory() { return createFactory() }`) +hr_factory_val(ce, f) :- hr_call_of(ce, w), hr_ret_expr(w, e), hr_factory_val(e, f). +// a factory METHOD read off into a const and called later (`const mk = factory.createMiddleware; mk(fn)`): +// (call, method name, factory) +.decl hr_detached(c0:symbol, c1:symbol, c2:symbol) +hr_detached(ce, n, f) :- call_site("client", "FUNCTION_CALL", _, _, _, ce, _), expr_child("client", ce, "METHOD_NAME", _, x), + hr_denotes_var(x, v), var_initializer("client", _, i, v), i != "", property_access_name(i, n), + expr_child("client", i, "RECEIVER", _, q), hr_factory_val(q, f). +// `.createApp()`: a new list per call +.decl hr_factory_app(c0:symbol, c1:symbol) +hr_factory_app(ce, f) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_factory_app(cn), hr_factory_val(r, f). +hr_factory_app(ce, f) :- hr_detached(ce, n, f), router_factory_app(n). +// the parameter of `initApp: (app) => {…}`: registered on every app the factory makes +.decl hr_factory_init_param(c0:symbol, c1:symbol) +hr_factory_init_param(f, p) :- hr_factory_call(f), expr_child("client", f, "ARGUMENT", "0", o), + rd_obj_prop(o, key, fn), router_factory_init(key), expr_anon_decl("client", m, fn), + param_decl("client", _, "0", _, m, p). + +// a property or field declared with the app class (`interface Ctx { server: X }`, +// `class C { app: X }`): reading it gives an app nothing here constructs, a list of its own +// whose paths cannot be completed (SPEC ruling R2) +.decl hr_typed_field(c0:symbol) +hr_typed_field(f) :- hr_on(), field_type_ref("client", r, f), + type_ref("client", _, _, tn, _, _, _, r), type_ref_module("client", m, r), + import_binding("client", _, tn, orig, m, ih), orig != "", + rd_import_path(ih, w), hr_spec(w, spec), router_app_class(spec, orig). +.decl hr_field_read(c0:symbol, c1:symbol) +hr_field_read(e, f) :- property_access_name(e, n), expr_child("client", e, "RECEIVER", _, q), + expr_type(q, _, tt), field_in_scope(tt, n, _, f), hr_typed_field(f). + +// ── STRATUM 1: hr_app(Expr, List) ─────────────────────────────────────────── +.decl hr_app(c0:symbol, c1:symbol) +hr_app(e, e) :- hr_new(e). +hr_app(ce, ce) :- hr_factory_app(ce, _). +hr_app(e, a) :- hr_app(c, a), expr_child("client", e, _, _, c), + expr_kind("client", k, _, e), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +hr_app(r, a) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_app(i, a). +hr_app(ce, a) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_returns_app(cn), hr_app(r, a). +hr_app(ce, a) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_base_path(cn), hr_app(r, a). +// a function returning a list it created: each call is a new list +hr_app(ce, ce) :- hr_callee(ce, w), hr_ret_cand(w, t), expr_enclosing_method(t, w). +// …returning one it did not create: the same list +hr_app(ce, t) :- hr_callee(ce, w), hr_ret_cand(w, t), !expr_enclosing_method(t, w), !hv_isparam(t, w). +// …returning its own PARAMETER (`function withConfig(app) { app.use(mw); return app }`): the app this call passed, +// never one list shared by every caller (SPEC ruling R16: each test's app serves only its own routes) +hr_app(ce, a) :- hr_callee(ce, w), hr_ret_cand(w, t), hv_isparam(t, w), param_decl("client", _, pos, _, w, t), + expr_child("client", ce, "ARGUMENT", pos, x), hr_app(x, a). +// a parameter an app is passed into, or one declared with the app class +hr_app(e, p) :- expr_referenced("client", "PARAMETER", p, e), hr_slot(p). +hr_app(e, f) :- hr_field_read(e, f). +// a field an app is written into (`this.app = createApp()`, `private app = new X()`): every read of +// the field is that app (SPEC [iter2] flow through fields) +.decl hr_field_write(c0:symbol, c1:symbol) +hr_field_write(f, v) :- hr_on(), (expr_kind("client", "ASSIGNMENT_EXPRESSION", _, x) ; expr_kind("client", "BINARY_EXPRESSION", _, x)), + expr_operator("client", "=", x), + expr_child("client", x, "LEFT_OPERAND", _, l), ts_field_access_target(l, f), + expr_child("client", x, "RIGHT_OPERAND", _, v). +hr_field_write(f, i) :- hr_on(), field_initializer("client", i, f). +hr_app(e, a) :- ts_field_access_target(e, f), hr_field_write(f, v), hr_app(v, a), e != v. +// a property of an object literal holding an app (`return { dir, app: createApp(dir) }`), read +// back through a const, an await or a function's return (`(await setup()).app`, `fixture.app`) +.decl hr_app_obj(c0:symbol) +hr_app_obj(o) :- rd_obj_prop(o, _, v), hr_app(v, _). +.decl hr_objlit(c0:symbol, c1:symbol) +hr_objlit(o, o) :- hr_app_obj(o). +hr_objlit(r, o) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_objlit(i, o). +// …and the result of a call of a function returning one: (expression, call, function, object). The call is +// kept, because an app the function creates is a new one per call (SPEC ruling R6) +.decl hr_objcall(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_objcall(ce, ce, w, o) :- hr_call_of(ce, w), hr_ret_expr(w, e), hr_objlit(e, o). +hr_objcall(r, ce, w, o) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_objcall(i, ce, w, o). +// …or a PARAMETER such a result is passed into (`mountHttp(runtime)` where `runtime = await createRuntime()`, then +// `const { usersRoutes } = runtime` inside): what each call passes there +// One source only: when the results of two DIFFERENT functions reach the parameter (`attach(host, ordersModule())`, +// `attach(host, invoicesModule())`), a read of it has no call context to tell which call's object it is, and every +// mount the function makes would take both objects' sub-apps (hono-8-01); those sub-apps are declared instead +// (hr_unknown_mount, unresolved_mount) +hr_objcall(r, ce, w, o) :- hr_objcall(a, ce, w, o), expr_child("client", oc, "ARGUMENT", pos, a), hr_call_of(oc, f), + param_decl("client", _, pos, _, f, p), !hr_objpar_amb(p), expr_referenced("client", "PARAMETER", p, r). +hr_objcall(e, ce, w, o) :- hr_objcall(c, ce, w, o), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +// ── a returned object handed to a PARAMETER: one source or several ───────────── +// hr_objcall follows an object a function returns into a parameter it is passed to (`mountHttp(runtime)`), with no +// call context: every call's object reaches every read of the parameter. That is right while every call passes the +// result of the SAME function (each call's apps are copies of one template), and wrong when two calls pass objects of +// two different functions: each mount the function makes would take both objects' sub-apps (hono-8-01). Which +// functions' results reach a parameter is decided here from calls and bindings only, before any app is known, so the +// app flow can test it. +// a function that returns an object literal (written in place, or a const holding one) +.decl hr_objfn(c0:symbol) +hr_objfn(w) :- hr_on(), hr_ret_expr(w, e), expr_kind("client", "OBJECT_LITERAL", _, e). +hr_objfn(w) :- hr_on(), hr_ret_expr(w, e), hr_denotes_var(e, v), var_initializer("client", _, i, v), i != "", + expr_kind("client", "OBJECT_LITERAL", _, i). +// (expression, function whose returned object it holds) +.decl hr_psrc(c0:symbol, c1:symbol) +hr_psrc(x, w) :- hr_objfn(w), hr_call_of(x, w). +hr_psrc(e, w) :- hr_psrc(c, w), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +hr_psrc(r, w) :- hr_psrc(i, w), var_initializer("client", _, i, v), hr_denotes_var(r, v). +hr_psrc(r, w) :- hr_psrc_p(p, w), expr_referenced("client", "PARAMETER", p, r). +// (parameter, function whose returned object a call passes there) +.decl hr_psrc_p(c0:symbol, c1:symbol) +hr_psrc_p(p, w) :- hr_psrc(a, w), expr_child("client", oc, "ARGUMENT", pos, a), hr_call_of(oc, f), + param_decl("client", _, pos, _, f, p). +// a parameter a mount in its function reads its sub-app from (`const { http } = mod; host.route('/', http)`, +// `host.route('/', mod.http)`): the only place where taking every call's object at once makes a route false +.decl hr_marg_need(c0:symbol) +hr_marg_need(sx) :- hr_on(), call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx). +hr_marg_need(c) :- hr_marg_need(x), expr_kind("client", k, _, x), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"), + expr_child("client", x, _, _, c). +hr_marg_need(q) :- hr_marg_need(x), property_access_name(x, _), expr_child("client", x, "RECEIVER", _, q). +hr_marg_need(i) :- hr_marg_need(x), expr_referenced("client", "VARIABLE", d, x), var_binding("client", _, "PROPERTY", _, i, d), i != "". +.decl hr_pmount(c0:symbol) +hr_pmount(p) :- hr_marg_need(x), expr_referenced("client", "PARAMETER", p, x). +// such a parameter two different functions' objects reach +.decl hr_objpar_amb(c0:symbol) +hr_objpar_amb(p) :- hr_pmount(p), hr_psrc_p(p, w1), hr_psrc_p(p, w2), w1 < w2. +// an element of a const array literal, read through a for..of binding over it +// (`for (const p of plugins) app.route(p.prefix, p.app)`) +.decl hr_arr(c0:symbol, c1:symbol) +hr_arr(x, x) :- hr_on(), expr_kind("client", "ARRAY_LITERAL", _, x). +hr_arr(r, a) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_arr(i, a). +hr_arr(e, a) :- hr_arr(c, a), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), expr_kind_is_transparent(k). +// an array method that returns some of the receiver's own elements (`[...].filter(f)`, `.sort(f)`, `.slice(1)`): a loop +// over the result iterates elements of that array literal, each still the value written there +.decl hr_arr_subset(c0:symbol) +hr_arr_subset("filter"). hr_arr_subset("sort"). hr_arr_subset("slice"). hr_arr_subset("reverse"). +hr_arr_subset("toSorted"). hr_arr_subset("toReversed"). +hr_arr(e, a) :- call_site("client", "METHOD_CALL", n, _, r, e, _), hr_arr_subset(n), r != "", hr_arr(r, a). +// …FILTERED: which elements survive is decided at run time, so what the loop registers for one is conditional (SPEC +// ruling R13b); sorting or slicing keeps every element's routes +.decl hr_arr_filtered(c0:symbol) +hr_arr_filtered(e) :- call_site("client", "METHOD_CALL", "filter", _, r, e, _), r != "", hr_arr(r, _). +hr_arr_filtered(e) :- call_site("client", "METHOD_CALL", n, _, r, e, _), hr_arr_subset(n), r != "", hr_arr_filtered(r). +hr_arr_filtered(r) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_arr_filtered(i). +hr_arr_filtered(e) :- hr_arr_filtered(c), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), expr_kind_is_transparent(k). +// a mount whose arguments read the variable of a loop over a filtered list: everything it mounts is registered when +// the element survives, exactly as a registration inside `if (...)` (SPEC ruling R13b) +.decl hr_marg_sub(c0:symbol, c1:symbol) +hr_marg_sub(ce, x) :- hr_on(), call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), expr_child("client", ce, "ARGUMENT", _, x). +hr_marg_sub(ce, c) :- hr_marg_sub(ce, x), expr_child("client", x, _, _, c). +.decl hr_cond_mount(c0:symbol) +hr_cond_mount(ce) :- hr_marg_sub(ce, x), expr_referenced("client", "VARIABLE", v, x), for_binding_iterable(v, it), hr_arr_filtered(it). +hr_objlit(r, o) :- hr_denotes_var(r, v), for_binding_iterable(v, it), hr_arr(it, arr), expr_child("client", arr, _, _, el), + hr_objlit(el, o). +hr_objlit(e, o) :- hr_objlit(c, o), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +.decl hr_prop_of(c0:symbol, c1:symbol) +hr_prop_of(e, v) :- property_access_name(e, n), expr_child("client", e, "RECEIVER", _, q), hr_objlit(q, o), + rd_obj_prop(o, n, v). +hr_app(e, a) :- hr_prop_of(e, v), hr_app(v, a). +// a name destructured from such an object (`const { app } = createTestApp()`) +.decl hr_destr_of(c0:symbol, c1:symbol) +hr_destr_of(e, v) :- expr_referenced("client", "VARIABLE", d, e), var_binding("client", _, "PROPERTY", src, i, d), i != "", + hr_objlit(i, o), rd_obj_prop(o, src, v). +hr_app(e, a) :- hr_destr_of(e, v), hr_app(v, a). +// a property of an object a call returned (`const { app } = createTestApp()`, `(await setup()).app`): an app +// the function created is this call's own list, any other is the same list every time. The call's own list is +// one per (call, created app), never the call alone: `return { envRoutes, fileRoutes }` holds two apps, and a read +// of `envRoutes` is the first only (one list for the call made every property read every app). Its id is the call +// and the created app joined by `#`; it is reported under the created app (hr_app_id) +.decl hr_viacall(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_viacall(e, ce, w, v) :- property_access_name(e, n), expr_child("client", e, "RECEIVER", _, q), hr_objcall(q, ce, w, o), + rd_obj_prop(o, n, v). +// (from the call's object outward: this is recursive, and starting at every variable read rescanned them all each round) +hr_viacall(e, ce, w, v) :- hr_objcall(i, ce, w, o), var_binding("client", _, "PROPERTY", src, i, d), i != "", + rd_obj_prop(o, src, v), expr_referenced("client", "VARIABLE", d, e). +// (list, call, created app) +.decl hr_objret_inst(c0:symbol, c1:symbol, c2:symbol) +hr_objret_inst(l, ce, t) :- hr_viacall(_, ce, w, v), hr_app(v, t), expr_enclosing_method(t, w), l = cat(ce, cat("#", t)). +hr_app(e, l) :- hr_viacall(e, ce, w, v), hr_app(v, t), expr_enclosing_method(t, w), l = cat(ce, cat("#", t)). +hr_app(e, t) :- hr_viacall(e, _, w, v), hr_app(v, t), !expr_enclosing_method(t, w). + +.decl hr_slot_arg(c0:symbol, c1:symbol, c2:symbol) +hr_slot_arg(oc, p, a) :- hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a), + param_decl("client", _, pos, _, w, p). +.decl hr_slot(c0:symbol) +.decl hr_param_mounted(c0:symbol) +hr_param_mounted(p) :- hr_reg(ce, _, cn), router_mount_app(cn), expr_child("client", ce, "ARGUMENT", "1", sx), hr_app(sx, p), + hr_slot_arg(_, p, _). +hr_slot(p) :- hr_slot_arg(_, p, a), hr_app(a, _). +hr_slot(p) :- hr_typed_slot(p). +hr_slot(f) :- hr_typed_field(f). +hr_slot(p) :- hr_factory_init_param(_, p). + +// ── a registration: a call on an app value ────────────────────────────────── +.decl hr_registrar(c0:symbol) +hr_registrar(n) :- hr_on(), router_verb(n, _). +hr_registrar(n) :- hr_on(), router_use(n). +hr_registrar(n) :- hr_on(), router_on(n). +hr_registrar(n) :- hr_on(), router_mount_app(n). +hr_registrar(n) :- hr_on(), router_mount_foreign(n). +hr_registrar(n) :- hr_on(), router_fallback(n). +hr_registrar(n) :- hr_on(), router_openapi(n). +.decl hr_reg(c0:symbol, c1:symbol, c2:symbol) +hr_reg(ce, a, cn) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), hr_registrar(cn), hr_app(r, a). + +// ── an OpenAPI route definition: the object `createRoute({...})` is called with ── +.decl hr_def_val(c0:symbol, c1:symbol) +hr_def_val(x, o) :- hr_on(), call_site("client", "FUNCTION_CALL", _, _, _, x, _), + expr_child("client", x, "METHOD_NAME", _, f), expr_referenced("client", "IMPORT_BINDING", ih, f), + import_binding("client", _, _, orig, _, ih), hr_import_spec(ih, spec), router_route_def(spec, orig), + expr_child("client", x, "ARGUMENT", "0", a), hr_def_obj(a, o). +hr_def_val(r, o) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_def_val(i, o). +hr_def_val(e, o) :- hr_def_val(c, o), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), expr_kind_is_transparent(k). +// an object literal written in place or held by a const, through `as T` / `satisfies T` / parentheses: read only for +// the expressions a definition is taken from (createRoute's argument, a wrapper call's arguments), never for every +// object literal and every read of one in the program +.decl hr_def_obj_need(c0:symbol) +hr_def_obj_need(a) :- hr_on(), call_site("client", "FUNCTION_CALL", _, _, _, x, _), + expr_child("client", x, "METHOD_NAME", _, f), expr_referenced("client", "IMPORT_BINDING", ih, f), + import_binding("client", _, _, orig, _, ih), hr_import_spec(ih, spec), router_route_def(spec, orig), + expr_child("client", x, "ARGUMENT", "0", a). +hr_def_obj_need(a) :- hr_def_call(x, _), expr_child("client", x, "ARGUMENT", _, a). +hr_def_obj_need(c) :- hr_def_obj_need(e), expr_kind("client", k, _, e), expr_kind_is_transparent(k), expr_child("client", e, _, _, c). +hr_def_obj_need(i) :- hr_def_obj_need(r), hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "". +.decl hr_def_obj(c0:symbol, c1:symbol) +hr_def_obj(o, o) :- hr_def_obj_need(o), expr_kind("client", "OBJECT_LITERAL", _, o). +hr_def_obj(e, o) :- hr_def_obj_need(e), expr_kind("client", k, _, e), expr_kind_is_transparent(k), expr_child("client", e, _, _, c), hr_def_obj(c, o). +hr_def_obj(r, o) :- hr_def_obj_need(r), hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_def_obj(i, o). +// …a project function that RETURNS a definition (`authRoute(scope, { method, path, .. })` returning +// `createRoute({ ...config, middleware })`): the call is a definition, the object the function builds. Its keys spread +// from a parameter (`...config`) are that call's argument's own (hr_def_spread), so each call is its own route +.decl hr_def_call(c0:symbol, c1:symbol) +hr_def_call(x, w) :- hr_call_of(x, w), hr_ret_expr(w, e), hr_def_val(e, _). +hr_def_val(x, o) :- hr_def_call(x, w), hr_ret_expr(w, e), hr_def_val(e, o). +// (call, the object the function builds, the call's argument object spread into it) +.decl hr_def_spread(c0:symbol, c1:symbol, c2:symbol) +hr_def_spread(x, o, o2) :- hr_def_call(x, w), hr_ret_expr(w, e), hr_def_val(e, o), expr_child("client", o, "SPREAD_OPERAND", _, sx), + hv_spread_src(sx, y), hr_def_param(y, p), param_decl("client", _, pos, _, w, p), expr_child("client", x, "ARGUMENT", pos, a), hr_def_obj(a, o2). +hr_def_val(x, o2) :- hr_def_spread(x, _, o2). +// a reference to a parameter, through `as T` and parentheses; read only where a definition can name one: a spread +// into an object, a definition's method or path value, the receiver of a property read inside an array spread +.decl hr_def_param_need(c0:symbol) +hr_def_param_need(y) :- hv_spread_src(_, y). +hr_def_param_need(pv) :- rd_obj_prop(_, k, pv), (router_def_key(k, "method") ; router_def_key(k, "path")). +hr_def_param_need(q) :- hr_sp_el(z), property_access_name(z, _), expr_child("client", z, "RECEIVER", _, q). +hr_def_param_need(c) :- hr_def_param_need(y), expr_kind("client", k, _, y), expr_kind_is_transparent(k), expr_child("client", y, _, _, c). +.decl hr_sp_el(c0:symbol) +hr_sp_el(y) :- hr_on(), expr_kind("client", "SPREAD_ELEMENT", _, el), expr_child("client", el, _, _, y). +hr_sp_el(c) :- hr_sp_el(y), expr_kind("client", k, _, y), expr_kind_is_transparent(k), expr_child("client", y, _, _, c). +hr_sp_el(c) :- hr_sp_el(y), expr_kind("client", "BINARY_EXPRESSION", _, y), (expr_operator("client", "??", y) ; expr_operator("client", "||", y)), + expr_child("client", y, "LEFT_OPERAND", _, c). +.decl hr_def_param(c0:symbol, c1:symbol) +hr_def_param(y, p) :- hr_def_param_need(y), expr_referenced("client", "PARAMETER", p, y). +hr_def_param(y, p) :- hr_def_param_need(y), expr_kind("client", k, _, y), expr_kind_is_transparent(k), expr_child("client", y, _, _, c), hr_def_param(c, p). +// `import * as routes from './routes'; app.openapi(routes.get, h)` +// (from the definition outward: it is recursive, and starting at every property read rescanned them all each round) +hr_def_val(e, o) :- hr_def_val(i, o), var_initializer("client", _, i, v), module_export_any("client", m, n, "VARIABLE", v), + import_binds_namespace(ih, "client", m), expr_referenced("client", "IMPORT_BINDING", ih, r), + expr_child("client", e, "RECEIVER", _, r), property_access_name(e, n). +.decl hr_openapi_def(c0:symbol, c1:symbol) +hr_openapi_def(ce, o) :- hr_reg(ce, _, cn), router_openapi(cn), expr_child("client", ce, "ARGUMENT", "0", x), hr_def_val(x, o). +rd_demand(v) :- hr_openapi_def(_, o), rd_obj_prop(o, k, v), (router_def_key(k, "method") ; router_def_key(k, "path")). + +// the strings a registration may need +rd_demand(p) :- hr_reg(ce, _, _), expr_child("client", ce, "ARGUMENT", "0", p). +rd_demand(p) :- hr_reg(ce, _, cn), router_on(cn), expr_child("client", ce, "ARGUMENT", "1", p). +rd_demand(p) :- hr_reg(ce, _, cn), router_on(cn), expr_child("client", ce, "ARGUMENT", pos, arr), + (pos = "0" ; pos = "1"), expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, _, p). +rd_demand(p) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_base_path(cn), hr_app(r, _), + expr_child("client", ce, "ARGUMENT", "0", p). + +// ── an app VARIABLE re-pointed at a basePath result (SPEC rulings R8a, R8b) ── +// `let app = new X(); app.get(..); app = app.basePath('/api'); app.get(..)`: a read in the same function after the +// assignment (and not inside it) sees the assignment's value, a read before it the initializer's. Syntactic only, so +// the value rules may negate it. (assignment, variable, value) +.decl hr_rb_asg(c0:symbol, c1:symbol, c2:symbol) +hr_rb_asg(asg, v, val) :- hr_on(), expr_kind("client", "ASSIGNMENT_EXPRESSION", _, asg), expr_child("client", asg, "LEFT_OPERAND", _, tgt), + expr_referenced("client", "VARIABLE", v, tgt), expr_child("client", asg, "RIGHT_OPERAND", _, val), + call_site("client", "METHOD_CALL", cn, _, _, val, _), router_base_path(cn). +.decl hr_rb_read(c0:symbol, c1:symbol) +hr_rb_read(r, v) :- hr_rb_asg(_, v, _), expr_referenced("client", "VARIABLE", v, r). +.decl hr_rb_pos(c0:symbol, c1:symbol) +hr_rb_pos(x, k) :- (hr_rb_asg(x, _, _) ; hr_rb_read(x, _)), + ts_expression(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, l, c, _, _, _, _, _, _, _, _, _, _, _, x), + strlen(l) <= 7, strlen(c) <= 5, + k = cat(cat(substr("0000000", 0, 7 - strlen(l)), l), cat(":", cat(substr("00000", 0, 5 - strlen(c)), c))). +.decl hr_rb_sub(c0:symbol, c1:symbol) +hr_rb_sub(asg, asg) :- hr_rb_asg(asg, _, _). +hr_rb_sub(asg, c) :- hr_rb_sub(asg, x), expr_child("client", x, _, _, c). +.decl hr_rb_before(c0:symbol, c1:symbol, c2:symbol) +hr_rb_before(r, asg, ka) :- hr_rb_read(r, v), hr_rb_asg(asg, v, _), expr_enclosing_method(r, w), expr_enclosing_method(asg, w), + hr_rb_pos(asg, ka), hr_rb_pos(r, kr), ka < kr, !hr_rb_sub(asg, r). +.decl hr_rb_after(c0:symbol) +hr_rb_after(r) :- hr_rb_before(r, _, _). +.decl hr_rb_shadowed(c0:symbol, c1:symbol) +hr_rb_shadowed(r, asg) :- hr_rb_before(r, asg, k1), hr_rb_before(r, _, k2), k2 > k1. +.decl hr_rb_last(c0:symbol, c1:symbol) +hr_rb_last(r, asg) :- hr_rb_before(r, asg, _), !hr_rb_shadowed(r, asg). +// the blocks an assignment or a read sits in, and a conditional block holding the assignment but not the read +.decl hr_rb_up(c0:symbol, c1:symbol) +hr_rb_up(x, b) :- (hr_rb_asg(x, _, _) ; hr_rb_read(x, _)), expr_owner("client", "BLOCK", b, _, x). +hr_rb_up(x, p) :- hr_rb_up(x, b), block_parent("client", p, b). +.decl hr_rb_cond(c0:symbol, c1:symbol) +hr_rb_cond(r, asg) :- hr_rb_last(r, asg), hr_rb_up(asg, b), block_kind("client", k, b), hr_cond_kind(k), !hr_rb_up(r, b). + +// ── STRATUM 2: hr_val(Expr, List, Base) ───────────────────────────────────── +.decl hr_val(c0:symbol, c1:symbol, c2:symbol) +hr_val(e, e, "/") :- hr_new(e). +hr_val(ce, ce, "/") :- hr_factory_app(ce, _). +hr_val(e, a, b) :- hr_val(c, a, b), expr_child("client", e, _, _, c), + expr_kind("client", k, _, e), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +hr_val(r, a, b) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_val(i, a, b), !hr_rb_after(r). +// a read AFTER the variable was re-pointed at a basePath result takes that result (SPEC rulings R8a, R8b); when the +// re-pointing ran only under a condition the read does not enclose, the base is the run-time one (partial, never exact) +hr_val(r, a, b) :- hr_rb_last(r, asg), !hr_rb_cond(r, asg), hr_rb_asg(asg, _, val), hr_val(val, a, b). +hr_val(r, a, b) :- hr_rb_last(r, asg), hr_rb_cond(r, asg), hr_rb_asg(asg, _, val), hr_val(val, a, b), contains("{}", b). +hr_val(r, a, "/{}") :- hr_rb_last(r, asg), hr_rb_cond(r, asg), hr_rb_asg(asg, _, val), hr_val(val, a, b), !contains("{}", b). +hr_val(ce, a, b) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_returns_app(cn), hr_val(r, a, b). +hr_val(ce, a, nb) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_base_path(cn), hr_val(r, a, b), + expr_child("client", ce, "ARGUMENT", "0", p), rd_val(p, pv), hr_bmerge(b, pv, nb), strlen(nb) < 300. +hr_bmreq(b, pv) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_base_path(cn), hr_val(r, _, b), + expr_child("client", ce, "ARGUMENT", "0", p), rd_val(p, pv). +// basePath's own copy of mergePath (below): a base is decided before any mount is flattened, and a mount reads +// whether its receiver's base can be run-time (hr_dyn_base_call), so the two may not share one demand relation +.decl hr_bmreq(c0:symbol, c1:symbol) +.decl hr_bmerge(c0:symbol, c1:symbol, c2:symbol) +.decl hr_blead(c0:symbol, c1:symbol) +hr_blead(x, x) :- (hr_bmreq(x, _) ; hr_bmreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) = "/". +hr_blead(x, y) :- (hr_bmreq(x, _) ; hr_bmreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) != "/", y = cat("/", x). +hr_blead("", "/") :- (hr_bmreq("", _) ; hr_bmreq(_, "")). +hr_bmerge(a, b, a1) :- hr_bmreq(a, b), hr_blead(a, a1), hr_blead(b, "/"). +hr_bmerge(a, b, r) :- hr_bmreq(a, b), hr_blead(a, a1), hr_blead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) = "/", r = cat(substr(a1, 0, strlen(a1) - 1), b1). +hr_bmerge(a, b, r) :- hr_bmreq(a, b), hr_blead(a, a1), hr_blead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) != "/", r = cat(a1, b1). +hr_val(ce, ce, b) :- hr_callee(ce, w), hr_ret_expr(w, e), hr_val(e, t, b), expr_enclosing_method(t, w). +hr_val(ce, t, b) :- hr_callee(ce, w), hr_ret_expr(w, e), hr_val(e, t, b), hr_ret_cand(w, t), !expr_enclosing_method(t, w), !hv_isparam(t, w). +hr_val(ce, a, b) :- hr_callee(ce, w), hr_ret_expr(w, e), hr_val(e, t, "/"), hv_isparam(t, w), param_decl("client", _, pos, _, w, t), + expr_child("client", ce, "ARGUMENT", pos, x), hr_val(x, a, b). +hr_val(ce, a, nb) :- hr_callee(ce, w), hr_ret_expr(w, e), hr_val(e, t, rb), rb != "/", hv_isparam(t, w), param_decl("client", _, pos, _, w, t), + expr_child("client", ce, "ARGUMENT", pos, x), hr_val(x, a, b), hr_bmerge(b, rb, nb), strlen(nb) < 300. +hr_bmreq(b, rb) :- hr_callee(ce, w), hr_ret_expr(w, e), hr_val(e, t, rb), rb != "/", hv_isparam(t, w), param_decl("client", _, pos, _, w, t), + expr_child("client", ce, "ARGUMENT", pos, x), hr_val(x, _, b). +hr_val(e, p, "/") :- expr_referenced("client", "PARAMETER", p, e), hr_slot(p). +hr_val(e, f, "/") :- hr_field_read(e, f). +// A write that reads the field it writes (`this.server = this.server.basePath(b)`) is evaluated +// once: the reads inside it see the field's OTHER writes, never the write itself, so the update is +// not followed round as a cycle (SPEC ruling R8) +.decl hr_fw_sub(c0:symbol, c1:symbol) +hr_fw_sub(v, v) :- hr_field_write(_, v). +hr_fw_sub(v, c) :- hr_fw_sub(v, x), expr_child("client", x, _, _, c). +.decl hr_fw_self(c0:symbol, c1:symbol) +hr_fw_self(e, v) :- hr_field_write(f, v), hr_fw_sub(v, e), ts_field_access_target(e, f). +hr_val(e, a, b) :- ts_field_access_target(e, f), hr_field_write(f, v), hr_val(v, a, b), e != v, !hr_fw_self(e, v). +hr_val(e, a, b) :- hr_prop_of(e, v), hr_val(v, a, b). +hr_val(e, a, b) :- hr_destr_of(e, v), hr_val(v, a, b). +hr_val(e, l, b) :- hr_viacall(e, ce, w, v), hr_val(v, t, b), expr_enclosing_method(t, w), l = cat(ce, cat("#", t)). +hr_val(e, t, b) :- hr_viacall(e, _, w, v), hr_val(v, t, b), !expr_enclosing_method(t, w). + +// ── INCLUSION: a list whose registrations are spliced into another ───────── +// hr_inc(Into, From, Site, Prefix, Kind). Kind: `mount` (route(prefix, sub)), +// `instance` (a call of a function that built the list), `param` (a function the app +// was passed into). +.decl hr_inc(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_inc(a, s, ce, pre, "mount") :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_app(sx, s), s != a, !hr_loop_paired(ce), !hr_multi(s), + !hr_elem_has_pre(ce, s), expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv), hr_merge(b, pv, pre), + (contains("{}", pre) ; !hr_dyn_base_call(ce)). +// …each candidate's own app, when the call reaches several (hr_multi) +hr_inc(a, t, ce, pre, "mount_each") :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_app(sx, s), s != a, !hr_loop_paired(ce), hr_multi(s), hr_each_cand(s, t, _), + !hr_elem_has_pre(ce, t), expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv), hr_merge(b, pv, pre), + (contains("{}", pre) ; !hr_dyn_base_call(ce)). +// …under the prefix THAT element's own method returns, when the prefix is a call on the same loop variable +// (`app.route(g.getBasePath(V), g.getRoutes())` over `[new A(), new B()]`): element i's class answers both calls, +// so A's routes are under A's prefix only (a call reaching several methods has no one value of its own) +.decl hr_elem_pre(c0:symbol, c1:symbol, c2:symbol) +hr_elem_pre(ce, s, pv) :- hr_reg(ce, _, cn), router_mount_app(cn), expr_child("client", ce, "ARGUMENT", "1", sx), + call_site("client", "METHOD_CALL", sn, _, r, sx, _), expr_referenced("client", "VARIABLE", v, r), + expr_child("client", ce, "ARGUMENT", "0", px), call_site("client", "METHOD_CALL", pn, _, pr, px, _), expr_referenced("client", "VARIABLE", v, pr), + for_binding_iterable(v, it), hr_arr(it, arr), expr_child("client", arr, _, _, el), expr_type(el, _, tt), + method_in_scope(tt, sn, _, w), hr_callee(sx, w), hr_ret_cand(w, s), method_in_scope(tt, pn, _, w2), rd_mval(w2, pv). +.decl hr_elem_has_pre(c0:symbol, c1:symbol) +hr_elem_has_pre(ce, s) :- hr_elem_pre(ce, s, _). +hr_inc(a, s, ce, pre, "mount") :- hr_reg(ce, a, cn), router_mount_app(cn), call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_app(sx, s), s != a, !hr_loop_paired(ce), !hr_multi(s), + hr_elem_pre(ce, s, pv), hr_merge(b, pv, pre), (contains("{}", pre) ; !hr_dyn_base_call(ce)). +hr_inc(a, t, ce, pre, "mount_each") :- hr_reg(ce, a, cn), router_mount_app(cn), call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_app(sx, s), s != a, !hr_loop_paired(ce), hr_multi(s), hr_each_cand(s, t, _), + hr_elem_pre(ce, t, pv), hr_merge(b, pv, pre), (contains("{}", pre) ; !hr_dyn_base_call(ce)). +hr_mreq(b, pv) :- hr_reg(ce, a, _), call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), hr_elem_pre(ce, _, pv). +// a module list read where it is mounted (R12.1): every module the literal glob matches, its default-exported app +hr_inc(a, s, ce, pre, "mount") :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), hr_gtied(ce, g), hr_glob_app_of(g, s), s != a, + expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv), hr_merge(b, pv, pre), + (contains("{}", pre) ; !hr_dyn_base_call(ce)). +// …a derived one: mounted there under a prefix that also holds what the run-time choice adds (`/{}`); every route +// it brings is partial unresolved_mount (hr_dreach), never exact +hr_inc(a, s, ce, pre, "mount_derived") :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), hr_gtied_d(ce, g), hr_glob_app_of(g, s), s != a, + expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv), hr_dpre(pv, dpv), hr_merge(b, dpv, pre). +.decl hr_dpre(c0:symbol, c1:symbol) +hr_dpre(pv, "/{}") :- hr_dpre_need(pv), (pv = "/" ; pv = ""). +hr_dpre(pv, cat("/{}", pv)) :- hr_dpre_need(pv), pv != "/", pv != "", substr(pv, 0, 1) = "/". +hr_dpre(pv, cat("/{}/", pv)) :- hr_dpre_need(pv), pv != "", substr(pv, 0, 1) != "/". +.decl hr_dpre_need(c0:symbol) +hr_dpre_need(pv) :- hr_gtied_d(ce, _), expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv). +hr_mreq(b, dpv) :- hr_reg(ce, a, cn), router_mount_app(cn), call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + hr_gtied_d(ce, _), expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv), hr_dpre(pv, dpv). +// a loop over a const array of list entries: each element's app under that element's path (R13) +hr_inc(a, s, ce, pre, "mount") :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + hr_loop_sub(ce, o, s), s != a, hr_loop_pre_expr(ce, o, px), rd_val(px, pv), hr_merge(b, pv, pre), + (contains("{}", pre) ; !hr_dyn_base_call(ce)). +// a loop over the entries of a const object (`for (const [name, s] of Object.entries(strategies))`) mounting +// `s.method()` under a prefix made from `name`: each entry's own instance runs its own class's method, under its +// own key (the map is known, so this is value-following, not dispatch over every implementation) +hr_inc(a, t, ce, pre, "mount") :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), hr_kv_sub(ce, key, t), t != a, hr_kv_pre(ce, key, pv), + hr_merge(b, pv, pre), (contains("{}", pre) ; !hr_dyn_base_call(ce)). +// a registration on a value that a run-time base may have reached (`if (b) this.server = +// this.server.basePath(b)`), a route or a mount alike, is declared once, partial, and never also +// served at its bare path (SPEC ruling R8a) +.decl hr_dyn_base_call(c0:symbol) +hr_dyn_base_call(ce) :- hr_reg(ce, _, _), call_site("client", _, _, _, r, ce, _), hr_val(r, _, b), contains("{}", b). +hr_mreq(b, pv) :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), + expr_child("client", ce, "ARGUMENT", "0", px), rd_val(px, pv). +hr_mreq(b, pv) :- hr_reg(ce, a, cn), router_mount_app(cn), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), hr_loop_pre_expr(ce, _, px), rd_val(px, pv). +hr_inc(ce, t, ce, "/", "instance") :- hr_callee(ce, w), hr_ret_cand(w, t), expr_enclosing_method(t, w). +hr_inc(a, p, oc, b, "param") :- hr_slot_arg(oc, p, x), hr_val(x, a, b), a != p, !hr_param_mounted(p). +// a parameter the function MOUNTS (`function wrap(inner) { const w = new X(); w.route('/', inner); return w }`): the mount +// takes the app the call passes, so that app is included into the parameter's list at the call (kind `arg`), the +// other way round from a parameter registrations are made on +hr_inc(p, s, oc, "/", "arg") :- hr_param_mounted(p), hr_slot_arg(oc, p, x), hr_app(x, s), s != p. +hr_inc(ce, p, ce, "/", "instance") :- hr_factory_app(ce, f), hr_factory_init_param(f, p). +hr_inc(l, t, ce, "/", "instance") :- hr_objret_inst(l, ce, t). + +// the same links without their prefixes: which lists are roots is decided before any +// string is read, because the strings a root's flattening needs depend on it +.decl hr_included(c0:symbol) +hr_included(s) :- hr_reg(ce, a, cn), router_mount_app(cn), expr_child("client", ce, "ARGUMENT", "1", sx), + hr_app(sx, s), s != a. +hr_included(t) :- hr_callee(ce, w), hr_ret_cand(w, t), expr_enclosing_method(t, w), ce = ce. +hr_included(p) :- hr_slot_arg(_, p, x), hr_app(x, a), a != p. +hr_included(s) :- hr_param_mounted(p), hr_slot_arg(_, p, x), hr_app(x, s), s != p. +hr_included(p) :- hr_factory_app(_, f), hr_factory_init_param(f, p). +hr_included(t) :- hr_objret_inst(_, _, t). +hr_included(t) :- hr_kv_sub(_, _, t). +hr_included(s) :- hr_reg(ce, a, cn), router_mount_app(cn), hr_gtied(ce, g), hr_glob_app_of(g, s), s != a. +hr_included(s) :- hr_reg(ce, a, cn), router_mount_app(cn), hr_gtied_d(ce, g), hr_glob_app_of(g, s), s != a. +.decl hr_list(c0:symbol) +hr_list(a) :- hr_app(_, a). +// a list nothing includes is what a server serves +.decl hr_root(c0:symbol) +hr_root(a) :- hr_list(a), !hr_included(a). +// an app mounted with route(p, it) on a receiver that is not a recognised app: it is served under a +// prefix nothing here knows, so it is never served at its own paths (SPEC [iter2], a mount argument +// is never a root) +.decl hr_unknown_mount(c0:symbol) +hr_unknown_mount(s) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_mount_app(cn), !hr_app(r, _), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_app(sx, s). +// …or an app held by an object that reaches a parameter together with another function's object (hono-8-01): the +// function mounts one of them per call, and which one is not followed here +hr_unknown_mount(s) :- hr_objpar_amb(p), hr_psrc_p(p, w), hr_objcall(_, _, w, o), rd_obj_prop(o, _, v), hr_app(v, s). + +// ── a declarative route list (SPEC ruling R13) ────────────────────────────── +// `const routes = [{ path: '/x', handler: subApp }]; for (const r of routes) app.route(r.path, r.handler)`. +// Values only, never key names: the loop mounts what the ELEMENTS of the array it iterates hold, one +// element at a time, so each element's app is mounted at that element's own path. +// (mount call, loop variable, property the mount argument reads) +.decl hr_loop_mount(c0:symbol, c1:symbol, c2:symbol) +hr_loop_mount(ce, v, hk) :- call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_elem_read(sx, v, hk). +// `el.key`, also through `as X` / `!` +.decl hr_elem_read(c0:symbol, c1:symbol, c2:symbol) +hr_elem_read(x, v, k) :- hr_on(), property_access_name(x, k), expr_child("client", x, "RECEIVER", _, q), + expr_referenced("client", "VARIABLE", v, q), for_binding_iterable(v, _). +hr_elem_read(x, v, k) :- expr_kind("client", kd, _, x), expr_kind_is_transparent(kd), expr_child("client", x, _, _, y), + hr_elem_read(y, v, k). +// the element objects of a const array the loop iterates: each is mounted on its own +.decl hr_loop_elem(c0:symbol, c1:symbol) +hr_loop_elem(ce, o) :- hr_loop_mount(ce, v, _), for_binding_iterable(v, it), hr_arr(it, arr), + expr_child("client", arr, _, _, x), hr_objlit(x, o). +.decl hr_loop_paired(c0:symbol) +hr_loop_paired(ce) :- hr_loop_mount(ce, v, _), for_binding_iterable(v, it), hr_arr(it, _). +hr_loop_paired(ce) :- hr_kv_sub(ce, _, _). +// (key variable, value variable, object): `for (const [k, v] of Object.entries(o))`, o a const object literal +.decl hr_kv_loop(c0:symbol, c1:symbol, c2:symbol) +hr_kv_loop(vk, vv, o) :- ts_variable(_, _, _, _, _, _, _, _, "FOR_BINDING", _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, "INDEX", "0", _, _, _, vk), + ts_variable(_, _, _, _, _, _, _, _, "FOR_BINDING", _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, "INDEX", "1", _, _, _, vv), + for_binding_iterable(vk, it), call_site("client", "METHOD_CALL", "entries", _, _, it, _), + expr_child("client", it, "ARGUMENT", "0", x), hr_denotes_var(x, ov), rd_init_obj(ov, o). +.decl hr_kv_mount(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_kv_mount(ce, vk, vv, mn) :- call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx), call_site("client", "METHOD_CALL", mn, _, q, sx, _), + expr_referenced("client", "VARIABLE", vv, q), hr_kv_loop(vk, vv, _). +.decl hr_kv_sub(c0:symbol, c1:symbol, c2:symbol) +hr_kv_sub(ce, key, t) :- hr_kv_mount(ce, vk, vv, mn), hr_kv_loop(vk, vv, o), rd_obj_prop(o, key, e), expr_type(e, _, tt), + method_in_scope(tt, mn, _, w), hr_ret_cand(w, t), expr_enclosing_method(t, w). +// the prefix for one entry: the key itself, or a template whose one hole is the key +.decl hr_kv_pre(c0:symbol, c1:symbol, c2:symbol) +hr_kv_pre(ce, key, key) :- hr_kv_sub(ce, key, _), hr_kv_mount(ce, vk, _, _), expr_child("client", ce, "ARGUMENT", "0", px), + expr_referenced("client", "VARIABLE", vk, px). +hr_kv_pre(ce, key, pv) :- hr_kv_sub(ce, key, _), hr_kv_mount(ce, vk, _, _), expr_child("client", ce, "ARGUMENT", "0", px), + expr_literal_type("client", "TEMPLATE", px), expr_literal_value("client", raw, px), + expr_child("client", px, "TEMPLATE_SPAN", "0", sp), expr_referenced("client", "VARIABLE", vk, sp), + !expr_child("client", px, "TEMPLATE_SPAN", "1", _), + a = min i : { i = range(0, strlen(raw) - 1), substr(raw, i, 2) = "${" }, + z = min j : { j = range(0, strlen(raw)), substr(raw, j, 1) = "}" }, + pv = cat(substr(raw, 1, a - 1), cat(key, substr(raw, z + 1, strlen(raw) - z - 2))). +hr_mreq(b, pv) :- hr_reg(ce, a, cn), router_mount_app(cn), call_site("client", _, _, _, r, ce, _), hr_val(r, a, b), hr_kv_pre(ce, _, pv). +// the prefix expression for one element: the element's own property when the path argument reads +// the loop variable too, else the path argument itself +.decl hr_loop_pre_expr(c0:symbol, c1:symbol, c2:symbol) +hr_loop_pre_expr(ce, o, px) :- hr_loop_elem(ce, o), hr_loop_mount(ce, v, _), expr_child("client", ce, "ARGUMENT", "0", a), + hr_elem_read(a, v, pk), rd_obj_prop(o, pk, px). +hr_loop_pre_expr(ce, o, a) :- hr_loop_elem(ce, o), hr_loop_mount(ce, v, _), expr_child("client", ce, "ARGUMENT", "0", a), + !hr_elem_read(a, v, _). +rd_demand(px) :- hr_loop_pre_expr(_, _, px). +// the app one element holds under the property the mount reads +.decl hr_loop_sub(c0:symbol, c1:symbol, c2:symbol) +hr_loop_sub(ce, o, s) :- hr_loop_elem(ce, o), hr_loop_mount(ce, _, hk), rd_obj_prop(o, hk, hv), hr_app(hv, s). +// An app written into a list entry (the value of a property of an object literal that is an element of +// an array literal) is mounted by whatever reads that list. When no loop over a const array mounts it, +// the reader is not known here: its routes are served under a prefix nothing here knows, never at its +// own paths. A served shape (requested, its fetch handed out, the default export, a test client) +// always wins. +.decl hr_elem_obj(c0:symbol) +hr_elem_obj(o) :- hr_on(), expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, _, o), + expr_kind("client", "OBJECT_LITERAL", _, o). +hr_elem_obj(o) :- hr_on(), expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, _, x), + expr_kind("client", k, _, x), expr_kind_is_transparent(k), expr_child("client", x, _, _, o), + expr_kind("client", "OBJECT_LITERAL", _, o). +.decl hr_listed(c0:symbol) +hr_listed(a) :- hr_elem_obj(o), rd_obj_prop(o, _, v), hr_app(v, a). +.decl hr_served_list(c0:symbol) +hr_served_list(a) :- hr_served_use(a). +hr_served_list(a) :- hr_default_app(_, a). +.decl hr_default_app(c0:symbol, c1:symbol) +hr_default_app(m, a) :- export_decl(_, "default", _, _, m, h), export_expression("client", x, h), hr_app(x, a). +.decl hr_served_use(c0:symbol) +hr_served_use(a) :- hr_app(r, a), call_site("client", "METHOD_CALL", cn, _, r, _, _), + (router_app_request(cn) ; router_served_fetch(cn)). +// (written from the knob outward: started from hr_app, property_access_name shared no variable with it and the rule +// enumerated every app value against every property read) +hr_served_use(a) :- router_served_fetch(n), property_access_name(e, n), expr_child("client", e, "RECEIVER", _, r), hr_app(r, a). +hr_served_use(a) :- call_site("client", "FUNCTION_CALL", _, _, _, tc, _), expr_child("client", tc, "METHOD_NAME", _, f), + expr_referenced("client", "IMPORT_BINDING", ih, f), import_binding("client", _, _, orig, _, ih), + hr_import_spec(ih, spec), router_test_client(spec, orig), expr_child("client", tc, "ARGUMENT", "0", x), hr_app(x, a). +.decl hr_list_entry(c0:symbol) +hr_list_entry(a) :- hr_listed(a), !hr_served_list(a). +// An OPAQUE module list (SPEC ruling R12.2): `app.route(p, mod.default)` where `mod` is a module the program loads by +// a name it computes (`await import(file)` over a directory listing). Its candidates are the default-exported apps, +// in the mounting module's directory or below, that no module imports, nothing mounts and nothing serves; the +// mounting module and every module importing it are the entry, never a candidate. +.decl hr_opaque_mount(c0:symbol, c1:symbol) +hr_opaque_mount(ce, m) :- call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx), !hr_app(sx, _), hr_default_read(sx), expr_module("client", m, ce), + !hr_gtied(ce, _), !hr_gtied_d(ce, _). +.decl hr_default_read(c0:symbol) +hr_default_read(x) :- hr_on(), property_access_name(x, "default"). +hr_default_read(x) :- expr_kind("client", k, _, x), expr_kind_is_transparent(k), expr_child("client", x, _, _, y), hr_default_read(y). +.decl hr_entry_mod(c0:symbol) +hr_entry_mod(m) :- hr_opaque_mount(_, m). +hr_entry_mod(m) :- hr_entry_mod(t), import_binding("client", _, _, _, m, ih), import_target_module(ih, _, t). +.decl hr_imported_mod(c0:symbol) +hr_imported_mod(t) :- hr_on(), import_target_module(_, _, t). +hr_imported_mod(t) :- hr_on(), dynamic_import_module(_, t). +.decl hr_opaque_dir(c0:symbol) +hr_opaque_dir(d) :- hr_opaque_mount(_, m), module_decl("client", _, _, fp, _, m), hr_mdir(fp, d). +.decl hr_mdir_slash(c0:symbol, c1:number) +hr_mdir_slash(fp, i) :- hr_on(), module_decl("client", _, _, fp, _, _), i = range(0, strlen(fp)), substr(fp, i, 1) = "/". +.decl hr_mdir(c0:symbol, c1:symbol) +hr_mdir(fp, d) :- module_decl("client", _, _, fp, _, _), hr_mdir_slash(fp, _), j = max i : { hr_mdir_slash(fp, i) }, + d = substr(fp, 0, j + 1). +hr_mdir(fp, "") :- hr_on(), module_decl("client", _, _, fp, _, _), !hr_mdir_slash(fp, _). +.decl hr_opaque_cand(c0:symbol) +hr_opaque_cand(a) :- hr_opaque_dir(d), module_decl("client", _, _, fp, _, m), strlen(fp) > strlen(d), substr(fp, 0, strlen(d)) = d, + !hr_entry_mod(m), !hr_imported_mod(m), hr_default_app(m, a), !hr_included(a). +hr_list_entry(a) :- hr_opaque_cand(a), !hr_served_use(a). +// A module list (SPEC ruling R12): `import.meta.glob('../routes/**/*.index.ts')`, the pattern a literal, is resolved +// against the project's files; the default-exported app of each matched module is loaded to be mounted by +// whatever iterates the list. Its default export is how the list reads it, not how a server serves it, so only a +// served use wins here. Which mount takes it is not followed through the run-time filtering the list goes +// through: its routes are under a prefix not known here. +.decl hr_glob_pat(c0:symbol, c1:symbol, c2:symbol) +hr_glob_pat(ce, m, pat) :- call_site("client", "METHOD_CALL", cn, _, "", ce, _), router_module_glob(cn), + expr_child("client", ce, "METHOD_NAME", _, pa), !expr_child("client", pa, "RECEIVER", _, _), + expr_child("client", ce, "ARGUMENT", "0", x), hr_glob_lit(x, pat), expr_module("client", m, ce). +.decl hr_glob_lit(c0:symbol, c1:symbol) +hr_glob_lit(x, v) :- hr_on(), expr_kind("client", "LITERAL", _, x), expr_literal_value("client", v, x). +hr_glob_lit(x, v) :- hr_on(), expr_kind("client", "ARRAY_LITERAL", _, x), expr_child("client", x, _, _, y), + expr_kind("client", "LITERAL", _, y), expr_literal_value("client", v, y), substr(v, 0, 1) != "!". +// the pattern made relative to the source root: `./` dropped, each `../` takes a directory off the module's own +.decl hr_glob_res(c0:symbol, c1:symbol, c2:symbol) +hr_glob_res(ce, dir, pat) :- hr_glob_pat(ce, m, pat), module_decl("client", _, _, fp, _, m), hr_dir_of(fp, dir). +hr_glob_res(ce, dir, r) :- hr_glob_res(ce, dir, x), strlen(x) > 2, substr(x, 0, 2) = "./", r = substr(x, 2, strlen(x) - 2). +hr_glob_res(ce, up, r) :- hr_glob_res(ce, dir, x), strlen(x) > 3, substr(x, 0, 3) = "../", dir != "", + hr_dir_of(dir, up), r = substr(x, 3, strlen(x) - 3). +.decl hr_dir_need(c0:symbol) +hr_dir_need(fp) :- hr_glob_pat(_, m, _), module_decl("client", _, _, fp, _, m). +// …and every directory above it (decided from the path alone, so the walk up reads no result of itself) +hr_dir_need(d) :- hr_glob_pat(_, m, _), module_decl("client", _, _, fp, _, m), i = range(1, strlen(fp)), substr(fp, i, 1) = "/", + d = substr(fp, 0, i). +.decl hr_dir_slash(c0:symbol, c1:number) +hr_dir_slash(p, i) :- hr_dir_need(p), i = range(0, strlen(p)), substr(p, i, 1) = "/". +.decl hr_dir_of(c0:symbol, c1:symbol) +hr_dir_of(p, d) :- hr_dir_need(p), hr_dir_slash(p, _), j = max i : { hr_dir_slash(p, i) }, d = substr(p, 0, j). +hr_dir_of(p, "") :- hr_dir_need(p), !hr_dir_slash(p, _). +.decl hr_glob_full(c0:symbol, c1:symbol) +hr_glob_full(ce, f) :- hr_glob_res(ce, dir, x), substr(x, 0, 1) != ".", dir != "", f = cat(dir, cat("/", x)). +hr_glob_full(ce, x) :- hr_glob_res(ce, "", x), substr(x, 0, 1) != ".". +// the glob as a regular expression: `**/` any directories, `*` within one, `?` one character, `{a,b}` either +.decl hr_glob_re(c0:symbol, c1:number, c2:symbol, c3:number) +hr_glob_re(f, 0, "", 0) :- hr_glob_full(_, f). +hr_glob_re(f, i + 3, cat(acc, "(.*/)?"), b) :- hr_glob_re(f, i, acc, b), i + 3 <= strlen(f), substr(f, i, 3) = "**/". +hr_glob_re(f, i + 2, cat(acc, ".*"), b) :- hr_glob_re(f, i, acc, b), i + 2 <= strlen(f), substr(f, i, 2) = "**", + (i + 2 = strlen(f) ; substr(f, i + 2, 1) != "/"). +hr_glob_re(f, i + 1, cat(acc, "[^/]*"), b) :- hr_glob_re(f, i, acc, b), i < strlen(f), substr(f, i, 1) = "*", + (i + 1 = strlen(f) ; substr(f, i + 1, 1) != "*"). +hr_glob_re(f, i + 1, cat(acc, "[^/]"), b) :- hr_glob_re(f, i, acc, b), i < strlen(f), substr(f, i, 1) = "?". +hr_glob_re(f, i + 1, cat(acc, "("), 1) :- hr_glob_re(f, i, acc, 0), i < strlen(f), substr(f, i, 1) = "{". +hr_glob_re(f, i + 1, cat(acc, ")"), 0) :- hr_glob_re(f, i, acc, 1), i < strlen(f), substr(f, i, 1) = "}". +hr_glob_re(f, i + 1, cat(acc, "|"), 1) :- hr_glob_re(f, i, acc, 1), i < strlen(f), substr(f, i, 1) = ",". +hr_glob_re(f, i + 1, cat(acc, cat("\\", ch)), b) :- hr_glob_re(f, i, acc, b), i < strlen(f), ch = substr(f, i, 1), + (ch = "." ; ch = "(" ; ch = ")" ; ch = "+" ; ch = "$" ; ch = "^" ; ch = "[" ; ch = "]" ; ch = "|"). +hr_glob_re(f, i + 1, cat(acc, ch), b) :- hr_glob_re(f, i, acc, b), i < strlen(f), ch = substr(f, i, 1), + ch != "*", ch != "?", ch != "{", ch != "}", ch != ".", ch != "(", ch != ")", ch != "+", ch != "$", ch != "^", + ch != "[", ch != "]", ch != "|", (ch != "," ; b = 0). +hr_glob_re(f, i + 1, cat(acc, ","), 0) :- hr_glob_re(f, i, acc, 0), i < strlen(f), substr(f, i, 1) = ",". +.decl hr_glob_mod(c0:symbol, c1:symbol) +hr_glob_mod(ce, m2) :- hr_glob_full(ce, f), hr_glob_re(f, strlen(f), re, 0), module_decl("client", _, _, fp, _, m2), match(re, fp). +.decl hr_glob_app_of(c0:symbol, c1:symbol) +hr_glob_app_of(ce, a) :- hr_glob_mod(ce, m), hr_default_app(m, a). +.decl hr_glob_app(c0:symbol) +hr_glob_app(a) :- hr_glob_app_of(_, a). +// The list read where it is mounted: `for (const mod of Object.values(G)) app.route(p, mod.default)` (eager) or +// `const mod = await G[key](); app.route(p, mod.default)` (lazy), G the glob's value through consts, element reads, +// the loader's call, an await, and the language's own Object.values / Object.entries. A project function in +// between (a run-time filter) is not followed: then the modules stay candidates under an unknown prefix. +.decl hr_gflow(c0:symbol, c1:symbol) +hr_gflow(g, g) :- hr_glob_pat(g, _, _). +hr_gflow(r, g) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_gflow(i, g). +hr_gflow(r, g) :- expr_referenced("client", "VARIABLE", v, r), for_binding_iterable(v, it), hr_gflow(it, g). +hr_gflow(e, g) :- hr_gflow(c, g), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION" ; k = "ELEMENT_ACCESS"). +hr_gflow(e, g) :- hr_gflow(c, g), expr_child("client", e, "METHOD_NAME", _, c), call_site("client", _, _, _, _, e, _). +hr_gflow(e, g) :- hr_gflow(c, g), expr_child("client", e, "ARGUMENT", "0", c), call_site("client", "METHOD_CALL", n, _, r, e, _), + (n = "values" ; n = "entries"), r != "". +// …and the same list after a project function took it (a run-time filter, `pick(tier, all)`): DERIVED, its +// modules are mounted there, but which of them is decided at run time (SPEC R13 derived lists) +.decl hr_gflow_d(c0:symbol, c1:symbol) +hr_gflow_d(e, g) :- hr_gflow(c, g), expr_child("client", e, "ARGUMENT", _, c), hr_call_of(e, _). +hr_gflow_d(e, g) :- hr_gflow_d(c, g), expr_child("client", e, "ARGUMENT", _, c), hr_call_of(e, _). +hr_gflow_d(r, g) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_gflow_d(i, g). +hr_gflow_d(r, g) :- expr_referenced("client", "VARIABLE", v, r), for_binding_iterable(v, it), hr_gflow_d(it, g). +hr_gflow_d(e, g) :- hr_gflow_d(c, g), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION" ; k = "ELEMENT_ACCESS"). +hr_gflow_d(e, g) :- hr_gflow_d(c, g), expr_child("client", e, "METHOD_NAME", _, c), call_site("client", _, _, _, _, e, _). +hr_gflow_d(e, g) :- hr_gflow_d(c, g), expr_child("client", e, "ARGUMENT", "0", c), call_site("client", "METHOD_CALL", n, _, r, e, _), + (n = "values" ; n = "entries"), r != "". +.decl hr_gdefault_d(c0:symbol, c1:symbol) +hr_gdefault_d(x, g) :- property_access_name(x, "default"), expr_child("client", x, "RECEIVER", _, q), hr_gflow_d(q, g). +hr_gdefault_d(x, g) :- expr_kind("client", k, _, x), expr_kind_is_transparent(k), expr_child("client", x, _, _, y), hr_gdefault_d(y, g). +.decl hr_gtied_d(c0:symbol, c1:symbol) +hr_gtied_d(ce, g) :- call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_gdefault_d(sx, g), !hr_gtied(ce, _). +.decl hr_gtied(c0:symbol, c1:symbol) +hr_gtied(ce, g) :- call_site("client", "METHOD_CALL", cn, _, _, ce, _), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx), hr_gdefault(sx, g). +.decl hr_gdefault(c0:symbol, c1:symbol) +hr_gdefault(x, g) :- property_access_name(x, "default"), expr_child("client", x, "RECEIVER", _, q), hr_gflow(q, g). +hr_gdefault(x, g) :- expr_kind("client", k, _, x), expr_kind_is_transparent(k), expr_child("client", x, _, _, y), hr_gdefault(y, g). +hr_list_entry(a) :- hr_glob_app(a), !hr_served_use(a). + + +// ── list elements followed through functions (SPEC ruling R13b) ───────────── +// A loop mounts the elements of a list a function was HANDED (`function mountPlugin(app, plugin) { for (const r of +// plugin.routes ?? []) app.route(r.path, r.handler) }`), or a list built by a helper (a push-built result, a sort, a +// `map` round trip). Values only: an expression's value is an object or array literal, reached by an ACCESS PATH +// (`|.routes|[]`: the property `routes`, then an element), or the same of a parameter. A parameter of a function that +// mounts (hv_ctx) is kept symbolic and bound per call, so each call mounts what it passes (/solo into the app of the +// call that passes it, never into every caller's); any other function's parameter is every value passed to it. +// The last column is 1 when the value went through a `filter` (its registrations are conditional). +.decl hv_ctx(c0:symbol) +hv_ctx(f) :- hr_loop_mount(ce, _, _), expr_enclosing_method(ce, f). +hv_ctx(f) :- hv_hsite(ce, _, _), expr_enclosing_method(ce, f). +hv_ctx(f) :- expr_enclosing_method(oc, f), hr_call_of(oc, g), hv_ctx(g). +// A function that RETURNS an object literal (`definePlugin(input) { return { routes: input.routes } }`) builds a fresh +// object per call: its result is the CALL (hv_objcall), and what the object holds is read with that call's own +// arguments, so its parameters are never the union of every caller's (one test's plugin is no other app's) +.decl hv_objret(c0:symbol, c1:symbol) +hv_objret(w, x) :- hr_ret_expr(w, x), expr_kind("client", "OBJECT_LITERAL", _, x). +.decl hv_nounion(c0:symbol) +hv_nounion(f) :- hv_ctx(f). +hv_nounion(w) :- hv_objret(w, _). +.decl hv_need(c0:symbol) +.decl hv(c0:symbol, c1:symbol, c2:symbol, c3:number) +hv_need(it) :- hr_loop_mount(ce, v, _), !hr_loop_paired(ce), for_binding_iterable(v, it). +hv_need(i) :- hv_need(e), hr_denotes_var(e, v), var_initializer("client", _, i, v), i != "". +hv_need(c) :- hv_need(e), expr_kind("client", k, _, e), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"), expr_child("client", e, _, _, c). +hv_need(q) :- hv_need(e), property_access_name(e, _), expr_child("client", e, "RECEIVER", _, q). +hv_need(it) :- hv_need(e), expr_referenced("client", "VARIABLE", v, e), for_binding_iterable(v, it). +hv_need(r) :- hv_need(e), call_site("client", "METHOD_CALL", n, _, r, e, _), hr_arr_subset(n), r != "". +hv_need(r) :- hv_need(e), call_site("client", "METHOD_CALL", n, _, r, e, _), hv_map(n), r != "". +hv_need(c) :- hv_need(e), expr_kind("client", "BINARY_EXPRESSION", _, e), (expr_operator("client", "??", e) ; expr_operator("client", "||", e)), + expr_child("client", e, _, _, c). +hv_need(c) :- hv_need(e), expr_kind("client", "TERNARY_EXPRESSION", _, e), (expr_child("client", e, "TERNARY_THEN", _, c) ; expr_child("client", e, "TERNARY_ELSE", _, c)). +hv_need(x) :- hv_need(e), hr_call_of(e, w), hr_ret_expr(w, x), !hv_objret(w, x). +hv_need(a) :- hv_need(e), expr_referenced("client", "PARAMETER", p, e), param_decl("client", _, pos, _, w, p), !hv_nounion(w), + hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a). +hv_need(r) :- hv_need(e), hv_cbparam(e, mc), call_site("client", "METHOD_CALL", _, _, r, mc, _). +// the methods whose result is the receiver's elements (hr_arr_subset), and those whose result is the callback's return +.decl hv_map(c0:symbol) +hv_map("map"). hv_map("flatMap"). +// a reference to the first parameter of a callback handed to a list method (`routes.map((r) => ..)`): an element +.decl hv_cbparam(c0:symbol, c1:symbol) +hv_cbparam(e, mc) :- expr_referenced("client", "PARAMETER", p, e), param_decl("client", _, "0", _, f, p), expr_anon_decl("client", f, fx), + expr_child("client", mc, "ARGUMENT", "0", fx), call_site("client", "METHOD_CALL", n, _, _, mc, _), (hv_map(n) ; hr_arr_subset(n) ; n = "forEach"). +hv(e, e, "", 0) :- hv_need(e), (expr_kind("client", "OBJECT_LITERAL", _, e) ; expr_kind("client", "ARRAY_LITERAL", _, e)). +hv(e, e, "", 0) :- hv_need(e), call_site("client", "METHOD_CALL", n, _, r, e, _), hv_map(n), r != "". +hv(e, b, p, c) :- hv_need(e), hr_denotes_var(e, v), var_initializer("client", _, i, v), i != "", hv(i, b, p, c). +hv(e, b, p, c) :- hv_need(e), expr_kind("client", k, _, e), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"), expr_child("client", e, _, _, x), + hv(x, b, p, c). +hv(e, b, cat(p, cat("|.", n)), c) :- hv_need(e), property_access_name(e, n), expr_child("client", e, "RECEIVER", _, q), hv(q, b, p, c), + strlen(p) < 120. +hv(e, b, cat(p, "|[]"), c) :- hv_need(e), expr_referenced("client", "VARIABLE", v, e), for_binding_iterable(v, it), hv(it, b, p, c), strlen(p) < 120. +hv(e, b, p, c) :- hv_need(e), call_site("client", "METHOD_CALL", n, _, r, e, _), hr_arr_subset(n), n != "filter", hv(r, b, p, c). +hv(e, b, p, 1) :- hv_need(e), call_site("client", "METHOD_CALL", "filter", _, r, e, _), hv(r, b, p, _). +hv(e, b, p, c) :- hv_need(e), expr_kind("client", "BINARY_EXPRESSION", _, e), (expr_operator("client", "??", e) ; expr_operator("client", "||", e)), + expr_child("client", e, _, _, x), hv(x, b, p, c). +hv(e, b, p, c) :- hv_need(e), expr_kind("client", "TERNARY_EXPRESSION", _, e), + (expr_child("client", e, "TERNARY_THEN", _, x) ; expr_child("client", e, "TERNARY_ELSE", _, x)), hv(x, b, p, c). +hv(e, e, "", 0) :- hv_need(e), hr_call_of(e, w), hv_objret(w, _). +hv(e, b, p, c) :- hv_need(e), hr_call_of(e, w), hr_ret_expr(w, x), !hv_objret(w, x), hv(x, b, p, c), !hv_isparam(b, w). +hv(e, b2, cat(p2, p), max(c, c2)) :- hv_need(e), hr_call_of(e, w), hr_ret_expr(w, x), !hv_objret(w, x), hv(x, b, p, c), hv_isparam(b, w), + param_decl("client", _, pos, _, w, b), expr_child("client", e, "ARGUMENT", pos, a), hv(a, b2, p2, c2), strlen(p2) + strlen(p) < 160. +hv(e, p, "", 0) :- hv_need(e), expr_referenced("client", "PARAMETER", p, e), !hv_cbparam(e, _). +hv(e, b, p, c) :- hv_need(e), expr_referenced("client", "PARAMETER", pp, e), param_decl("client", _, pos, _, w, pp), !hv_nounion(w), + !hv_cbparam(e, _), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a), hv(a, b, p, c). +hv(e, b, cat(p, "|[]"), c) :- hv_need(e), hv_cbparam(e, mc), call_site("client", "METHOD_CALL", _, _, r, mc, _), hv(r, b, p, c), strlen(p) < 120. +.decl hv_isparam(c0:symbol, c1:symbol) +hv_isparam(b, w) :- hr_on(), param_decl("client", _, _, _, w, b). +.decl hv_param(c0:symbol) +hv_param(b) :- hr_on(), param_decl("client", _, _, _, _, b). +// stepping a path from a literal: (base, path) -> (base', path') one step further, and whether a filter was crossed +.decl hv_step(c0:symbol, c1:symbol, c2:symbol) +hv_step(pth, tok, rest) :- hv_todo(_, pth), strlen(pth) > 1, substr(pth, 0, 1) = "|", j = range(2, strlen(pth) + 1), + (j = strlen(pth) ; substr(pth, j, 1) = "|"), tok = substr(pth, 1, j - 1), !contains("|", tok), rest = substr(pth, j, strlen(pth) - j). +// (a literal base, a path still to walk) +.decl hv_todo(c0:symbol, c1:symbol) +// the value one step reaches: a property of an object literal (also through `...spread`), an element of an array literal +// (also one `push`ed onto the variable it initialises), the callback's return for a `map` result +.decl hv_elem(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hv_elem(o, tok, v, "own") :- hv_todo(o, pth), hv_step(pth, tok, _), substr(tok, 0, 1) = ".", rd_obj_prop(o, substr(tok, 1, strlen(tok) - 1), v). +hv_elem(o, tok, v, "spread") :- hv_todo(o, pth), hv_step(pth, tok, _), substr(tok, 0, 1) = ".", expr_kind("client", "OBJECT_LITERAL", _, o), + expr_child("client", o, "SPREAD_OPERAND", _, x), hv_spread_src(x, v). +hv_elem(a, "[]", x, "own") :- hv_todo(a, pth), hv_step(pth, "[]", _), expr_kind("client", "ARRAY_LITERAL", _, a), expr_child("client", a, _, _, x), + !expr_kind("client", "SPREAD_ELEMENT", _, x). +hv_elem(a, "[]", x, "own") :- hv_todo(a, pth), hv_step(pth, "[]", _), expr_kind("client", "ARRAY_LITERAL", _, a), var_initializer("client", _, a, d), + call_site("client", "METHOD_CALL", "push", _, r, pc, _), expr_referenced("client", "VARIABLE", d, r), expr_child("client", pc, "ARGUMENT", _, x). +hv_elem(mc, "[]", x, "own") :- hv_todo(mc, pth), hv_step(pth, "[]", _), call_site("client", "METHOD_CALL", n, _, _, mc, _), hv_map(n), + expr_child("client", mc, "ARGUMENT", "0", fx), expr_anon_decl("client", f, fx), hr_ret_expr(f, x). +// …a property of the object a builder call returns (kind `call`: read with that call's arguments, hv_cv) +hv_elem(e, tok, v, "call") :- hv_todo(e, pth), hv_step(pth, tok, _), substr(tok, 0, 1) = ".", hr_call_of(e, w), hv_objret(w, x), + rd_obj_prop(x, substr(tok, 1, strlen(tok) - 1), v). +// …the elements of a list an array literal spreads (`[...routes].sort(..)`): looked up in the spread list +hv_elem(a, "[]", y, "spread") :- hv_todo(a, pth), hv_step(pth, "[]", _), expr_kind("client", "ARRAY_LITERAL", _, a), expr_child("client", a, _, _, x), + expr_kind("client", "SPREAD_ELEMENT", _, x), expr_child("client", x, _, _, y). +// …a method the object holds, as the LAST step (`plugin.register`, handed an app): the function itself +hv_elem(o, tok, f, "fn") :- hv_todo(o, pth), hv_step(pth, tok, ""), substr(tok, 0, 1) = ".", objlit_member_fn(o, substr(tok, 1, strlen(tok) - 1), f). +// a value read inside a builder, seen from one call of it: its parameters are that call's arguments +.decl hv_cv(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +// …a property the builder's object takes from an object it spreads (`return { ...input, defined: true }`): looked up +// in the spread value, as seen from the call (kind `callspread`) +hv_elem(e, tok, y, "callspread") :- hv_todo(e, pth), hv_step(pth, tok, _), substr(tok, 0, 1) = ".", hr_call_of(e, w), hv_objret(w, x), + expr_child("client", x, "SPREAD_OPERAND", _, sx), hv_spread_src(sx, y). +.decl hv_callk(c0:symbol) +hv_callk("call"). hv_callk("callspread"). +hv_cv(e, v, b2, p2, c) :- hv_elem(e, _, v, k), hv_callk(k), hv(v, b2, p2, c), hr_call_of(e, w), !hv_isparam(b2, w). +hv_cv(e, v, b4, cat(p4, p2), max(c, c4)) :- hv_elem(e, _, v, k), hv_callk(k), hv(v, b2, p2, c), hr_call_of(e, w), param_decl("client", _, pos, _, w, b2), + expr_child("client", e, "ARGUMENT", pos, a), hv(a, b4, p4, c4), strlen(p4) + strlen(p2) < 160. +hv_need(a) :- hv_elem(e, _, _, k), hv_callk(k), hr_call_of(e, w), param_decl("client", _, pos, _, w, _), expr_child("client", e, "ARGUMENT", pos, a). +// a spread source stands for the object it spreads: a property lookup continues in it (marked so the step repeats there) +.decl hv_spread_src(c0:symbol, c1:symbol) +hv_spread_src(x, y) :- hr_on(), expr_kind("client", "OBJECT_LITERAL", _, o), expr_child("client", o, "SPREAD_OPERAND", _, x), + expr_kind("client", "SPREAD_ELEMENT", _, x), expr_child("client", x, _, _, y). +hv_spread_src(x, x) :- hr_on(), expr_kind("client", "OBJECT_LITERAL", _, o), expr_child("client", o, "SPREAD_OPERAND", _, x), + !expr_kind("client", "SPREAD_ELEMENT", _, x). +hv_need(v) :- hv_elem(_, _, v, _). +// hv_res(base, path, base', path', filtered): the path walked from a literal until a parameter or the end +.decl hv_res(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +hv_res(b, p, b, p, 0) :- hv_todo(b, p), (p = "" ; hv_param(b)). +hv_res(b, p, b3, p3, max(c1, c2)) :- hv_todo(b, p), !hv_param(b), hv_step(p, tok, rest), hv_elem(b, tok, v, "own"), + hv(v, b2, p2, c1), hv_res(b2, cat(p2, rest), b3, p3, c2). +// …a property found in a spread object: look the same property up there +hv_res(b, p, b3, p3, max(c1, c2)) :- hv_todo(b, p), hv_step(p, tok, _), hv_elem(b, tok, v, "spread"), hv(v, b2, p2, c1), + hv_res(b2, cat(p2, p), b3, p3, c2). +hv_todo(b2, cat(p2, rest)) :- hv_todo(b, p), !hv_param(b), hv_step(p, tok, rest), hv_elem(b, tok, v, "own"), hv(v, b2, p2, _), + strlen(p2) + strlen(rest) < 160. +hv_res(b, p, b3, p3, max(c1, c2)) :- hv_todo(b, p), hv_step(p, tok, rest), hv_elem(b, tok, v, "call"), hv_cv(b, v, b2, p2, c1), + hv_res(b2, cat(p2, rest), b3, p3, c2). +hv_todo(b2, cat(p2, rest)) :- hv_todo(b, p), hv_step(p, tok, rest), hv_elem(b, tok, v, "call"), hv_cv(b, v, b2, p2, _), strlen(p2) + strlen(rest) < 160. +hv_res(b, p, b3, p3, max(c1, c2)) :- hv_todo(b, p), hv_step(p, _, _), hv_elem(b, tok, v, "callspread"), hv_step(p, tok, _), hv_cv(b, v, b2, p2, c1), + hv_res(b2, cat(p2, p), b3, p3, c2). +hv_todo(b2, cat(p2, p)) :- hv_todo(b, p), hv_step(p, tok, _), hv_elem(b, tok, v, "callspread"), hv_cv(b, v, b2, p2, _), strlen(p2) + strlen(p) < 160. +hv_res(b, p, f, "", 0) :- hv_todo(b, p), !hv_param(b), hv_step(p, tok, ""), hv_elem(b, tok, f, "fn"). +hv_todo(b2, cat(p2, p)) :- hv_todo(b, p), hv_step(p, tok, _), hv_elem(b, tok, v, "spread"), hv(v, b2, p2, _), strlen(p2) + strlen(p) < 160. + +// PENDING MOUNTS: (mount, inclusion site, receiver expression, element base, path, filtered, prefix key, app key). A mount +// in a loop over a list that is not a literal here: the element base is walked to an object literal, or, when it is a +// parameter of the function the pending sits in, bound at every call of that function (and so is a receiver that is a +// parameter of it, the call becoming the inclusion site) +.decl hv_pm(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:number, c6:symbol, c7:symbol) +hv_pm(ce, ce, r, b, cat(p, "|[]"), c, kp, kh) :- hr_loop_mount(ce, v, kh), !hr_loop_paired(ce), call_site("client", _, _, _, r, ce, _), + for_binding_iterable(v, it), hv(it, b, p, c), expr_child("client", ce, "ARGUMENT", "0", a0), hr_elem_read(a0, v, kp). +hv_todo(b, p) :- hv_pm(_, _, _, b, p, _, _, _). +hv_pm(om, s, r, b2, p2, max(c, c2), kp, kh) :- hv_pm(om, s, r, b, p, c, kp, kh), !hv_param(b), hv_res(b, p, b2, p2, c2), (b2 != b ; p2 != p). +// the receiver is a parameter of the function the element parameter belongs to: both bound at each call +.decl hv_recv_param(c0:symbol, c1:symbol, c2:symbol) +hv_recv_param(r, w, pos) :- hv_rx(r), hr_app(r, pr), param_decl("client", _, pos, _, w, pr). +.decl hv_rx(c0:symbol) +hv_rx(r) :- hr_on(), call_site("client", "METHOD_CALL", cn, _, r, _, _), router_mount_app(cn), r != "". +hv_rx(r) :- hr_on(), call_site("client", _, _, _, _, oc, _), expr_child("client", oc, "ARGUMENT", _, r). +hv_pm(om, oc, r2, b2, cat(p2, p), max(c, c2), kp, kh) :- hv_pm(om, _, r, b, p, c, kp, kh), param_decl("client", _, pos, _, w, b), + hv_recv_param(r, w, rpos), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a), hv_need_arg(a), hv(a, b2, p2, c2), + expr_child("client", oc, "ARGUMENT", rpos, r2), strlen(p2) + strlen(p) < 160. +hv_pm(om, s, r, b2, cat(p2, p), max(c, c2), kp, kh) :- hv_pm(om, s, r, b, p, c, kp, kh), param_decl("client", _, pos, _, w, b), + !hv_recv_param(r, w, _), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a), hv_need_arg(a), hv(a, b2, p2, c2), + strlen(p2) + strlen(p) < 160. +.decl hv_need_arg(c0:symbol) +hv_need_arg(a) :- hv_pm(_, _, _, b, _, _, _, _), param_decl("client", _, pos, _, w, b), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a). +hv_need(a) :- hv_need_arg(a). +// the element objects each pending mount takes, with the receiver it is mounted on +.decl hv_fin(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number, c5:symbol, c6:symbol) +hv_fin(om, s, r, o, c, kp, kh) :- hv_pm(om, s, r, o, "", c, kp, kh), expr_kind("client", "OBJECT_LITERAL", _, o). +.decl hv_fin_sub(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hv_fin_sub(s, r, o, t) :- hv_fin(_, s, r, o, _, _, kh), rd_obj_prop(o, kh, hx), hr_app(hx, t). +hr_included(t) :- hv_fin_sub(_, r, _, t), hr_app(r, a), a != t. +rd_demand(px) :- hv_fin(_, _, _, o, _, kp, _), rd_obj_prop(o, kp, px). +hr_inc(a, t, s, pre, "mount") :- hv_fin(_, s, r, o, _, kp, kh), rd_obj_prop(o, kh, hx), hr_app(hx, t), hr_val(r, a, b), a != t, + rd_obj_prop(o, kp, px), rd_val(px, pv), hr_merge(b, pv, pre), (contains("{}", pre) ; !hr_dyn_base_call_r(r)). +hr_mreq(b, pv) :- hv_fin(_, _, r, o, _, kp, _), hr_val(r, _, b), rd_obj_prop(o, kp, px), rd_val(px, pv). +.decl hr_dyn_base_call_r(c0:symbol) +hr_dyn_base_call_r(r) :- hv_fin(_, _, r, _, _, _, _), hr_val(r, _, b), contains("{}", b). +// filtered on the way: what it brings is conditional (SPEC R13b) +.decl hr_cond_inc(c0:symbol, c1:symbol) +hr_cond_inc(t, s) :- hv_fin(_, s, _, o, 1, _, kh), rd_obj_prop(o, kh, hx), hr_app(hx, t). +.decl hv_fin_mount(c0:symbol) +hv_fin_mount(om) :- hv_fin(om, _, _, _, _, _, _). + +// A method HANDED an app by a call through a list element (`for (const p of plugins) p.register?.(app)`): the element +// objects the loop iterates name the method; its app parameter is included into the passed app (kind `param`), each +// call where it is made (SPEC R13b; the element list filtered makes it conditional) +.decl hv_hcall(c0:symbol, c1:symbol) +hv_hcall(ce, q) :- call_site("client", k, n, _, q, ce, _), (k = "METHOD_CALL" ; k = "OPTIONAL_CALL"), q != "", expr_referenced("client", "VARIABLE", v, q), for_binding_iterable(v, _), + !hr_registrar(n), expr_child("client", ce, "ARGUMENT", _, x), hr_app(x, _). +hv_need(q) :- hv_hcall(_, q). +.decl hv_hobj(c0:symbol, c1:symbol, c2:number) +hv_hobj(ce, o, max(c, c2)) :- hv_hcall(ce, q), hv(q, b, p, c), hv_todo2(b, p), hv_res(b, p, o, "", c2), expr_kind("client", "OBJECT_LITERAL", _, o). +.decl hv_todo2(c0:symbol, c1:symbol) +hv_todo2(b, p) :- hv_hcall(_, q), hv(q, b, p, _). +hv_todo(b, p) :- hv_todo2(b, p). +// the method the element names: its own member, or one of an object it spreads +.decl hv_member(c0:symbol, c1:symbol, c2:symbol) +hv_member(o, n, f) :- hv_hobj(ce, o, _), call_site("client", _, n, _, _, ce, _), objlit_member_fn(o, n, f). +hv_member(o0, n, f) :- hv_hobj(ce, o0, _), call_site("client", _, n, _, _, ce, _), hv_spreads(o0, o), objlit_member_fn(o, n, f). +.decl hv_spreads(c0:symbol, c1:symbol) +hv_spreads(o, o2) :- hv_hobj(_, o, _), expr_child("client", o, "SPREAD_OPERAND", _, x), hv_spread_src(x, y), hv_need_sp(y), hv(y, b, p, _), hv_todo3(b, p), + hv_res(b, p, o2, "", _), expr_kind("client", "OBJECT_LITERAL", _, o2). +.decl hv_need_sp(c0:symbol) +hv_need_sp(y) :- hv_hobj(_, o, _), expr_child("client", o, "SPREAD_OPERAND", _, x), hv_spread_src(x, y). +hv_need(y) :- hv_need_sp(y). +.decl hv_todo3(c0:symbol, c1:symbol) +hv_todo3(b, p) :- hv_need_sp(y), hv(y, b, p, _). +hv_todo(b, p) :- hv_todo3(b, p). +.decl hv_handed(c0:symbol, c1:symbol, c2:symbol, c3:number) +hv_handed(ce, f, pf, c) :- hv_hobj(ce, o, c), hv_member(o, n, f), call_site("client", _, n, _, _, ce, _), + expr_child("client", ce, "ARGUMENT", pos, x), hr_app(x, _), param_decl("client", _, pos, _, f, pf). +hr_included(pf) :- hv_handed(_, _, pf, _). +hr_inc(a, pf, ce, b, "param") :- hv_handed(ce, f, pf, _), param_decl("client", _, pos, _, f, pf), expr_child("client", ce, "ARGUMENT", pos, x), + hr_val(x, a, b), a != pf. +hr_cond_inc(pf, ce) :- hv_handed(ce, _, pf, 1). + +// …the same through a PARAMETER (`function mountPlugin(app, plugin) { plugin.register?.(app) }`): the call names the +// member of whatever object each call of the function passes, so it is bound per call like a pending mount (hv_pm), +// rebinding the app argument too when it is a parameter of the same function; the outermost call is the inclusion +// site. (call, receiver parameter, position of the app argument) +.decl hv_hsite(c0:symbol, c1:symbol, c2:symbol) +hv_hsite(ce, q, xpos) :- call_site("client", k, n, _, q, ce, _), (k = "METHOD_CALL" ; k = "OPTIONAL_CALL"), q != "", + (expr_referenced("client", "PARAMETER", _, q) ; expr_referenced("client", "VARIABLE", v, q), for_binding_iterable(v, _)), + !hr_registrar(n), expr_child("client", ce, "ARGUMENT", xpos, x), hr_app(x, _). +hv_need(q) :- hv_hsite(_, q, _). +// (handed call, inclusion site, app expression, element base, path, filtered) +.decl hv_hpm(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:number) +hv_hpm(ce, ce, x, b, cat(p, cat("|.", n)), c) :- hv_hsite(ce, q, xpos), call_site("client", _, n, _, _, ce, _), expr_child("client", ce, "ARGUMENT", xpos, x), + hv(q, b, p, c), strlen(p) < 120. +hv_todo(b, p) :- hv_hpm(_, _, _, b, p, _). +hv_hpm(ce, s, x, b2, p2, max(c, c2)) :- hv_hpm(ce, s, x, b, p, c), !hv_param(b), hv_res(b, p, b2, p2, c2), (b2 != b ; p2 != p). +hv_hpm(ce, oc, x2, b2, cat(p2, p), max(c, c2)) :- hv_hpm(ce, _, x, b, p, c), param_decl("client", _, pos, _, w, b), + hv_recv_param(x, w, rpos), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a), hv_hneed_arg(a), hv(a, b2, p2, c2), + expr_child("client", oc, "ARGUMENT", rpos, x2), strlen(p2) + strlen(p) < 160. +hv_hpm(ce, s, x, b2, cat(p2, p), max(c, c2)) :- hv_hpm(ce, s, x, b, p, c), param_decl("client", _, pos, _, w, b), + !hv_recv_param(x, w, _), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a), hv_hneed_arg(a), hv(a, b2, p2, c2), + strlen(p2) + strlen(p) < 160. +.decl hv_hneed_arg(c0:symbol) +hv_hneed_arg(a) :- hv_hpm(_, _, _, b, _, _), param_decl("client", _, pos, _, w, b), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, a). +hv_need(a) :- hv_hneed_arg(a). +// the method each call reaches, and its app parameter included into the app the inclusion site passes +.decl hv_hfin(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +hv_hfin(ce, s, x, pf, c) :- hv_hpm(ce, s, x, f, "", c), hv_hsite(ce, _, xpos), param_decl("client", _, xpos, _, f, pf). +hr_included(pf) :- hv_hfin(_, _, _, pf, _). +hr_inc(a, pf, s, b, "param") :- hv_hfin(_, s, x, pf, _), hr_val(x, a, b), a != pf. +hr_cond_inc(pf, s) :- hv_hfin(_, s, _, pf, 1). + +// ── mergePath: how the router joins a prefix and a path ──────────────────── +// Each piece gets a leading `/`; a prefix's trailing `/` is dropped before a non-root +// path and kept before `/`; a `/` path adds nothing; the empty result is `/`. +.decl hr_mreq(c0:symbol, c1:symbol) +.decl hr_merge(c0:symbol, c1:symbol, c2:symbol) +.decl hr_lead(c0:symbol, c1:symbol) +hr_lead(x, x) :- (hr_mreq(x, _) ; hr_mreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) = "/". +hr_lead(x, y) :- (hr_mreq(x, _) ; hr_mreq(_, x)), strlen(x) >= 1, substr(x, 0, 1) != "/", y = cat("/", x). +hr_lead("", "/") :- (hr_mreq("", _) ; hr_mreq(_, "")). +// prefix ends with `/` +hr_merge(a, b, a1) :- hr_mreq(a, b), hr_lead(a, a1), hr_lead(b, "/"), + substr(a1, strlen(a1) - 1, 1) = "/". +hr_merge(a, b, r) :- hr_mreq(a, b), hr_lead(a, a1), hr_lead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) = "/", r = cat(substr(a1, 0, strlen(a1) - 1), b1). +// prefix does not end with `/` +hr_merge(a, b, a1) :- hr_mreq(a, b), hr_lead(a, a1), hr_lead(b, "/"), + substr(a1, strlen(a1) - 1, 1) != "/". +hr_merge(a, b, r) :- hr_mreq(a, b), hr_lead(a, a1), hr_lead(b, b1), b1 != "/", + substr(a1, strlen(a1) - 1, 1) != "/", r = cat(a1, b1). + +// ── position keys: registration order as comparable symbols ──────────────── +// A key is the zero-padded line and column of the registering token (`.get` of +// `app.x().get()`, so a chain orders left to right), or of the call for a function +// call. A list included into another gets the include site's key as a dotted prefix, +// so plain symbol comparison is program order on the flattened list. +.decl hr_need_key(c0:symbol) +hr_need_key(ce) :- hr_reg(ce, _, _). +hr_need_key(oc) :- hr_slot_arg(oc, _, a), hr_app(a, _). +hr_need_key(ce) :- hr_app(ce, ce), !hr_new(ce). +hr_need_key(ce) :- hr_objret_inst(_, ce, _). +.decl hr_key_pn(c0:symbol, c1:symbol) +hr_key_pn(ce, pn) :- hr_need_key(ce), call_callee_expr(_, ce, ne), expr_child("client", ne, "PROPERTY_NAME", _, pn). +.decl hr_has_key_pn(c0:symbol) +hr_has_key_pn(ce) :- hr_key_pn(ce, _). +.decl hr_key_expr(c0:symbol, c1:symbol) +hr_key_expr(ce, pn) :- hr_key_pn(ce, pn). +hr_key_expr(ce, ce) :- hr_need_key(ce), !hr_has_key_pn(ce). +.decl hr_key(c0:symbol, c1:symbol) +hr_key(ce, k) :- hr_key_expr(ce, x), + ts_expression(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, l, c, _, _, _, _, _, _, _, _, _, _, _, x), + strlen(l) <= 7, strlen(c) <= 5, + k = cat(cat(substr("0000000", 0, 7 - strlen(l)), l), cat(":", cat(substr("00000", 0, 5 - strlen(c)), c))). diff --git a/graph/typescript/engine/config-resolution/http-router-routes.dl b/graph/typescript/engine/config-resolution/http-router-routes.dl new file mode 100644 index 000000000..e638361e2 --- /dev/null +++ b/graph/typescript/engine/config-resolution/http-router-routes.dl @@ -0,0 +1,971 @@ +// ============================================================================ +// CONFIG-RESOLUTION · HTTP ROUTER ROUTES (the route table, composed) +// +// From the app lists of http-router-apps.dl to what a served application answers: +// +// http_route(Handler, Verb, FullPath, App, Order) +// http_route_partial(Handler, Verb, KnownPath, App, Reason) +// http_mount(ParentApp, ChildApp, Prefix, Order) +// middleware_applies(Mw, Handler, Verb, FullPath, Position, App) +// middleware_site(Mw, Kind, Callee, Specifier) +// framework_undetermined(Node, What, Reason) +// +// Every function handed to a registration is an `http` entry point: the router calls +// it, nothing in the program does. +// +// ── THE MODEL ─────────────────────────────────────────────────────────────── +// A registering call puts one ENTRY per handler argument on its list, in argument +// order, under (verb, base + path). The last argument is the route's handler, earlier +// ones are middleware for that route only. `use` puts middleware entries for every verb +// (no path means every path). A list nothing includes is a ROOT; flattening a root +// splices every included list at its include site, under the include's prefix, so the +// flattened order key compares as program order. A mounted sub-app contributes only +// what was registered on it before the mount when both are in one module (the router +// copies the sub-app's routes at mount time); a sub-app from another module is fully +// registered by then, because a module's imports run before it. +// +// ── DECLINED, AND SAID SO ─────────────────────────────────────────────────── +// A path that is not a literal, a template of literals or a const comes out of rd_val +// with a `{}` hole: the route goes to http_route_partial with a reason, never into +// http_route. A middleware scope with a literal segment where the route has a +// parameter cannot be decided without a request: no row, framework_undetermined. +// ============================================================================ + +// ── where the handlers start in a registering call ────────────────────────── +// A first argument that is a function (written in place, named, or a value built by a +// call) is a handler, and the call continues the previous path of its chain. +.decl hr_arg0_fnlike(c0:symbol) +hr_arg0_fnlike(ce) :- hr_reg(ce, _, _), expr_child("client", ce, "ARGUMENT", "0", a), + expr_kind("client", k, _, a), (k = "ARROW_FUNCTION" ; k = "FUNCTION_EXPRESSION" ; k = "CALL_EXPRESSION" ; k = "SPREAD_ELEMENT"). +hr_arg0_fnlike(ce) :- hr_reg(ce, _, _), expr_child("client", ce, "ARGUMENT", "0", a), + expr_referenced("client", "METHOD", _, a). +hr_arg0_fnlike(ce) :- hr_reg(ce, _, _), expr_child("client", ce, "ARGUMENT", "0", a), + expr_referenced("client", "IMPORT_BINDING", ih, a), import_binds(ih, "client", "METHOD", _). +hr_arg0_fnlike(ce) :- hr_reg(ce, _, _), expr_child("client", ce, "ARGUMENT", "0", a), + hr_denotes_var(a, v), var_initializer("client", _, i, v), i != "", + expr_kind("client", k, _, i), (k = "ARROW_FUNCTION" ; k = "FUNCTION_EXPRESSION" ; k = "CALL_EXPRESSION"). + +.decl hr_pathed(c0:symbol) +hr_pathed(ce) :- hr_reg(ce, _, cn), (router_verb(cn, _) ; router_use(cn)), + expr_child("client", ce, "ARGUMENT", "0", _), !hr_arg0_fnlike(ce). +.decl hr_pathless(c0:symbol) +hr_pathless(ce) :- hr_reg(ce, _, cn), (router_verb(cn, _) ; router_use(cn)), hr_arg0_fnlike(ce). + +.decl hr_hstart(c0:symbol, c1:number) +hr_hstart(ce, 1) :- hr_pathed(ce). +hr_hstart(ce, 0) :- hr_pathless(ce). +hr_hstart(ce, 2) :- hr_reg(ce, _, cn), router_on(cn). +hr_hstart(ce, 0) :- hr_reg(ce, _, cn), router_fallback(cn). +// `openapi(routeDef, handler, hook?)`: the handler only (the hook validates, it is not a route) +hr_harg(ce, 100, a) :- hr_reg(ce, _, cn), router_openapi(cn), expr_child("client", ce, "ARGUMENT", "1", a). +// the definition's `middleware` (one, or a list) runs before it, in order +.decl hr_def_mw(c0:symbol, c1:symbol) +hr_def_mw(ce, v) :- hr_openapi_def(ce, o), rd_obj_prop(o, k, v), router_def_key(k, "middleware"), !hr_def_mw_overridden(o). +// a caller's definition spread into a wrapper's object that writes its own `middleware` after it: the wrapper's wins +.decl hr_def_mw_overridden(c0:symbol) +hr_def_mw_overridden(o2) :- hr_def_spread(_, o, o2), rd_obj_prop(o, k, _), router_def_key(k, "middleware"). +hr_def_mw(ce, c) :- hr_def_mw(ce, v), expr_kind("client", k, _, v), expr_kind_is_transparent(k), expr_child("client", v, _, _, c). +// …a const holding the list (`const middleware = [authorize(auth), ...rest]; return createRoute({ ...config, middleware })`) +hr_def_mw(ce, i) :- hr_def_mw(ce, v), hr_denotes_var(v, d), var_initializer("client", _, i, d), i != "", expr_kind("client", "ARRAY_LITERAL", _, i). +.decl hr_def_mw_var(c0:symbol) +hr_def_mw_var(v) :- hr_def_mw(_, v), hr_denotes_var(v, d), var_initializer("client", _, i, d), i != "", expr_kind("client", "ARRAY_LITERAL", _, i). +hr_harg(ce, n, el) :- hr_def_mw(ce, arr), expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, epos, el), + to_number(epos) < 90, n = 10 + to_number(epos), !expr_kind("client", "SPREAD_ELEMENT", _, el). +hr_harg(ce, 10, v) :- hr_def_mw(ce, v), !expr_kind("client", "ARRAY_LITERAL", _, v), + expr_kind("client", k, _, v), !expr_kind_is_transparent(k), !hr_def_mw_var(v). +// …a spread in that list of the CALLER's own list (`...(config.middleware ?? [])`, `config` the definition the call +// was handed): that call's argument object's list, in place; a list the argument does not hold adds nothing. Any other +// spread is a list decided at run time (dynamic_middleware_list) +.decl hr_def_mwsp(c0:symbol, c1:number, c2:symbol) +hr_def_mwsp(ce, n, y) :- hr_def_mw(ce, arr), expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, epos, el), + to_number(epos) < 90, n = 10 + to_number(epos), expr_kind("client", "SPREAD_ELEMENT", _, el), expr_child("client", el, _, _, y). +hr_def_mwsp(ce, n, c) :- hr_def_mwsp(ce, n, y), expr_kind("client", k, _, y), expr_kind_is_transparent(k), expr_child("client", y, _, _, c). +hr_def_mwsp(ce, n, c) :- hr_def_mwsp(ce, n, y), expr_kind("client", "BINARY_EXPRESSION", _, y), (expr_operator("client", "??", y) ; expr_operator("client", "||", y)), + expr_child("client", y, "LEFT_OPERAND", _, c). +// (registration, ordinal, the caller's argument object, the key read) +.decl hr_def_mwsp_key(c0:symbol, c1:number, c2:symbol, c3:symbol) +hr_def_mwsp_key(ce, n, o2, key) :- hr_def_mwsp(ce, n, z), property_access_name(z, key), expr_child("client", z, "RECEIVER", _, q), + hr_def_param(q, p), param_decl("client", _, pos, _, w, p), expr_child("client", ce, "ARGUMENT", "0", x0), hr_def_callat(x0, x), + hr_def_call(x, w), expr_child("client", x, "ARGUMENT", pos, a), hr_def_obj(a, o2). +.decl hr_def_callat(c0:symbol, c1:symbol) +hr_def_callat(x, x) :- hr_def_call(x, _). +hr_def_callat(r, x) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hr_def_callat(i, x). +hr_def_callat(e, x) :- hr_on(), expr_kind("client", k, _, e), expr_kind_is_transparent(k), expr_child("client", e, _, _, c), hr_def_callat(c, x). +.decl hr_def_mwsp_val(c0:symbol, c1:number, c2:symbol) +hr_def_mwsp_val(ce, n, v) :- hr_def_mwsp_key(ce, n, o2, key), rd_obj_prop(o2, key, v). +hr_def_mwsp_val(ce, n, c) :- hr_def_mwsp_val(ce, n, v), expr_kind("client", k, _, v), expr_kind_is_transparent(k), expr_child("client", v, _, _, c). +hr_def_mwsp_val(ce, n, i) :- hr_def_mwsp_val(ce, n, v), hr_denotes_var(v, d), var_initializer("client", _, i, d), i != "", + expr_kind("client", "ARRAY_LITERAL", _, i). +hr_harg(ce, n + to_number(j), el) :- hr_def_mwsp_val(ce, n, arr), expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, j, el), + !expr_kind("client", "SPREAD_ELEMENT", _, el), n + to_number(j) < 90. +.decl hr_def_mwsp_known(c0:symbol, c1:number) +hr_def_mwsp_known(ce, n) :- hr_def_mwsp_key(ce, n, _, _). +framework_undetermined(m, "middleware", "dynamic_middleware_list") :- hr_def_mwsp(ce, n, _), !hr_def_mwsp_known(ce, n), + expr_enclosing_method(ce, m). + +// ── the handler arguments, in order: (call, ordinal, expression) ──────────── +// ordinal = argument position * 100 + element index, so a spread `...[a, b]` keeps +// its elements in place. +.decl hr_harg(c0:symbol, c1:number, c2:symbol) +hr_harg(ce, n, a) :- hr_hstart(ce, s), expr_child("client", ce, "ARGUMENT", pos, a), + n = to_number(pos) * 100, to_number(pos) >= s, + !expr_kind("client", "SPREAD_ELEMENT", _, a). +// `mount(prefix, fetch, options?)`: the one foreign handler +hr_harg(ce, 100, a) :- hr_reg(ce, _, cn), router_mount_foreign(cn), expr_child("client", ce, "ARGUMENT", "1", a). +// a spread of a const array literal, or of a call that hands its arguments back as +// handlers (router_handler_spread) +.decl hr_spread(c0:symbol, c1:number, c2:symbol) +hr_spread(ce, p, x) :- hr_hstart(ce, s), expr_child("client", ce, "ARGUMENT", pos, a), + p = to_number(pos), p >= s, expr_kind("client", "SPREAD_ELEMENT", _, a), + expr_child("client", a, _, _, x). +.decl hr_spread_arr(c0:symbol, c1:number, c2:symbol) +hr_spread_arr(ce, p, arr) :- hr_spread(ce, p, x), expr_kind("client", "ARRAY_LITERAL", _, x), arr = x. +hr_spread_arr(ce, p, arr) :- hr_spread(ce, p, x), hr_denotes_var(x, v), var_initializer("client", _, arr, v), + expr_kind("client", "ARRAY_LITERAL", _, arr). +.decl hr_spread_ret(c0:symbol, c1:number, c2:symbol) +hr_spread_ret(ce, p, x) :- hr_spread(ce, p, x), call_site("client", _, _, _, _, x, _). +hr_spread_ret(ce, p, i) :- hr_spread(ce, p, x), hr_denotes_var(x, v), var_initializer("client", _, i, v), + call_site("client", _, _, _, _, i, _). +.decl hr_spread_val(c0:symbol, c1:number, c2:symbol) +hr_spread_val(ce, p, e) :- hr_spread_ret(ce, p, x), hr_call_of(x, f), hr_ret_expr(f, e). +hr_spread_arr(ce, p, e) :- hr_spread_val(ce, p, e), expr_kind("client", "ARRAY_LITERAL", _, e). +hr_spread_arr(ce, p, arr) :- hr_spread_val(ce, p, e), hr_denotes_var(e, v), var_initializer("client", _, arr, v), + expr_kind("client", "ARRAY_LITERAL", _, arr). +hr_harg(ce, n, el) :- hr_spread_arr(ce, p, arr), expr_child("client", arr, _, epos, el), + n = p * 100 + to_number(epos), to_number(epos) < 100. +.decl hr_spread_call(c0:symbol, c1:number, c2:symbol) +hr_spread_call(ce, p, x) :- hr_spread(ce, p, x), call_site("client", _, sn, _, _, x, _), router_handler_spread(sn). +hr_spread_call(ce, p, i) :- hr_spread(ce, p, x), hr_denotes_var(x, v), var_initializer("client", _, i, v), + call_site("client", _, sn, _, _, i, _), router_handler_spread(sn). +// …through a factory method read off into a const (`const mkHandlers = factory.createHandlers`) +hr_spread_call(ce, p, x) :- hr_spread(ce, p, x), hr_detached(x, n, _), router_handler_spread(n). +hr_spread_call(ce, p, i) :- hr_spread(ce, p, x), hr_denotes_var(x, v), var_initializer("client", _, i, v), + hr_detached(i, n, _), router_handler_spread(n). +hr_harg(ce, n, el) :- hr_spread_call(ce, p, x), expr_child("client", x, "ARGUMENT", epos, el), + n = p * 100 + to_number(epos), to_number(epos) < 100. +.decl hr_spread_known(c0:symbol, c1:number) +hr_spread_known(ce, p) :- hr_spread_arr(ce, p, _). +hr_spread_known(ce, p) :- hr_spread_call(ce, p, _). +framework_undetermined(m, "middleware", "dynamic_middleware_list") :- hr_spread(ce, p, _), + !hr_spread_known(ce, p), expr_enclosing_method(ce, m). + +.decl hr_last(c0:symbol, c1:number) +hr_last(ce, n) :- hr_harg(ce, _, _), n = max x : { hr_harg(ce, x, _) }. + +// ── the function each handler argument is ─────────────────────────────────── +// Written in place, named, a const holding one, an import of one, what a project +// function returns when called (a middleware factory), or the argument of a knob +// wrapper (`createMiddleware(fn)`). +.decl hr_farg(c0:symbol) +hr_farg(a) :- hr_harg(_, _, a). +hr_farg(i) :- hr_farg(a), hr_denotes_var(a, v), var_initializer("client", _, i, v), i != "". +hr_farg(e) :- hr_farg(a), hr_call_of(a, f), hr_ret_expr(f, e). +hr_farg(x) :- hr_farg(a), hr_wrapper_call(a), expr_child("client", a, "ARGUMENT", "0", x). +hr_farg(c) :- hr_farg(a), expr_kind("client", k, _, a), expr_kind_is_transparent(k), expr_child("client", a, _, _, c). +// `Object.assign(fn, { scope })` returns its first argument, the function, with properties added +.decl hr_assign_call(c0:symbol) +hr_assign_call(a) :- hr_on(), call_site("client", "METHOD_CALL", "assign", _, r, a, _), r != "", !hr_call_of(a, _). +hr_farg(x) :- hr_farg(a), hr_assign_call(a), expr_child("client", a, "ARGUMENT", "0", x). +// a property of an object literal a handler argument reads (`guard.middleware` where `guard = createGuard(..)` returns +// `{ middleware, inFlight }`, or `const { middleware } = createGuard(..)`): that property's own value, never another's +.decl hr_fobj_need(c0:symbol) +hr_fobj_need(q) :- hr_farg(a), property_access_name(a, _), expr_child("client", a, "RECEIVER", _, q). +hr_fobj_need(i) :- hr_farg(a), expr_referenced("client", "VARIABLE", d, a), var_binding("client", _, "PROPERTY", _, i, d), i != "". +hr_fobj_need(i) :- hr_fobj_need(x), hr_denotes_var(x, v), var_initializer("client", _, i, v), i != "". +hr_fobj_need(e) :- hr_fobj_need(x), hr_call_of(x, f), hr_ret_expr(f, e). +hr_fobj_need(c) :- hr_fobj_need(x), expr_kind("client", k, _, x), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"), + expr_child("client", x, _, _, c). +// (expression, the object literal it evaluates to) +.decl hr_fobj(c0:symbol, c1:symbol) +hr_fobj(x, x) :- hr_fobj_need(x), expr_kind("client", "OBJECT_LITERAL", _, x). +hr_fobj(x, o) :- hr_fobj_need(x), hr_denotes_var(x, v), var_initializer("client", _, i, v), i != "", hr_fobj(i, o). +hr_fobj(x, o) :- hr_fobj_need(x), hr_call_of(x, f), hr_ret_expr(f, e), hr_fobj(e, o). +hr_fobj(x, o) :- hr_fobj_need(x), expr_kind("client", k, _, x), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"), + expr_child("client", x, _, _, c), hr_fobj(c, o). +.decl hr_fprop(c0:symbol, c1:symbol) +hr_fprop(a, v) :- hr_farg(a), property_access_name(a, n), expr_child("client", a, "RECEIVER", _, q), hr_fobj(q, o), rd_obj_prop(o, n, v). +hr_fprop(a, v) :- hr_farg(a), expr_referenced("client", "VARIABLE", d, a), var_binding("client", _, "PROPERTY", src, i, d), i != "", + hr_fobj(i, o), rd_obj_prop(o, src, v). +hr_farg(v) :- hr_fprop(_, v). +.decl hr_wrapper_call(c0:symbol) +hr_wrapper_call(a) :- call_site("client", "METHOD_CALL", cn, _, r, a, _), router_factory_mw(cn), hr_factory_val(r, _). +hr_wrapper_call(a) :- hr_detached(a, n, _), router_factory_mw(n). +hr_wrapper_call(a) :- hr_on(), call_site("client", "FUNCTION_CALL", _, _, _, a, _), + expr_child("client", a, "METHOD_NAME", _, f), expr_referenced("client", "IMPORT_BINDING", ih, f), + import_binding("client", _, _, orig, _, ih), hr_import_spec(ih, spec), router_mw_wrapper(spec, orig). +.decl hr_fn(c0:symbol, c1:symbol) +hr_fn(a, m) :- hr_farg(a), expr_anon_decl("client", m, a). +hr_fn(a, m) :- hr_farg(a), expr_referenced("client", "METHOD", m, a). +hr_fn(a, m) :- hr_farg(a), expr_referenced("client", "IMPORT_BINDING", ih, a), import_binds(ih, "client", "METHOD", m). +// a member of a namespace import (`import * as handlers …; handlers.login`): the module's export +.decl hr_ns_member(c0:symbol, c1:symbol, c2:symbol) +hr_ns_member(a, k, ent) :- hr_farg(a), property_access_name(a, n), expr_child("client", a, "RECEIVER", _, r), + expr_referenced("client", "IMPORT_BINDING", ih, r), import_binds_namespace(ih, "client", mod), + module_export_any("client", mod, n, k, ent). +hr_fn(a, m) :- hr_ns_member(a, "METHOD", m). +hr_farg(i) :- hr_ns_member(_, "VARIABLE", v), var_initializer("client", _, i, v), i != "". +hr_fn(a, m) :- hr_ns_member(a, "VARIABLE", v), var_initializer("client", _, i, v), i != "", hr_fn(i, m). +hr_fn(a, m) :- hr_farg(a), hr_denotes_var(a, v), var_initializer("client", _, i, v), hr_fn(i, m). +// the value the function RETURNS, never a function written inside it (the option callbacks of +// `return rateLimiter({ keyGenerator: (c) => … })` are not middleware, SPEC ruling R10) +hr_fn(a, m) :- hr_farg(a), hr_call_of(a, f), hr_ret_expr(f, e), hr_fn(e, m). +hr_fn(a, m) :- hr_farg(a), hr_wrapper_call(a), expr_child("client", a, "ARGUMENT", "0", x), hr_fn(x, m). +hr_fn(a, m) :- hr_farg(a), hr_assign_call(a), expr_child("client", a, "ARGUMENT", "0", x), hr_fn(x, m). +hr_fn(a, m) :- hr_fprop(a, v), hr_fn(v, m). +hr_fn(a, m) :- hr_farg(a), expr_kind("client", k, _, a), expr_kind_is_transparent(k), + expr_child("client", a, _, _, c), hr_fn(c, m). + +.decl hr_node_fn(c0:symbol, c1:number, c2:symbol) +hr_node_fn(ce, n, m) :- hr_harg(ce, n, a), hr_fn(a, m), method_prov(m, "client"). +// the node a ROUTE's handler is: the project function, or a library call's result keyed at the call +// (`serveStatic({...})`), never dropped (SPEC ruling R5) +.decl hr_route_node(c0:symbol, c1:number, c2:symbol) +hr_route_node(ce, n, m) :- hr_node_fn(ce, n, m). +hr_route_node(ce, n, a) :- hr_harg(ce, n, a), !hr_has_fn(ce, n), call_site("client", _, _, _, _, a, _), !hr_has_libret(a). +hr_route_node(ce, n, x) :- hr_harg(ce, n, a), !hr_has_fn(ce, n), hr_libret(a, x). +.decl hr_has_fn(c0:symbol, c1:number) +hr_has_fn(ce, n) :- hr_node_fn(ce, n, _). +// a project function that returns a library call's result (`limiter(5)` returning +// `rateLimiter({...})`): the middleware is that library call, keyed where it is written +.decl hr_libret(c0:symbol, c1:symbol) +hr_libret(a, x) :- hr_farg(a), hr_call_of(a, f), hr_ret_expr(f, x), call_site("client", _, _, _, _, x, _), + !hr_call_of(x, _), !hr_wrapper_call(x), !hr_assign_call(x). +// …also through a const holding that call (`const a = limiter(1); app.use(...[a, b])`) +hr_libret(a, x) :- hr_farg(a), hr_denotes_var(a, v), var_initializer("client", _, i, v), i != "", hr_libret(i, x). +// …or a const holding a library call itself (SPEC ruling R10; R11's `value` is for a non-call value only) +hr_libret(a, i) :- hr_farg(a), hr_denotes_var(a, v), var_initializer("client", _, i, v), i != "", + call_site("client", _, _, _, _, i, _), !hr_call_of(i, _), !hr_wrapper_call(i), !hr_any_fn(a). +.decl hr_any_fn(c0:symbol) +hr_any_fn(a) :- hr_fn(a, _). +// the node a handler argument stands for: the project function, else the library call it +// returns, else the argument +.decl hr_node(c0:symbol, c1:number, c2:symbol) +hr_node(ce, n, m) :- hr_node_fn(ce, n, m). +hr_node(ce, n, x) :- hr_harg(ce, n, a), hr_libret(a, x). +hr_node(ce, n, a) :- hr_harg(ce, n, a), !hr_has_fn(ce, n), !hr_has_libret(a). +.decl hr_has_libret(c0:symbol) +hr_has_libret(a) :- hr_libret(a, _). + +// a call of a knob function imported from its module: (call, which knob relation, name) +.decl hr_knob_call(c0:symbol, c1:symbol, c2:symbol) +hr_knob_call(a, spec, orig) :- hr_on(), call_site("client", "FUNCTION_CALL", _, _, _, a, _), + expr_child("client", a, "METHOD_NAME", _, f), expr_referenced("client", "IMPORT_BINDING", ih, f), + import_binding("client", _, _, orig, _, ih), hr_import_spec(ih, spec). +// the functions a combinator runs: `every(a, b)`, `some(a, b)`, `except(paths, mw)` +.decl hr_comb_arg(c0:symbol) +hr_comb_arg(x) :- hr_harg(_, _, a), hr_knob_call(a, spec, n), router_mw_combinator(spec, n), + expr_child("client", a, "ARGUMENT", _, x). +hr_comb_arg(x) :- hr_harg(_, _, a), hr_knob_call(a, spec, n), router_mw_except(spec, n), + expr_child("client", a, "ARGUMENT", "1", x). +hr_farg(x) :- hr_comb_arg(x). +entry_point(m, "http") :- hr_comb_arg(x), hr_fn(x, m), method_prov(m, "client"). +// `except(path | [paths], mw)`: not on a route whose full path is one of them +.decl hr_except_path(c0:symbol, c1:number, c2:symbol) +hr_except_path(ce, n, v) :- hr_harg(ce, n, a), hr_knob_call(a, spec, nm), router_mw_except(spec, nm), + expr_child("client", a, "ARGUMENT", "0", x), rd_val(x, v). +hr_except_path(ce, n, v) :- hr_harg(ce, n, a), hr_knob_call(a, spec, nm), router_mw_except(spec, nm), + expr_child("client", a, "ARGUMENT", "0", arr), expr_kind("client", "ARRAY_LITERAL", _, arr), + expr_child("client", arr, _, _, x), rd_val(x, v). +rd_demand(x) :- hr_harg(_, _, a), hr_knob_call(a, spec, nm), router_mw_except(spec, nm), + expr_child("client", a, "ARGUMENT", "0", x). +rd_demand(x) :- hr_harg(_, _, a), hr_knob_call(a, spec, nm), router_mw_except(spec, nm), + expr_child("client", a, "ARGUMENT", "0", arr), expr_kind("client", "ARRAY_LITERAL", _, arr), + expr_child("client", arr, _, _, x). +.decl hr_excepted(c0:symbol, c1:number, c2:symbol) +hr_excepted(ce, n, p) :- hr_except_path(ce, n, p). +// …an exclusion that is not written as literal paths (a property read, a predicate, a value chosen at run time): +// which routes it skips is not known here (SPEC 3.1 dynamic_except), declared on the middleware it wraps, or on the +// function that builds the call when that middleware is not a function the program names +.decl hr_except_call(c0:symbol, c1:symbol) +hr_except_call(x, a0) :- hr_knob_call(x, spec, nm), router_mw_except(spec, nm), expr_child("client", x, "ARGUMENT", "0", a0). +.decl hr_lit_paths(c0:symbol) +hr_lit_paths(a0) :- hr_except_call(_, a0), expr_kind("client", "LITERAL", _, a0). +hr_lit_paths(a0) :- hr_except_call(_, a0), expr_kind("client", "ARRAY_LITERAL", _, a0), + !hr_nonlit_elem(a0). +.decl hr_nonlit_elem(c0:symbol) +hr_nonlit_elem(a0) :- hr_except_call(_, a0), expr_kind("client", "ARRAY_LITERAL", _, a0), expr_child("client", a0, _, _, y), + !expr_kind("client", "LITERAL", _, y). +.decl hr_dyn_except(c0:symbol) +hr_dyn_except(x) :- hr_except_call(x, a0), !hr_lit_paths(a0). +.decl hr_dyn_except_named(c0:symbol) +hr_dyn_except_named(x) :- hr_dyn_except(x), expr_child("client", x, "ARGUMENT", "1", x1), hr_fn(x1, _). +framework_undetermined(m, "middleware_scope", "dynamic_except") :- hr_dyn_except(x), expr_child("client", x, "ARGUMENT", "1", x1), hr_fn(x1, m). +framework_undetermined(m, "middleware_scope", "dynamic_except") :- hr_dyn_except(x), !hr_dyn_except_named(x), expr_enclosing_method(x, m). + +// a served default export `{ fetch: app.fetch, scheduled, queue() {} }`: the platform +// calls the other members +.decl hr_served_obj(c0:symbol) +hr_served_obj(o) :- export_decl(_, "default", _, "DEFAULT_EXPRESSION", mod, h), export_expression("client", o, h), + expr_kind("client", "OBJECT_LITERAL", _, o), rd_obj_prop(o, key, v), router_served_fetch(key), + property_access_name(v, key), expr_child("client", v, "RECEIVER", _, r), hr_app(r, _), mod = mod. +// `{ fetch(req, env, ctx) { return app.fetch(req, env, ctx) } }`: a fetch member that forwards to an +// app's fetch is the same served shape (SPEC ruling R4); the fetch member is called by the platform too +hr_served_obj(o) :- export_decl(_, "default", _, "DEFAULT_EXPRESSION", _, h), export_expression("client", o, h), + expr_kind("client", "OBJECT_LITERAL", _, o), objlit_member_fn(o, key, fm), router_served_fetch(key), + call_site("client", "METHOD_CALL", key, _, r, ce, _), hr_app(r, _), expr_enclosing_method(ce, fm). + +// http_served_by(App, Site, How) — where a root app is handed to whatever serves it: the default export +// `{ fetch: app.fetch }` or one whose fetch forwards to the app (default_export_fetch), `export default app` +// (default_export), its fetch handed to a call such as `serve({ fetch: app.fetch })` (fetch_handed), or a request +// sent to it in place, a test (request). What "how does a request reach the app" is answered with. +http_served_by(ai, o, "default_export_fetch") :- hr_served_obj(o), rd_obj_prop(o, key, v), router_served_fetch(key), + property_access_name(v, key), expr_child("client", v, "RECEIVER", _, r), hr_app(r, a), hr_root(a), hr_app_id(a, ai). +http_served_by(ai, o, "default_export_fetch") :- hr_served_obj(o), objlit_member_fn(o, key, fm), router_served_fetch(key), + call_site("client", "METHOD_CALL", key, _, r, ce, _), expr_enclosing_method(ce, fm), hr_app(r, a), hr_root(a), hr_app_id(a, ai). +http_served_by(ai, x, "default_export") :- export_decl(_, "default", _, _, _, h), export_expression("client", x, h), hr_app(x, a), + hr_root(a), !hr_partial_root(a), hr_app_id(a, ai). +http_served_by(ai, ce, "fetch_handed") :- property_access_name(v, key), router_served_fetch(key), expr_child("client", v, "RECEIVER", _, r), + hr_app(r, a), hr_root(a), hr_app_id(a, ai), hr_handed_in(v, ce), !hr_served_obj_val(v). +.decl hr_handed_in(c0:symbol, c1:symbol) +hr_handed_in(v, ce) :- hr_on(), expr_child("client", ce, "ARGUMENT", _, v), call_site("client", _, _, _, _, ce, _). +hr_handed_in(v, ce) :- hr_on(), expr_child("client", o, "OBJECT_PROPERTY_VALUE", _, v), expr_child("client", ce, "ARGUMENT", _, o), + call_site("client", _, _, _, _, ce, _). +.decl hr_served_obj_val(c0:symbol) +hr_served_obj_val(v) :- hr_served_obj(o), rd_obj_prop(o, _, v). + +entry_point(m, "http") :- hr_served_obj(o), rd_obj_prop(o, key, v), !router_served_fetch(key), + expr_callable(v, m), method_prov(m, "client"). +entry_point(m, "http") :- hr_served_obj(o), objlit_member_fn(o, k, m), !router_served_fetch(k). + +// ── http: every function a router calls ───────────────────────────────────── +// Handlers, per-route and app-level middleware, notFound/onError, a mounted foreign +// handler. Receiver-checked, unlike entry-points.dl's verb-and-path rule, which stays. +entry_point(m, "http") :- hr_node_fn(_, _, m). + +// ── the local path of each registering call ───────────────────────────────── +.decl hr_local(c0:symbol, c1:symbol) +hr_local(ce, lp) :- hr_pathed(ce), expr_child("client", ce, "ARGUMENT", "0", p), rd_val(p, lp). +hr_local(ce, "*") :- hr_pathless(ce), hr_reg(ce, _, cn), router_use(cn). +// a path-less verb continues the path of the registration it is chained on; on a +// fresh app value that is `/`; on anything else it is not known here +.decl hr_cont_src(c0:symbol) +hr_cont_src(r) :- hr_reg(r, _, rn), (router_verb(rn, _) ; router_use(rn)). +hr_cont_src(r) :- hr_reg(r, _, rn), router_on(rn). +// after `on(verbs, path, h)` a path-less verb continues that path (each of a path list: the +// router keeps the last, which this does not single out) +hr_local(ce, lp) :- hr_pathless(ce), hr_reg(ce, _, cn), router_verb(cn, _), + call_site("client", _, _, _, r, ce, _), hr_reg(r, _, rn), router_on(rn), hr_on_piece(r, "1", lp). +hr_cont_src(r) :- hr_new(r). +hr_cont_src(r) :- hr_on(), call_site("client", "METHOD_CALL", cn, _, _, r, _), router_base_path(cn). +hr_local(ce, lp) :- hr_pathless(ce), hr_reg(ce, _, cn), router_verb(cn, _), + call_site("client", _, _, _, r, ce, _), hr_local(r, lp), hr_reg(r, _, rn), (router_verb(rn, _) ; router_use(rn)). +hr_local(ce, "/") :- hr_pathless(ce), hr_reg(ce, _, cn), router_verb(cn, _), + call_site("client", _, _, _, r, ce, _), (hr_new(r) ; call_site("client", "METHOD_CALL", bn, _, _, r, _), router_base_path(bn)). +// on a variable: the router keeps one current path per app object, so it is the path +// of the previous registration on that app in this module; with none, `/` +.decl hr_pathless_var(c0:symbol) +hr_pathless_var(ce) :- hr_pathless(ce), hr_reg(ce, _, cn), router_verb(cn, _), + call_site("client", _, _, _, r, ce, _), !hr_cont_src(r). +.decl hr_keyn(c0:symbol, c1:number) +hr_keyn(ce, n) :- hr_key_expr(ce, x), + ts_expression(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, l, c, _, _, _, _, _, _, _, _, _, _, _, x), + to_number(l) < 200000, to_number(c) < 10000, n = to_number(l) * 10000 + to_number(c). +.decl hr_prev_cand(c0:symbol, c1:symbol, c2:number) +hr_prev_cand(ce, r2, n2) :- hr_pathless_var(ce), hr_reg(ce, a, _), hr_keyn(ce, n), expr_module("client", m, ce), + hr_reg(r2, a, rn), (router_verb(rn, _) ; router_use(rn)), r2 != ce, expr_module("client", m, r2), + hr_keyn(r2, n2), n2 < n. +.decl hr_prev(c0:symbol, c1:symbol) +hr_prev(ce, r2) :- hr_prev_cand(ce, _, _), b = max x : { hr_prev_cand(ce, _, x) }, hr_prev_cand(ce, r2, b). +.decl hr_has_prev(c0:symbol) +hr_has_prev(ce) :- hr_prev(ce, _). +hr_local(ce, lp) :- hr_prev(ce, r2), hr_local(r2, lp). +hr_local(ce, "/") :- hr_pathless_var(ce), !hr_has_prev(ce). +// `mount(prefix, h)` serves prefix/* +hr_local(ce, lp) :- hr_reg(ce, _, cn), router_mount_foreign(cn), expr_child("client", ce, "ARGUMENT", "0", p), + rd_val(p, pv), hr_merge(pv, "*", lp). +hr_mreq(pv, "*") :- hr_reg(ce, _, cn), router_mount_foreign(cn), expr_child("client", ce, "ARGUMENT", "0", p), rd_val(p, pv). + +// `on(verb | [verbs], path | [paths], ...)`: a verb is written in either case +.decl hr_on_piece(c0:symbol, c1:symbol, c2:symbol) +hr_on_piece(ce, pos, v) :- hr_reg(ce, _, cn), router_on(cn), expr_child("client", ce, "ARGUMENT", pos, x), + (pos = "0" ; pos = "1"), !expr_kind("client", "ARRAY_LITERAL", _, x), rd_val(x, v). +hr_on_piece(ce, pos, v) :- hr_reg(ce, _, cn), router_on(cn), expr_child("client", ce, "ARGUMENT", pos, x), + (pos = "0" ; pos = "1"), expr_kind("client", "ARRAY_LITERAL", _, x), expr_child("client", x, _, _, el), rd_val(el, v). +.decl hr_on_verb(c0:symbol, c1:symbol) +hr_on_verb(ce, vv) :- hr_on_piece(ce, "0", w), ts_http_verb_name(w, vv). +hr_on_verb(ce, w) :- hr_on_piece(ce, "0", w), !ts_http_verb_name(w, _). + +// ── the entries of a list: (list, key, kind, verb, path, call, ordinal) ───── +.decl hr_entry(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:number) +.decl hr_entry_base(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +// (call, list, kind, verb, local path, base) +hr_entry_base(ce, a, "route", vv, lp, b) :- hr_reg(ce, a, cn), router_verb(cn, vv), hr_local(ce, lp), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b). +hr_entry_base(ce, a, "mw", "ANY", lp, b) :- hr_reg(ce, a, cn), router_use(cn), hr_local(ce, lp), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b). +hr_entry_base(ce, a, "route", "ANY", lp, b) :- hr_reg(ce, a, cn), router_mount_foreign(cn), hr_local(ce, lp), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b). +hr_entry_base(ce, a, "route", vv, lp, b) :- hr_reg(ce, a, _), hr_on_verb(ce, vv), hr_on_piece(ce, "1", lp), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b). +hr_entry_base(ce, a, "route", vv, lp, b) :- hr_openapi_def(ce, o), hr_reg(ce, a, _), + rd_obj_prop(o, mk, mv), router_def_key(mk, "method"), hr_def_v(ce, mv, w), ts_http_verb_name(w, vv), + rd_obj_prop(o, pk, pv), router_def_key(pk, "path"), hr_def_v(ce, pv, raw), hr_brace_path(raw, lp), + call_site("client", _, _, _, r, ce, _), hr_val(r, a, b). +// an `openapi(def, h)` whose definition gives no literal method and path (a definition built where it cannot be read): +// the route exists, its verb and path are not known here; declared, never dropped (SPEC 3.7, dynamic_route_path) +.decl hr_openapi_routed(c0:symbol) +hr_openapi_routed(ce) :- hr_openapi_def(ce, _), hr_entry_base(ce, _, "route", _, _, _). +.decl hr_openapi_unread(c0:symbol) +hr_openapi_unread(ce) :- hr_reg(ce, _, cn), router_openapi(cn), !hr_openapi_routed(ce). +remote_undetermined(h, "http", "dynamic_route_path") :- hr_openapi_unread(ce), hr_node_fn(ce, 100, h). +remote_undetermined(m, "http", "dynamic_route_path") :- hr_openapi_unread(ce), !hr_has_fn(ce, 100), expr_enclosing_method(ce, m). +// an OpenAPI path writes a parameter `{id}`; the router registers `:id` +.decl hr_brace_raw(c0:symbol) +hr_brace_raw(raw) :- hr_openapi_def(ce, o), rd_obj_prop(o, pk, pv), router_def_key(pk, "path"), hr_def_v(ce, pv, raw). +// a definition's method or path written as a PARAMETER of a wrapper on the registration's call chain +// (`analyticsRoute(id, summary, '/overview', schema)` building `{ method: 'get', path }`): that call's argument, per +// registration (hr_def_chain: the wrapper calls from the registration's argument inward) +.decl hr_def_chain(c0:symbol, c1:symbol) +hr_def_chain(ce, x) :- hr_reg(ce, _, cn), router_openapi(cn), expr_child("client", ce, "ARGUMENT", "0", x0), hr_def_callat(x0, x). +hr_def_chain(ce, x2) :- hr_def_chain(ce, x), hr_def_call(x, w), hr_ret_expr(w, e), hr_def_callat(e, x2). +.decl hr_def_parg(c0:symbol, c1:symbol, c2:symbol) +hr_def_parg(ce, pv, a) :- hr_openapi_def(ce, o), rd_obj_prop(o, k, pv), (router_def_key(k, "method") ; router_def_key(k, "path")), + hr_def_param(pv, p), param_decl("client", _, pos, _, w, p), hr_def_chain(ce, x), hr_def_call(x, w), + expr_child("client", x, "ARGUMENT", pos, a). +rd_demand(a) :- hr_def_parg(_, _, a). +.decl hr_def_pargd(c0:symbol, c1:symbol) +hr_def_pargd(ce, pv) :- hr_def_parg(ce, pv, _). +.decl hr_def_v(c0:symbol, c1:symbol, c2:symbol) +hr_def_v(ce, pv, raw) :- hr_openapi_def(ce, o), rd_obj_prop(o, k, pv), (router_def_key(k, "method") ; router_def_key(k, "path")), + !hr_def_pargd(ce, pv), rd_val(pv, raw). +hr_def_v(ce, pv, raw) :- hr_def_parg(ce, pv, a), rd_val(a, raw). +.decl hr_brace_step(c0:symbol, c1:number, c2:symbol) +hr_brace_step(raw, 0, "") :- hr_brace_raw(raw). +// …but a `{}` is a piece decided at run time (rd_val's hole), never a parameter named nothing: kept, so the route is partial +hr_brace_step(raw, i + 2, cat(acc, "{}")) :- hr_brace_step(raw, i, acc), i + 1 < strlen(raw), substr(raw, i, 1) = "{", substr(raw, i + 1, 1) = "}". +hr_brace_step(raw, i + 1, cat(acc, ":")) :- hr_brace_step(raw, i, acc), i + 1 < strlen(raw), substr(raw, i, 1) = "{", substr(raw, i + 1, 1) != "}". +hr_brace_step(raw, i + 1, acc) :- hr_brace_step(raw, i, acc), i < strlen(raw), substr(raw, i, 1) = "}". +hr_brace_step(raw, i + 1, cat(acc, "{")) :- hr_brace_step(raw, i, acc), i + 1 = strlen(raw), substr(raw, i, 1) = "{". +hr_brace_step(raw, i + 1, cat(acc, ch)) :- hr_brace_step(raw, i, acc), i < strlen(raw), ch = substr(raw, i, 1), + ch != "{", ch != "}". +.decl hr_brace_path(c0:symbol, c1:symbol) +hr_brace_path(raw, p) :- hr_brace_step(raw, strlen(raw), p). +hr_mreq(b, lp) :- hr_entry_base(_, _, _, _, lp, b). +hr_entry(a, k2, kind, vv, p, ce, n) :- hr_entry_base(ce, a, kind, vv, lp, b), hr_merge(b, lp, p), + hr_harg(ce, n, _), hr_key(ce, k), s = to_string(n), + k2 = cat(k, cat(",", cat(substr("00000", 0, 5 - strlen(s)), s))). +// the path as the call itself wrote it, without any base (for the partial reason: a hole in the +// call's own path is a dynamic route path, one anywhere else a dynamic prefix) +.decl hr_entry_own(c0:symbol, c1:symbol) +hr_entry_own(ce, lp) :- hr_entry_base(ce, _, _, _, lp, _). + +// ── flattening a root ─────────────────────────────────────────────────────── +// (root, list, prefix, key prefix, cut key, cut module): a mount in the sub-app's own +// module copies only the entries registered before it. +.decl hr_flat(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +hr_flat(r, r, "/", "", "", "") :- hr_root(r). +.decl hr_cutoff(c0:symbol, c1:symbol, c2:symbol) +hr_cutoff(site, k, m) :- hr_inc(_, sub, site, _, "mount"), hr_key(site, k), expr_module("client", m, site), !hr_inline_sub(site, sub). +// an app built INSIDE the mount's argument (`app.route('/x', new X().get('/', h))`): its chain runs before the mount +// does, though it is written after the mount's name, so nothing it registers there is cut off +hr_cutoff(site, "", "") :- hr_inc(_, sub, site, _, "mount"), hr_inline_sub(site, sub). +.decl hr_inl_desc(c0:symbol, c1:symbol) +hr_inl_desc(site, sx) :- hr_on(), call_site("client", "METHOD_CALL", cn, _, _, site, _), router_mount_app(cn), expr_child("client", site, "ARGUMENT", "1", sx). +hr_inl_desc(site, y) :- hr_inl_desc(site, z), expr_child("client", z, k, _, y), (k = "RECEIVER" ; k = "METHOD_NAME" ; k = "ROOT"). +.decl hr_inline_sub(c0:symbol, c1:symbol) +hr_inline_sub(site, sub) :- hr_inl_desc(site, sub). +hr_cutoff(site, "", "") :- hr_inc(_, _, site, _, kind), kind != "mount". +hr_flat(r, s, np, nk, cut, cm) :- hr_flat(r, a, p, kp, _, _), hr_inc(a, s, site, pre, kd), kd != "mount_each", + hr_merge(p, pre, np), hr_key(site, k), nk = cat(kp, cat(k, ".")), strlen(nk) < 160, + hr_cutoff(site, cut, cm). +// the candidates one loop mount takes (hr_each_cand) sit at the mount, in the order of the elements: `~` +hr_flat(r, s, np, nk, "", "") :- hr_flat(r, a, p, kp, _, _), hr_inc(a, s, site, pre, "mount_each"), hr_each_ord(site, s, o), + hr_merge(p, pre, np), hr_key(site, k), nk = cat(kp, cat(k, cat("~", cat(o, ".")))), strlen(nk) < 160. +.decl hr_each_ord(c0:symbol, c1:symbol, c2:symbol) +hr_each_ord(site, t, o) :- hr_inc(_, t, site, _, "mount_each"), expr_child("client", site, "ARGUMENT", "1", sx), hr_app(sx, s), + hr_each_cand(s, t, o). +hr_mreq(p, pre) :- hr_flat(_, a, p, _, _, _), hr_inc(a, _, _, pre, _). + +// (root, flat key, kind, verb, full path, call, ordinal) +.decl hr_fentry(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:number) +.decl hr_fcand(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:number, c7:symbol) +// (root, key prefix, list, key, kind, verb, list path, call, ordinal, prefix): an entry of a list at one place +// the root's flattening reaches it +.decl hr_node_entry(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:symbol, c7:symbol, c8:number, c9:symbol) +hr_node_entry(r, kp, a, k, kind, vv, p, ce, n, pre) :- hr_flat(r, a, pre, kp, "", _), hr_entry(a, k, kind, vv, p, ce, n). +hr_node_entry(r, kp, a, k, kind, vv, p, ce, n, pre) :- hr_flat(r, a, pre, kp, cut, _), cut != "", + hr_entry(a, k, kind, vv, p, ce, n), k < cut. +hr_node_entry(r, kp, a, k, kind, vv, p, ce, n, pre) :- hr_flat(r, a, pre, kp, cut, cm), cut != "", + hr_entry(a, k, kind, vv, p, ce, n), expr_module("client", em, ce), em != cm. +hr_fcand(r, fk, kind, vv, p, ce, n, pre) :- hr_node_entry(r, kp, _, k, kind, vv, p, ce, n, pre), fk = cat(kp, k). +hr_mreq(pre, p) :- hr_fcand(_, _, _, _, p, _, _, pre). +hr_fentry(r, fk, kind, vv, fp, ce, n) :- hr_fcand(r, fk, kind, vv, p, ce, n, pre), hr_merge(pre, p, fp). + +// a root nothing passed an app into: a parameter typed as the app class +// the id an app is reported under: the expression that created its route list. A list made by a call of +// a factory (each call its own list here) is reported under the factory's `new`, which is what a reader opens. +.decl hr_is_instance(c0:symbol) +hr_is_instance(l) :- hr_inc(l, t, _, _, "instance"), !hr_slot(t). +.decl hr_app_id(c0:symbol, c1:symbol) +hr_app_id(a, a) :- hr_list(a), !hr_is_instance(a). +hr_app_id(l, i) :- hr_inc(l, t, _, _, "instance"), !hr_slot(t), hr_app_id(t, i). +.decl hr_partial_root(c0:symbol) +hr_partial_root(r) :- hr_root(r), hr_slot(r). +hr_partial_root(r) :- hr_root(r), hr_unknown_mount(r). +hr_partial_root(r) :- hr_root(r), hr_fetch_in_handler(r). +// an app a REQUEST HANDLER serves itself, by calling its fetch (`wrapped.fetch(new Request(url, ..))` in a function an +// `all('*', (c) => invokePackage(c, app))` handler calls): it answers under whatever prefix that handler's route has, +// a run-time forwarding, so its routes are an unresolved mount, never exact roots at their own paths +.decl hr_fetch_site(c0:symbol, c1:symbol) +hr_fetch_site(r, m) :- call_site("client", "METHOD_CALL", cn, _, x, ce, _), router_app_fetch(cn), hr_app(x, r), hr_root(r), + expr_enclosing_method(ce, m). +// (fetching function, a function calling it): the site's function and its callers, two calls up +.decl hr_fetch_up(c0:symbol, c1:symbol, c2:number) +hr_fetch_up(r, m, 0) :- hr_fetch_site(r, m). +hr_fetch_up(r, g, d + 1) :- hr_fetch_up(r, f, d), d < 2, hr_call_of(oc, f), expr_enclosing_method(oc, g). +.decl hr_is_handler(c0:symbol) +hr_is_handler(m) :- hr_node_fn(_, _, m). +.decl hr_fetch_in_handler(c0:symbol) +hr_fetch_in_handler(r) :- hr_fetch_up(r, m, _), hr_is_handler(m). +hr_partial_root(r) :- hr_root(r), hr_list_entry(r). + +// http_route(Handler, Verb, FullPath, App, Order) — a route a served app answers: +// the handler function, the verb (ANY for all), the full path composed through every +// basePath and mount, the root app (the expression that created it) and the order key +// of the registration on that app (dotted, zero-padded: compares as program order). +// One row per (handler, verb, path, app): an app built by a factory that many calls make (each test's +// `createApp()`) is many lists reported under one App, each with the route under its own include key; the row keeps the +// earliest key (lowest line, then column, of its first segment, then the lowest key), never one per list (hono-7-06) +.decl hr_route_row(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_route_row(m, vv, fp, ai, fk) :- hr_fentry(r, fk, "route", vv, fp, ce, n), hr_last(ce, n), hr_app_id(r, ai), + hr_route_node(ce, n, m), !contains("{}", fp), !hr_partial_root(r), !hr_dyn_base_call(ce). +.decl hr_route_rl(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:number, c6:number) +hr_route_rl(m, vv, fp, ai, fk, to_number(substr(fk, 0, 7)), to_number(substr(fk, 8, 5))) :- hr_route_row(m, vv, fp, ai, fk), strlen(fk) >= 13. +.decl hr_route_ml(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +// (the minimum once per (handler, verb, path, app), not once per row of the group) +.decl hr_route_grp(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_route_grp(m, vv, fp, ai) :- hr_route_rl(m, vv, fp, ai, _, _, _). +hr_route_ml(m, vv, fp, ai, l) :- hr_route_grp(m, vv, fp, ai), l = min x : { hr_route_rl(m, vv, fp, ai, _, x, _) }. +.decl hr_route_mc(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number, c5:number) +hr_route_mc(m, vv, fp, ai, l, c) :- hr_route_ml(m, vv, fp, ai, l), c = min y : { hr_route_rl(m, vv, fp, ai, _, l, y) }. +.decl hr_route_cand(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_route_cand(m, vv, fp, ai, fk) :- hr_route_mc(m, vv, fp, ai, l, c), hr_route_rl(m, vv, fp, ai, fk, l, c). +.decl hr_route_later(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_route_later(m, vv, fp, ai, fk) :- hr_route_cand(m, vv, fp, ai, fk), hr_route_cand(m, vv, fp, ai, k2), k2 < fk. +http_route(m, vv, fp, ai, fk) :- hr_route_cand(m, vv, fp, ai, fk), !hr_route_later(m, vv, fp, ai, fk). + +// route_registered_by(RegMethod, Handler, Verb, FullPath, App) — the function whose body makes +// the registering call (a registration function, an app factory, a module body): what a change +// to it adds to or removes from the served route table +route_registered_by(rm, m, vv, fp, ai) :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), !contains("{}", fp), !hr_partial_root(r), !hr_dyn_base_call(ce), expr_enclosing_method(ce, rm), hr_app_id(r, ai), + hr_reg(ce, _, _). + +// a route whose path or app cannot be completed: what is known, and why +.decl hr_partial(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_partial(m, vv, fp, r, "dynamic_route_path") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), contains("{}", fp), !hr_partial_root(r), hr_entry_own(ce, op), contains("{}", op). +hr_partial(m, vv, fp, r, "dynamic_mount_prefix") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), contains("{}", fp), !hr_partial_root(r), hr_entry_own(ce, op), !contains("{}", op). +// a route a derived module list brought in (hr_inc kind mount_derived), at any depth below it +.decl hr_dreach(c0:symbol, c1:symbol) +hr_dreach(r, s) :- hr_flat(r, a, _, _, _, _), hr_inc(a, s, _, _, "mount_derived"). +hr_dreach(r, s2) :- hr_dreach(r, s), hr_inc(s, s2, _, _, _). +hr_partial(m, vv, fp, r, "unresolved_mount") :- hr_node_entry(r, _, a, _, "route", vv, p, ce, n, pre), hr_last(ce, n), + hr_route_node(ce, n, m), hr_dreach(r, a), hr_merge(pre, p, fp). +hr_partial(m, vv, fp, r, "unresolved_app_value") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), hr_root(r), hr_slot(r), !hr_slot_handed(r). +// a typed app slot of a method that the program DOES hand an app to, through a call the call graph cannot +// resolve (`for (const p of plugins.filter(..)) p.register?.(app)`): the app is known, which plugins receive +// it is decided at run time, so the routes are mounted under an unknown mount (SPEC R13, derived lists) +.decl hr_slot_handed(c0:symbol) +hr_slot_handed(p) :- hr_typed_slot(p), param_decl("client", _, pos, _, w, p), hr_handed_call(ce, w), + expr_child("client", ce, "ARGUMENT", pos, x), hr_app(x, _). +// a call that reaches the method through the signature it implements (`p.register?.(app)` typed by an +// interface), or by its name when nothing resolves it +.decl hr_handed_call(c0:symbol, c1:symbol) +hr_handed_call(ce, w) :- hr_call_of(ce, sig), method_dispatch_candidate(sig, w, _). +hr_handed_call(ce, w) :- method_decl("client", n, _, _, w), hr_typed_slot(p), param_decl("client", _, _, _, w, p), + call_site("client", "METHOD_CALL", n, _, _, ce, _), !hr_call_of(ce, _). +hr_partial(m, vv, fp, r, "unresolved_mount") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), hr_root(r), hr_slot(r), hr_slot_handed(r). +hr_partial(m, vv, fp, r, "unresolved_mount") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), hr_root(r), hr_unknown_mount(r), !hr_slot(r). +hr_partial(m, vv, fp, r, "unresolved_mount") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), hr_root(r), hr_fetch_in_handler(r), !hr_slot(r), !hr_unknown_mount(r). +// an app in a list entry no loop over a const array mounts (SPEC ruling R13) +hr_partial(m, vv, fp, r, "unresolved_mount") :- hr_fentry(r, _, "route", vv, fp, ce, n), hr_last(ce, n), + hr_route_node(ce, n, m), hr_root(r), hr_list_entry(r), !hr_slot(r). +// ONE row per route and app (SPEC R8): of the reasons, the one that says most (an app or mount nothing +// resolves, then the call's own path, then the prefix), and of the known paths the shortest (the fewest +// unknown pieces), never one row per depth a run-time prefix could be nested to +.decl hr_why_rank(c0:symbol, c1:number) +hr_why_rank("unresolved_app_value", 0). hr_why_rank("unresolved_mount", 1). +hr_why_rank("dynamic_route_path", 2). hr_why_rank("dynamic_mount_prefix", 3). +// (several root lists may be reported under one app id: every call of a helper that builds an app is its own +// list, R6, and is reported under the helper's `new`; the row is per app id, so per what the reader sees) +.decl hr_partial_ai(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_partial_ai(m, vv, fp, ai, w) :- hr_partial(m, vv, fp, r, w), hr_app_id(r, ai). +.decl hr_pbest(c0:symbol, c1:symbol, c2:symbol, c3:number) +hr_pbest(m, vv, ai, k) :- hr_partial_ai(m, vv, _, ai, _), k = min x : { hr_partial_ai(m, vv, _, ai, w), hr_why_rank(w, x) }. +.decl hr_plen(c0:symbol, c1:symbol, c2:symbol, c3:number) +hr_plen(m, vv, ai, n) :- hr_pbest(m, vv, ai, k), hr_why_rank(w, k), + n = min l : { hr_partial_ai(m, vv, fp, ai, w), l = strlen(fp) }. +// of equally short known paths, the first in symbol order: one row +.decl hr_pfirst(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_pfirst(m, vv, ai, fp) :- hr_pbest(m, vv, ai, k), hr_why_rank(w, k), hr_plen(m, vv, ai, n), + hr_partial_ai(m, vv, fp, ai, w), strlen(fp) = n, !hr_pshorter(m, vv, ai, fp). +.decl hr_pcand(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_pcand(m, vv, ai, fp) :- hr_pbest(m, vv, ai, k), hr_why_rank(w, k), hr_plen(m, vv, ai, n), + hr_partial_ai(m, vv, fp, ai, w), strlen(fp) = n. +.decl hr_pshorter(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_pshorter(m, vv, ai, fp) :- hr_pcand(m, vv, ai, fp), hr_pcand(m, vv, ai, f2), f2 < fp. +.decl hr_partial1(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_partial1(m, vv, fp, ai, w) :- hr_pfirst(m, vv, ai, fp), hr_pbest(m, vv, ai, k), hr_why_rank(w, k). +http_route_partial(m, vv, fp, ai, why) :- hr_partial1(m, vv, fp, ai, why). +remote_undetermined(m, "http", why) :- hr_partial1(m, _, _, _, why). + +// http_mount(ParentApp, ChildApp, Prefix, Order) — `route(prefix, child)`: the child +// app's registrations so far are served under prefix (merged with the parent's base). +// An app is exported under an expression: a list a returned object's property gives (`#`, hr_objret_inst) +// is exported under the app it was made from. +http_mount(ao, so, pre, k) :- hr_inc(a, s, site, pre, kd), (kd = "mount" ; kd = "mount_each"), hr_key(site, k), !contains("{}", pre), + hr_mount_id(a, ao), hr_mount_id(s, so). +.decl hr_mount_id_need(c0:symbol) +hr_mount_id_need(x) :- hr_inc(a, s, _, _, kd), (kd = "mount" ; kd = "mount_each"), (x = a ; x = s). +.decl hr_mount_id(c0:symbol, c1:symbol) +hr_mount_id(x, x) :- hr_mount_id_need(x), !contains("#", x). +hr_mount_id(x, i) :- hr_mount_id_need(x), contains("#", x), hr_app_id(x, i). +framework_undetermined(m, "mount", "unresolved_mount") :- hr_reg(ce, _, cn), router_mount_app(cn), + expr_child("client", ce, "ARGUMENT", "1", sx), !hr_app(sx, _), expr_enclosing_method(ce, m), !hv_fin_mount(ce). +framework_undetermined(m, "mount", "foreign_mount") :- hr_reg(ce, _, cn), router_mount_foreign(cn), + !hr_has_fn(ce, 100), expr_enclosing_method(ce, m). + +// a registration inside a branch or a loop is still emitted, and said to be one +.decl hr_block_up(c0:symbol, c1:symbol) +hr_block_up(ce, b) :- hr_reg(ce, _, _), expr_owner("client", "BLOCK", b, _, ce). +hr_block_up(ce, p) :- hr_block_up(ce, b), block_parent("client", p, b). +.decl hr_cond_kind(c0:symbol) +hr_cond_kind("IF"). hr_cond_kind("ELSE"). hr_cond_kind("ELSE_IF"). hr_cond_kind("SWITCH"). +hr_cond_kind("CASE"). hr_cond_kind("DEFAULT"). hr_cond_kind("CATCH"). hr_cond_kind("CONDITIONAL"). +.decl hr_loop_kind(c0:symbol) +hr_loop_kind("FOR"). hr_loop_kind("FOR_OF"). hr_loop_kind("FOR_IN"). hr_loop_kind("WHILE"). +hr_loop_kind("DO"). hr_loop_kind("DO_WHILE"). +framework_undetermined(m, "registration", "conditional_registration") :- hr_block_up(ce, b), + block_kind("client", k, b), hr_cond_kind(k), hr_last(ce, n), hr_node_fn(ce, n, m). +framework_undetermined(m, "registration", "loop_registration") :- hr_block_up(ce, b), + block_kind("client", k, b), hr_loop_kind(k), hr_last(ce, n), hr_node_fn(ce, n, m). +// an app-level middleware registered inside a branch or a loop: it may not run before the routes it would match +framework_undetermined(x, "registration", "conditional_registration") :- hr_block_up(ce, b), hr_reg(ce, _, cn), router_use(cn), + block_kind("client", k, b), hr_cond_kind(k), hr_node_fn(ce, _, x), !hr_dyn_arg_any(ce). +framework_undetermined(x, "registration", "loop_registration") :- hr_block_up(ce, b), hr_reg(ce, _, cn), router_use(cn), + block_kind("client", k, b), hr_loop_kind(k), hr_node_fn(ce, _, x), !hr_dyn_arg_any(ce). +// …a library middleware or a value has no body to name: the function that registers it says so +framework_undetermined(m, "registration", "conditional_registration") :- hr_block_up(ce, b), hr_reg(ce, _, cn), router_use(cn), + block_kind("client", k, b), hr_cond_kind(k), hr_harg(ce, n, _), !hr_has_fn(ce, n), !hr_dyn_arg_any(ce), expr_enclosing_method(ce, m). +framework_undetermined(m, "registration", "loop_registration") :- hr_block_up(ce, b), hr_reg(ce, _, cn), router_use(cn), + block_kind("client", k, b), hr_loop_kind(k), hr_harg(ce, n, _), !hr_has_fn(ce, n), !hr_dyn_arg_any(ce), expr_enclosing_method(ce, m). +// registration_conditional(RegCall, Reason) — a registering call (`use(..)`, a verb, a mount) written inside a branch +// or a loop. The rows above name the function a registration runs; a library middleware has none, so this is how a +// chain line keyed at the library call finds that the `use(..)` putting it there may not run. +registration_conditional(ce, "conditional_registration") :- hr_block_up(ce, b), block_kind("client", k, b), hr_cond_kind(k). +registration_conditional(ce, "loop_registration") :- hr_block_up(ce, b), block_kind("client", k, b), hr_loop_kind(k). +// …or a `use(..)` whose middleware is a value read at run time (a loop variable, a ternary over a config list, a spread +// no rule reads): the call is where that list enters every chain it stands in, so a question can name the line +registration_conditional(ce, "dynamic_middleware_list") :- hr_dyn_arg(ce, _). +registration_conditional(ce, "dynamic_middleware_list") :- hr_spread(ce, p, _), !hr_spread_known(ce, p). +.decl hr_dyn_arg_any(c0:symbol) +hr_dyn_arg_any(ce) :- hr_dyn_arg(ce, _). + +// a route brought in by a mount in a loop over a filtered list (hr_cond_mount), at any depth below it: served at its +// exact path when its element survives the filter, so declared conditional (SPEC ruling R13b) +.decl hr_creach(c0:symbol, c1:symbol) +hr_creach(r, s) :- hr_flat(r, a, _, _, _, _), hr_inc(a, s, site, _, _), hr_cond_mount(site). +hr_creach(r, s) :- hr_flat(r, a, _, _, _, _), hr_inc(a, s, site, _, _), hr_cond_inc(s, site). +hr_creach(r, s2) :- hr_creach(r, s), hr_inc(s, s2, _, _, _). +framework_undetermined(m, "registration", "conditional_registration") :- hr_node_entry(r, _, a, _, "route", _, _, ce, n, _), + hr_last(ce, n), hr_route_node(ce, n, m), hr_creach(r, a). + +// ── middleware application ────────────────────────────────────────────────── +.decl hr_hent(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hr_hent(r, hk, ce, vv, fp) :- hr_fentry(r, hk, "route", vv, fp, ce, n), hr_last(ce, n), + !contains("{}", fp), !hr_partial_root(r), !hr_dyn_base_call(ce). +// (root, key, call, ordinal, scope, verb): `use` entries, and a verb registration whose +// function takes `next` and calls it (the router composes every matching entry, so it +// runs before a later route it matches) +.decl hr_ment(c0:symbol, c1:symbol, c2:symbol, c3:number, c4:symbol, c5:symbol) +hr_ment(r, mk, ce, n, q, vv) :- hr_fentry(r, mk, "mw", vv, q, ce, n), !contains("{}", q), !hr_dyn_arg(ce, n). +hr_ment(r, mk, ce, n, q, vv) :- hr_fentry(r, mk, "route", vv, q, ce, n), !contains("{}", q), + hr_node_fn(ce, n, m), hr_calls_next(m). +.decl hr_calls_next(c0:symbol) +hr_calls_next(m) :- hr_node_fn(_, _, m), param_decl("client", _, "1", _, m, p), + expr_referenced("client", "PARAMETER", p, f), expr_child("client", ce, "METHOD_NAME", _, f), + call_site("client", _, _, _, _, ce, _). +.decl hr_verb_ok(c0:symbol, c1:symbol) +hr_verb_ok("ANY", v) :- hr_hent(_, _, _, v, _). +hr_verb_ok(v, v) :- hr_hent(_, _, _, v, _). +// (scope, path) pairs whose match is decided: every scope a root's middleware writes against every path its handlers have, +// distinct values first. The join through each (middleware key, handler key) pair with mk < hk gave the same decisions +// (a pair is only consulted beside such a key pair, and a segment's kind depends on the segment alone) at the size of +// hr_applies (2.1 s for 9k pairs on a large project) +.decl hr_spair(c0:symbol, c1:symbol) +.decl hr_rscope(c0:symbol, c1:symbol) +hr_rscope(r, q) :- hr_ment(r, _, _, _, q, _). +.decl hr_rpath(c0:symbol, c1:symbol) +hr_rpath(r, p) :- hr_hent(r, _, _, _, p). +hr_spair(q, p) :- hr_rscope(r, q), hr_rpath(r, p). + +// segments of a path, empty ones skipped +.decl hr_spath(c0:symbol) +hr_spath(q) :- hr_spair(q, _). +hr_spath(p) :- hr_spair(_, p). +.decl hr_slash(c0:symbol, c1:number) +hr_slash(p, i) :- hr_spath(p), i = range(0, strlen(p)), substr(p, i, 1) = "/". +.decl hr_next_slash(c0:symbol, c1:number, c2:number) +hr_next_slash(p, i, j) :- hr_slash(p, i), j = min x : { hr_slash(p, x), x > i }. +.decl hr_has_next(c0:symbol, c1:number) +hr_has_next(p, i) :- hr_next_slash(p, i, _). +.decl hr_seg_at(c0:symbol, c1:number, c2:symbol) +hr_seg_at(p, i, t) :- hr_next_slash(p, i, j), t = substr(p, i + 1, j - i - 1). +hr_seg_at(p, i, t) :- hr_slash(p, i), !hr_has_next(p, i), t = substr(p, i + 1, strlen(p) - i - 1). +.decl hr_seg_ne(c0:symbol, c1:number) +hr_seg_ne(p, i) :- hr_seg_at(p, i, t), t != "". +.decl hr_seg(c0:symbol, c1:number, c2:symbol) +hr_seg(p, k, t) :- hr_seg_at(p, i, t), t != "", k = count : { hr_seg_ne(p, x), x < i }. +.decl hr_nseg(c0:symbol, c1:number) +hr_nseg(p, n) :- hr_spath(p), n = count : { hr_seg(p, _, _) }. +.decl hr_lit(c0:symbol) +hr_lit(t) :- hr_seg(_, _, t), substr(t, 0, 1) != ":", t != "*". + +// a scope ending in `*` matches its fixed segments and anything (or nothing) after +.decl hr_qtail(c0:symbol) +hr_qtail(q) :- hr_nseg(q, n), n >= 1, hr_seg(q, n - 1, "*"). +.decl hr_qfix(c0:symbol, c1:number) +hr_qfix(q, n - 1) :- hr_qtail(q), hr_nseg(q, n). +hr_qfix(q, n) :- hr_nseg(q, n), !hr_qtail(q). +.decl hr_len_ok(c0:symbol, c1:symbol) +hr_len_ok(q, p) :- hr_spair(q, p), hr_qtail(q), hr_qfix(q, f), hr_nseg(p, np), np >= f. +hr_len_ok(q, p) :- hr_spair(q, p), !hr_qtail(q), hr_nseg(q, n), hr_nseg(p, n). +.decl hr_conflict(c0:symbol, c1:symbol) +hr_conflict(q, p) :- hr_spair(q, p), hr_qfix(q, f), hr_seg(q, i, x), i < f, hr_seg(p, i, y), + hr_lit(x), hr_lit(y), x != y. +.decl hr_undec(c0:symbol, c1:symbol) +hr_undec(q, p) :- hr_spair(q, p), hr_qfix(q, f), hr_seg(q, i, x), i < f, hr_seg(p, i, y), + hr_lit(x), !hr_lit(y). +.decl hr_qstar(c0:symbol, c1:symbol) +hr_qstar(q, pq) :- hr_spair(q, _), strlen(q) >= 2, substr(q, strlen(q) - 1, 1) = "*", substr(q, strlen(q) - 2, 1) != "/", + pq = substr(q, 0, strlen(q) - 1). +.decl hr_scope_ok(c0:symbol, c1:symbol) +hr_scope_ok(q, p) :- hr_len_ok(q, p), !hr_conflict(q, p), !hr_undec(q, p), !hr_qstar(q, _). +hr_scope_ok(q, p) :- hr_spair(q, p), hr_qstar(q, pq), strlen(p) >= strlen(pq), substr(p, 0, strlen(pq)) = pq. + +// (root, handler key, middleware key, middleware call, ordinal) +.decl hr_applies(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +hr_applies(r, hk, mk, mce, mn) :- hr_ment(r, mk, mce, mn, q, mv), hr_hent(r, hk, _, hv, p), mk < hk, + hr_verb_ok(mv, hv), hr_scope_ok(q, p), !hr_excepted(mce, mn, p). +// the earlier arguments of the route's own call +hr_applies(r, hk, mk, ce, mn) :- hr_hent(r, hk, ce, vv, fp), hr_fentry(r, mk, "route", vv, fp, ce, mn), + hr_last(ce, n), mn < n, !hr_dyn_arg(ce, mn). +// (the few undecidable (scope, path) pairs first, then the entries holding them: joined the other way round it walked +// every middleware/handler pair of every root for 8 rows, 1.7 s on a large project) +.decl hr_undec_pair(c0:symbol, c1:symbol) +hr_undec_pair(q, p) :- hr_undec(q, p), hr_len_ok(q, p), !hr_conflict(q, p). +framework_undetermined(mw, "middleware_scope", "param_vs_literal_scope") :- hr_undec_pair(q, p), hr_ment(r, mk, mce, mn, q, mv), + hr_hent(r, hk, _, hv, p), mk < hk, hr_verb_ok(mv, hv), hr_node(mce, mn, mw). +// a scoped `use` against a route under an unknown prefix cannot be decided (SPEC 3.3 [iter2]): no row, +// and the middleware says so; a `*` scope on the same app is decidable and is not declared +framework_undetermined(mw, "middleware_scope", "partial_route_scope") :- hr_fentry(r, mk, "mw", _, q, mce, mn), + q != "/*", hr_mw_own(mce, lq), !hr_star(lq), hr_fentry(r, hk, "route", _, fp, ce, n), hr_last(ce, n), contains("{}", fp), mk < hk, + hr_node(mce, mn, mw). +// middleware_may_apply(Mw, Handler, Verb, KnownPath, Scope, App) — the same undecidable pairs, one row per route: +// a scoped `use` registered before a route whose prefix is not known may or may not run before it, so the +// question about that route can say `Mw may run (scope Scope vs unknown prefix)` instead of nothing +// A partial route's chain is decided where it can be (SPEC 3.3 [iter2]): a middleware registered before it on +// the SAME list, whose scope as written there matches the route's path as written there (both sit under the +// one unknown prefix that list is mounted at), and a whole-app `*` / `/*` of the root before it; the +// route's own earlier arguments. Positions are ordinals among those. +// (root, flat key, call, verb, list path, flat full path, key prefix, list) +.decl hr_pr(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol, c6:symbol, c7:symbol) +hr_pr(r, hk, ce, vv, p, fp, kp, a) :- hr_node_entry(r, kp, a, k, "route", vv, p, ce, n, pre), hr_last(ce, n), + hk = cat(kp, k), hr_merge(pre, p, fp), (contains("{}", fp) ; hr_partial_root(r) ; hr_dyn_base_call(ce)). +.decl hr_star(c0:symbol) +hr_star("*"). hr_star("/*"). +hr_spair(q, p) :- hr_pr(r, hk, _, _, p, _, kp, a), !contains("{}", p), hr_node_entry(r, kp, a, k, "mw", _, q, _, _, _), + cat(kp, k) < hk, !contains("{}", q), !hr_star(q). +.decl hr_papplies(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +hr_papplies(r, hk, mk, mce, mn) :- hr_pr(r, hk, _, hv, p, _, kp, a), hr_node_entry(r, kp, a, k, "mw", mv, q, mce, mn, _), + mk = cat(kp, k), mk < hk, hr_verb_ok(mv, hv), !hr_dyn_arg(mce, mn), + (hr_star(q) ; !contains("{}", p), !contains("{}", q), hr_scope_ok(q, p)), !hr_excepted(mce, mn, p). +hr_papplies(r, hk, mk, mce, mn) :- hr_pr(r, hk, _, hv, _, _, _, _), hr_fentry(r, mk, "mw", mv, q, mce, mn), hr_star(q), + mk < hk, hr_verb_ok(mv, hv), !hr_dyn_arg(mce, mn). +// a `*` use on the route's own list or on any list it is mounted under (the root included) runs before it, whatever +// the unknown prefix: that prefix is the one the route's path is under too +hr_papplies(r, hk, mk, mce, mn) :- hr_pr(r, hk, _, hv, _, _, kp, _), hr_node_entry(r, kpa, _, k, "mw", mv, _, mce, mn, _), + strlen(kpa) <= strlen(kp), substr(kp, 0, strlen(kpa)) = kpa, + hr_mw_own(mce, lq), hr_star(lq), mk = cat(kpa, k), mk < hk, hr_verb_ok(mv, hv), !hr_dyn_arg(mce, mn). +hr_papplies(r, hk, mk, ce, mn) :- hr_pr(r, hk, ce, vv, p, _, kp, a), hr_node_entry(r, kp, a, k, "route", vv, p, ce, mn, _), + hr_last(ce, n), mn < n, !hr_dyn_arg(ce, mn), mk = cat(kp, k). +hr_verb_ok("ANY", v) :- hr_pr(_, _, _, v, _, _, _, _). +hr_verb_ok(v, v) :- hr_pr(_, _, _, v, _, _, _, _). +.decl hr_papplies_k(c0:symbol, c1:symbol, c2:symbol) +hr_papplies_k(r, hk, mk) :- hr_papplies(r, hk, mk, _, _). +.decl hr_prank(c0:symbol, c1:symbol, c2:symbol, c3:number) +hr_prank(r, hk, mk, pos) :- hr_papplies_k(r, hk, mk), !hr_second(r, mk), pos = count : { hr_papplies_k(r, hk, k2), k2 < mk, !hr_second(r, k2) }. +hr_prank(r, hk, mk, pos) :- hr_papplies_k(r, hk, mk), hr_rep(r, mk, k1), pos = count : { hr_papplies_k(r, hk, k2), k2 < k1, !hr_second(r, k2) }. +// on the one known path the route's partial row names +middleware_applies(mw, h, vv, fp, to_string(pos), ai) :- hr_pr(r, hk, ce, vv, _, fp, _, _), hr_last(ce, n), + hr_route_node(ce, n, h), hr_app_id(r, ai), hr_partial1(h, vv, fp, ai, _), + hr_papplies(r, hk, mk, mce, mn), hr_node(mce, mn, mw), hr_prank(r, hk, mk, pos). +// middleware_may_apply: one row per (middleware, route, app), the scope as the `use` wrote it, the route's +// known path as its partial row names it; never a middleware the chain above already decided +.decl hr_mw_own(c0:symbol, c1:symbol) +hr_mw_own(mce, lp) :- hr_entry_base(mce, _, "mw", _, lp, _). +.decl hr_may(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number, c5:symbol) +hr_may(mw, h, vv, mce, mn, ai) :- hr_fentry(r, mk, "mw", _, q, mce, mn), q != "/*", + hr_pr(r, hk, ce, vv, _, _, _, _), hr_last(ce, n), mk < hk, !hr_papplies(r, hk, mk, mce, mn), + hr_node(mce, mn, mw), hr_route_node(ce, n, h), hr_app_id(r, ai). +.decl hr_may_decided(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hr_may_decided(mw, h, vv, ai) :- middleware_applies(mw, h, vv, fp, _, ai), contains("{}", fp). +middleware_may_apply(mw, h, vv, fp, q, ai) :- hr_may(mw, h, vv, mce, _, ai), hr_partial1(h, vv, fp, ai, _), + hr_mw_own(mce, q), !hr_may_decided(mw, h, vv, ai). +.decl hr_applies_k(c0:symbol, c1:symbol, c2:symbol) +hr_applies_k(r, hk, mk) :- hr_applies(r, hk, mk, _, _). +.decl hr_rank(c0:symbol, c1:symbol, c2:symbol, c3:number) +hr_rank(r, hk, mk, pos) :- hr_applies_k(r, hk, mk), !hr_second(r, mk), pos = count : { hr_applies_k(r, hk, k2), k2 < mk, !hr_second(r, k2) }. +hr_rank(r, hk, mk, pos) :- hr_applies_k(r, hk, mk), hr_rep(r, mk, k1), pos = count : { hr_applies_k(r, hk, k2), k2 < k1, !hr_second(r, k2) }. +// ALTERNATIVES (SPEC ruling R15): `if (..) app.use(s, a) else app.use(s, b)`, one middleware per branch on the same +// list and scope, are one position of the chain, held by whichever runs (each declared conditional_registration) +.decl hr_use_block(c0:symbol, c1:symbol, c2:symbol) +hr_use_block(b, a, ce) :- hr_reg(ce, a, cn), router_use(cn), expr_owner("client", "BLOCK", b, _, ce). +.decl hr_blk(c0:symbol, c1:symbol, c2:number, c3:symbol) +hr_blk(b, k, to_number(o), p) :- hr_use_block(b, _, _), ts_block(k, o, _, _, _, _, _, _, _, _, p, _, _, _, _, _, _, _, _, _, b). +// The j-th middleware of the else branch stands at the position of the j-th of the if branch (one of the two runs); +// when the branches register different numbers (R15 clause 2), the longer branch's extra ones follow on, so what +// comes after continues after the longer branch. (call, arg, ordinal in its branch's middleware on that list) +.decl hr_bkey(c0:symbol, c1:symbol, c2:symbol, c3:number, c4:symbol) +hr_bkey(b, a, c, n, kk) :- hr_use_block(b, a, c), hr_harg(c, n, _), hr_key(c, k), s = to_string(n), + kk = cat(k, cat(",", cat(substr("00000", 0, 5 - strlen(s)), s))). +.decl hr_bord(c0:symbol, c1:symbol, c2:number, c3:symbol, c4:number) +hr_bord(b, c, n, a, j) :- hr_bkey(b, a, c, n, kk), j = count : { hr_bkey(b, a, _, _, kk2), kk2 < kk }. +.decl hr_alt(c0:symbol, c1:number, c2:symbol, c3:number) +hr_alt(c1, n1, c2, n2) :- hr_use_block(b1, a, _), hr_blk(b1, "IF", o, p), hr_use_block(b2, a, _), hr_blk(b2, "ELSE", o + 1, p), + hr_bord(b1, c1, n1, a, j), hr_bord(b2, c2, n2, a, j), hr_mw_own(c1, q), hr_mw_own(c2, q). +// (root, the else-branch entry's flat key, the if-branch entry's flat key) +.decl hr_rep(c0:symbol, c1:symbol, c2:symbol) +hr_rep(r, k2, k1) :- hr_alt(c1, n1, c2, n2), hr_node_entry(r, kp, _, kk2, "mw", _, _, c2, n2, _), hr_node_entry(r, kp, _, kk1, "mw", _, _, c1, n1, _), + k2 = cat(kp, kk2), k1 = cat(kp, kk1). +.decl hr_second(c0:symbol, c1:symbol) +hr_second(r, k) :- hr_rep(r, k, _). +// …and an if/else whose two branches register DIFFERENT NUMBERS of middleware on one list (SPEC ruling R15, second +// clause): which branch ran decides how many positions there are, so every chain position after the first middleware +// either branch put there is not known statically (dynamic_middleware_list on each route whose chain holds a later one) +.decl hr_pair_blk(c0:symbol, c1:symbol, c2:symbol) +hr_pair_blk(b1, b2, a) :- hr_use_block(b1, a, _), hr_blk(b1, "IF", o, p), + ts_block("ELSE", o2, _, _, _, _, _, _, _, _, p, _, _, _, _, _, _, _, _, _, b2), to_number(o2) = o + 1. +hr_pair_blk(b1, b2, a) :- hr_use_block(b2, a, _), hr_blk(b2, "ELSE", o, p), + ts_block("IF", o1, _, _, _, _, _, _, _, _, p, _, _, _, _, _, _, _, _, _, b1), to_number(o1) + 1 = o. +.decl hr_uneq_use(c0:symbol) +hr_uneq_use(c) :- hr_pair_blk(b1, b2, a), n1 = count : { hr_use_block(b1, a, c1), hr_harg(c1, _, _) }, + n2 = count : { hr_use_block(b2, a, c2), hr_harg(c2, _, _) }, n1 != n2, (hr_use_block(b1, a, c) ; hr_use_block(b2, a, c)). +framework_undetermined(h, "middleware_chain", "dynamic_middleware_list") :- hr_uneq_use(c), hr_applies(r, hk, mk, c, _), + hr_applies(r, hk, mk2, c2, _), !hr_uneq_use(c2), mk2 > mk, hr_hent(r, hk, ce, _, _), hr_last(ce, n), hr_route_node(ce, n, h). +// the same on a PARTIAL route's chain (a list mounted under a prefix the program does not spell): its positions are +// the ordinals among the middleware decided there, so a later one is just as dependent on which branch ran +framework_undetermined(h, "middleware_chain", "dynamic_middleware_list") :- hr_uneq_use(c), hr_papplies(r, hk, mk, c, _), + hr_papplies(r, hk, mk2, c2, _), !hr_uneq_use(c2), mk2 > mk, hr_pr(r, hk, ce, _, _, _, _, _), hr_last(ce, n), hr_route_node(ce, n, h). +// a chain holding a middleware that ANOTHER element of a loop mount brought in (one candidate's `*` use reaches the +// routes of the candidates after it): which elements run, and in what order, is decided at run time (SPEC R13b) +.decl hr_each_pfx(c0:symbol, c1:symbol) +// (a key is scanned once, and only one that holds a loop-mount mark at all: the scan per applies row, of every key, cost +// 3 s for no row on a large project) +.decl hr_each_key(c0:symbol) +hr_each_key(mk) :- hr_applies_k(_, _, mk), contains("~", mk). +hr_each_pfx(mk, pfx) :- hr_each_key(mk), i = range(0, strlen(mk)), substr(mk, i, 1) = "~", pfx = substr(mk, 0, i + 6). +framework_undetermined(h, "middleware_chain", "dynamic_middleware_list") :- hr_applies_k(r, hk, mk), hr_each_pfx(mk, pfx), + (strlen(hk) < strlen(pfx) ; substr(hk, 0, strlen(pfx)) != pfx), hr_hent(r, hk, ce, _, _), hr_last(ce, n), hr_route_node(ce, n, h). + +// a spread no rule could read (dynamic_middleware_list) stands somewhere in the chain: the +// positions are the ordinals among the KNOWN elements (relative order exact), and the handler's +// chain is declared incomplete (SPEC 3.3 [iter2]) +.decl hr_dyn_key(c0:symbol, c1:symbol) +hr_dyn_key(a, k) :- hr_spread(ce, p, _), !hr_spread_known(ce, p), hr_reg(ce, a, _), hr_key(ce, k0), + s = to_string(p * 100), k = cat(k0, cat(",", cat(substr("00000", 0, 5 - strlen(s)), s))). +// a middleware argument whose value is not known here: a loop variable +// (`for (const m of config.before) app.use('*', m)`) or a variable declared without a value. It +// takes no position; the chains it may stand in are declared incomplete instead (SPEC 3.3) +.decl hr_dyn_arg(c0:symbol, c1:number) +hr_dyn_arg(ce, n) :- hr_harg(ce, n, a), !hr_has_fn(ce, n), hr_denotes_var(a, v), var_initializer("client", _, "", v). +// …or chosen at run time (`use('/*', isX(mw) ? except(mw.paths, mw.handler) : mw)` over a config list) +hr_dyn_arg(ce, n) :- hr_harg(ce, n, a), !hr_has_fn(ce, n), expr_kind("client", "TERNARY_EXPRESSION", _, a). +framework_undetermined(h, "middleware_chain", "dynamic_middleware_list") :- hr_dyn_arg(ce, n), hr_last(ce, l), n < l, + hr_route_node(ce, l, h). +hr_dyn_key(a, k) :- hr_dyn_arg(ce, n), hr_reg(ce, a, cn), router_use(cn), hr_key(ce, k0), + s = to_string(n), k = cat(k0, cat(",", cat(substr("00000", 0, 5 - strlen(s)), s))). +.decl hr_fdyn(c0:symbol, c1:symbol) +hr_fdyn(r, fk) :- hr_flat(r, a, _, kp, _, _), hr_dyn_key(a, k), fk = cat(kp, k). +// …and of a partial route, from its own list or any list it is mounted under (SPEC 3.3: an `except(..)` chosen +// per element of a config list on the app a run-time tier list is mounted under) +.decl hr_fdyn_kp(c0:symbol, c1:symbol, c2:symbol) +hr_fdyn_kp(r, kpa, fk) :- hr_flat(r, a, _, kpa, _, _), hr_dyn_key(a, k), fk = cat(kpa, k). +framework_undetermined(h, "middleware_chain", "dynamic_middleware_list") :- hr_pr(r, hk, ce, _, _, _, kp, _), hr_fdyn_kp(r, kpa, sk), + strlen(kpa) <= strlen(kp), substr(kp, 0, strlen(kpa)) = kpa, sk < hk, hr_last(ce, n), hr_route_node(ce, n, h). +// positions stay the ordinals among the known elements; the chain says it is not complete +framework_undetermined(h, "middleware_chain", "dynamic_middleware_list") :- hr_hent(r, hk, ce, _, _), hr_fdyn(r, sk), + sk < hk, hr_last(ce, n), hr_route_node(ce, n, h). + +// middleware_applies(Mw, Handler, Verb, FullPath, Position, App) — Mw runs before Handler +// on a request for Verb FullPath, at Position (0 first) in the chain of the served app App +// (one chain per app a handler is mounted under). Mw is the project function, or the +// registering argument expression for library middleware. +middleware_applies(mw, h, vv, fp, to_string(pos), ai) :- hr_hent(r, hk, ce, vv, fp), hr_last(ce, n), hr_app_id(r, ai), + hr_route_node(ce, n, h), hr_applies(r, hk, mk, mce, mn), hr_node(mce, mn, mw), hr_rank(r, hk, mk, pos). + +// middleware_registered_at(Mw, Handler, Verb, FullPath, App, RegCall) — the registering call that puts Mw in the +// chain of Handler on App: an app-level `use(..)` (or a verb registration that calls next), or the route's own +// call for its per-route middleware. What a change to that one line adds to or removes from the chain. +middleware_registered_at(mw, h, vv, fp, ai, mce) :- hr_hent(r, hk, ce, vv, fp), hr_last(ce, n), hr_app_id(r, ai), + hr_route_node(ce, n, h), hr_applies(r, hk, _, mce, mn), hr_node(mce, mn, mw). +middleware_registered_at(mw, h, vv, fp, ai, mce) :- hr_pr(r, hk, ce, vv, _, fp, _, _), hr_last(ce, n), + hr_route_node(ce, n, h), hr_app_id(r, ai), hr_partial1(h, vv, fp, ai, _), + hr_papplies(r, hk, _, mce, mn), hr_node(mce, mn, mw). + +// router_node_at(Id, File, Line, What) — where a node of the tables above is written, for the ones that are not +// call sites: an app held in a parameter or a field, a middleware value, a served default export. What a reader +// is shown in place of the id. +.decl hr_at_need(c0:symbol) +hr_at_need(x) :- http_route(_, _, _, x, _). +hr_at_need(x) :- http_route_partial(_, _, _, x, _). +hr_at_need(x) :- http_mount(x, _, _, _). +hr_at_need(x) :- http_mount(_, x, _, _). +hr_at_need(x) :- http_served_by(x, _, _). +hr_at_need(x) :- http_served_by(_, x, _). +hr_at_need(x) :- middleware_applies(x, _, _, _, _, _). +hr_at_need(x) :- middleware_registered_at(_, _, _, _, x, _). +hr_at_need(x) :- middleware_may_apply(x, _, _, _, _, _). +router_node_at(x, fp, l, "expression") :- hr_at_need(x), ts_expression(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, l, _, _, _, _, _, _, _, _, _, _, _, _, x), + expr_module("client", m, x), module_file("client", fp, m). +router_node_at(p, fp, l, cat("parameter ", n)) :- hr_at_need(p), ts_method_parameter(n, _, meth, _, _, _, _, _, _, _, l, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, p), + method_module("client", meth, mm), module_file("client", fp, mm). +router_node_at(f, fp, l, cat("field ", n)) :- hr_at_need(f), ts_field(n, _, _, _, _, _, l, _, _, _, _, _, _, _, mm, _, _, _, _, _, _, _, _, _, _, _, _, _, f), + module_file("client", fp, mm). + +// middleware_site(Mw, Kind, Callee, Specifier) — what a middleware node is: +// project_fn (a function of the project), factory_result (what a project function +// returns), library_call (the value a package's function returns; no project body). +.decl hr_mw_arg(c0:symbol, c1:number, c2:symbol) +hr_mw_arg(ce, n, a) :- hr_entry(_, _, "mw", _, _, ce, n), hr_harg(ce, n, a). +hr_mw_arg(ce, n, a) :- hr_harg(ce, n, a), hr_last(ce, l), n < l, hr_entry(_, _, "route", _, _, ce, n). +middleware_site(m, "project_fn", "", "") :- hr_mw_arg(ce, n, a), hr_node_fn(ce, n, m), + !expr_kind("client", "CALL_EXPRESSION", _, a). +middleware_site(m, "factory_result", cn, "") :- hr_mw_arg(ce, n, a), hr_node_fn(ce, n, m), + call_site("client", _, cn, _, _, a, _). +middleware_site(x, "library_call", orig, spec) :- hr_mw_arg(_, _, a), hr_libret(a, x), + expr_child("client", x, "METHOD_NAME", _, f), + expr_referenced("client", "IMPORT_BINDING", ih, f), import_binding("client", _, _, orig, _, ih), + rd_import_path(ih, spec). +// a middleware VALUE that is neither a function nor a call (`app.use(guard.middleware)`, `app.use(mw)` for a const +// holding something that is not a call): named only, keyed at the argument, never resolved (SPEC ruling R11) +.decl hr_mw_value(c0:symbol, c1:symbol, c2:symbol) +hr_mw_value(a, cat(cat(rn, "."), nm), spec) :- hr_mw_arg(ce, n, a), !hr_has_fn(ce, n), !hr_dyn_arg(ce, n), + property_access_name(a, nm), expr_child("client", a, "RECEIVER", _, r), hr_ref_name(r, rn, spec). +hr_mw_value(a, rn, spec) :- hr_mw_arg(ce, n, a), !hr_has_fn(ce, n), !hr_dyn_arg(ce, n), hr_ref_name(a, rn, spec), + !hr_has_libret(a). +.decl hr_ref_name(c0:symbol, c1:symbol, c2:symbol) +hr_ref_name(e, nm, "") :- hr_on(), expr_referenced("client", "VARIABLE", v, e), var_decl("client", nm, _, _, _, _, v). +hr_ref_name(e, local, spec) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, e), import_binding("client", _, local, _, _, ih), + rd_import_path(ih, spec). +middleware_site(a, "value", nm, spec) :- hr_mw_value(a, nm, spec), !call_site("client", _, _, _, _, a, _). +middleware_site(a, "library_call", orig, spec) :- hr_mw_arg(ce, n, a), !hr_has_fn(ce, n), !hr_has_libret(a), + call_site("client", _, _, _, _, a, _), expr_child("client", a, "METHOD_NAME", _, f), + expr_referenced("client", "IMPORT_BINDING", ih, f), import_binding("client", _, _, orig, _, ih), + rd_import_path(ih, spec). diff --git a/graph/typescript/engine/config-resolution/knobs.dl b/graph/typescript/engine/config-resolution/knobs.dl index c9064f726..87c876ff6 100644 --- a/graph/typescript/engine/config-resolution/knobs.dl +++ b/graph/typescript/engine/config-resolution/knobs.dl @@ -147,6 +147,14 @@ ts_remote_confidence_exact("exact"). // a placeholder on one end stood in for a literal on the other .decl ts_remote_confidence_route_shape(c0:symbol) ts_remote_confidence_route_shape("route_shape"). +// a request whose base address is not a literal (`${base}/x`, a computed host): it MAY reach the route +// (SPEC ruling R14) +.decl ts_remote_confidence_base_unknown(c0:symbol) +ts_remote_confidence_base_unknown("base_unknown"). +// a request whose HTTP method is not decidable (the init is a parameter, the method a computed value): it may reach a +// route of any verb its path fits (SPEC ruling R17); an unknown base wins over it (base_unknown) +.decl ts_remote_confidence_method_unknown(c0:symbol) +ts_remote_confidence_method_unknown("method_unknown"). // the verb that matches every other one: `app.all`, `@All`, a request whose method // is computed .decl ts_http_verb_any(c0:symbol) @@ -252,3 +260,186 @@ ts_msg_transport_member("Transport.TCP", "tcp"). // bound to one in module configuration): it joins an end of any transport .decl ts_remote_transport_message(c0:symbol) ts_remote_transport_message("message"). + +// ============================================================================ +// HTTP ROUTER APPLICATIONS (config-resolution/http-router-*.dl) +// +// An application object a program builds and registers routes, middleware and +// sub-applications on (`const app = new X(); app.get('/x', h); app.route('/p', sub)`). +// Recognised by the CLASS it is constructed from and the MODULE that class is imported +// from, never by a method name: `get`, `use`, `route`, `on` are everywhere. +// ============================================================================ + +// router_app_class(Specifier, ExportedName): `new ()` of this import is an app +.decl router_app_class(c0:symbol, c1:symbol) +router_app_class("hono", "Hono"). +router_app_class("hono/tiny", "Hono"). +router_app_class("hono/quick", "Hono"). +router_app_class("@hono/zod-openapi", "OpenAPIHono"). +// ── how a module may be named: Deno specifiers and URLs ───────────────────── +// router_spec_scheme(Prefix): `npm:hono@4`, `jsr:@hono/hono@^4/logger` name the package +// after the prefix, a version after `@` dropped; router_spec_url(Prefix, Package): a URL +// import of the package's published module (`@v3/mod.ts` is the package itself) +.decl router_spec_scheme(c0:symbol) +router_spec_scheme("npm:"). +router_spec_scheme("jsr:"). +.decl router_spec_url(c0:symbol, c1:symbol) +router_spec_url("https://deno.land/x/hono", "hono"). +router_spec_url("https://esm.sh/hono", "hono"). +// the JSR name of the package +router_app_class("@hono/hono", "Hono"). +// router_verb(Method, Verb): a route registration and the verb it serves +.decl router_verb(c0:symbol, c1:symbol) +router_verb("get", "GET"). router_verb("post", "POST"). +router_verb("put", "PUT"). router_verb("delete", "DELETE"). +router_verb("patch", "PATCH"). router_verb("options", "OPTIONS"). +router_verb("all", "ANY"). +// middleware for every verb, under a path or under all paths +.decl router_use(c0:symbol) +router_use("use"). +// `on(VERB | [VERBS], path | [paths], ...handlers)` +.decl router_on(c0:symbol) +router_on("on"). +// `route(prefix, subApp)`: the sub-app's registrations so far, under the prefix +.decl router_mount_app(c0:symbol) +router_mount_app("route"). +// `basePath(prefix)`: a new app value sharing the route list, its registrations prefixed +.decl router_base_path(c0:symbol) +router_base_path("basePath"). +// `mount(prefix, fetchHandler)`: a foreign handler for every verb under prefix/* +.decl router_mount_foreign(c0:symbol) +router_mount_foreign("mount"). +// a handler the router calls when nothing matched or something threw +.decl router_fallback(c0:symbol) +router_fallback("notFound"). +router_fallback("onError"). +// methods whose result is the app itself (so a chain stays an app value) +.decl router_returns_app(c0:symbol) +router_returns_app(n) :- router_verb(n, _). +router_returns_app(n) :- router_use(n). +router_returns_app(n) :- router_on(n). +router_returns_app(n) :- router_mount_app(n). +router_returns_app(n) :- router_mount_foreign(n). +router_returns_app(n) :- router_fallback(n). +router_returns_app("openapi"). +router_returns_app("doc"). +router_returns_app("doc31"). +// router_mw_wrapper(Specifier, Name): `name(fn)` is middleware whose body is `fn` +.decl router_mw_wrapper(c0:symbol, c1:symbol) +router_mw_wrapper("hono/factory", "createMiddleware"). +// router_mw_combinator(Specifier, Name): `name(mw, ...)` is one middleware running its +// function arguments (`every`, `some`); router_mw_except: `name(paths, mw)` runs mw +// everywhere but the listed paths +.decl router_mw_combinator(c0:symbol, c1:symbol) +router_mw_combinator("hono/combine", "every"). +router_mw_combinator("hono/combine", "some"). +.decl router_mw_except(c0:symbol, c1:symbol) +router_mw_except("hono/combine", "except"). +// router_served_fetch(Name): the property of an app that serves requests +// (`export default { fetch: app.fetch, scheduled }`: the other members are called by +// the platform) +.decl router_served_fetch(c0:symbol) +router_served_fetch("fetch"). +// router_module_glob(Name): `import.meta.(pattern | [patterns], opts)` loads every module the pattern +// matches (the bundler's module list, SPEC ruling R12) +.decl router_module_glob(c0:symbol) +router_module_glob("glob"). +// router_factory(Specifier, Name): `name({ initApp })` makes a factory; `.createApp()` +// (router_factory_app) is an app whose first registrations are initApp's (router_factory_init) +.decl router_factory(c0:symbol, c1:symbol) +router_factory("hono/factory", "createFactory"). +.decl router_factory_app(c0:symbol) +router_factory_app("createApp"). +.decl router_factory_init(c0:symbol) +router_factory_init("initApp"). +// `.createMiddleware(fn)`: the middleware is fn +.decl router_factory_mw(c0:symbol) +router_factory_mw("createMiddleware"). +// ── the clients that send to an app's routes (framework-behavior/http-rpc-client.dl) ── +// router_rpc_client: `name(base)`; router_test_client: `name(app)`; each +// property of the client is a path segment, router_rpc_index adds none, and a +// router_rpc_verb method sends; router_app_request: `app.(path, init)` sends +.decl router_rpc_client(c0:symbol, c1:symbol) +router_rpc_client("hono/client", "hc"). +.decl router_test_client(c0:symbol, c1:symbol) +router_test_client("hono/testing", "testClient"). +.decl router_rpc_index(c0:symbol) +router_rpc_index("index"). +.decl router_rpc_verb(c0:symbol, c1:symbol) +router_rpc_verb("$get", "GET"). router_rpc_verb("$post", "POST"). +router_rpc_verb("$put", "PUT"). router_rpc_verb("$delete", "DELETE"). +router_rpc_verb("$patch", "PATCH"). router_rpc_verb("$options", "OPTIONS"). +router_rpc_verb("$head", "HEAD"). +.decl router_app_request(c0:symbol) +router_app_request("request"). +// router_app_fetch: `app.(request, env)` serves a request object directly; +// router_request_class: the platform class a request object is built with +.decl router_app_fetch(c0:symbol) +router_app_fetch("fetch"). +.decl router_request_class(c0:symbol) +router_request_class("Request"). +// ── OpenAPI route definitions and schema validators ───────────────────────── +// router_openapi(Method): `app.(routeDef, handler, hook?)` registers routeDef's method +// and path; router_route_def(Specifier, Name): `name({ method, path, request, responses })` +.decl router_openapi(c0:symbol) +router_openapi("openapi"). +.decl router_route_def(c0:symbol, c1:symbol) +router_route_def("@hono/zod-openapi", "createRoute"). +// the keys of a route definition +.decl router_def_key(c0:symbol, c1:symbol) +router_def_key("method", "method"). router_def_key("path", "path"). +router_def_key("request", "request"). router_def_key("responses", "responses"). +router_def_key("body", "body"). router_def_key("content", "content"). +router_def_key("schema", "schema"). router_def_key("middleware", "middleware"). +// router_def_request_target(Key, Target): `request.` validates that target +.decl router_def_request_target(c0:symbol, c1:symbol) +router_def_request_target("params", "param"). router_def_request_target("query", "query"). +router_def_request_target("headers", "header"). router_def_request_target("cookies", "cookie"). +// router_def_body_target(ContentType, Target) +.decl router_def_body_target(c0:symbol, c1:symbol) +router_def_body_target("application/json", "json"). +router_def_body_target("multipart/form-data", "form"). +router_def_body_target("application/x-www-form-urlencoded", "form"). +// router_validator(Specifier, Name): `name(target, schema)` validates target with schema +// as route middleware; router_validator_fn: `name(target, fn)`, a function validator +.decl router_validator(c0:symbol, c1:symbol) +router_validator("@hono/zod-validator", "zValidator"). +.decl router_validator_fn(c0:symbol, c1:symbol) +router_validator_fn("hono/validator", "validator"). +// router_schema_module(Specifier): a schema library a validator's schemas are built with +.decl router_schema_module(c0:symbol) +router_schema_module("zod"). router_schema_module("zod/v4"). router_schema_module("zod/v3"). +router_schema_module("zod/mini"). router_schema_module("zod/v4-mini"). router_schema_module("zod/v4/core"). +router_schema_module("@hono/zod-openapi"). +// `c..(target)`: the validated value of target +.decl router_ctx_req(c0:symbol) +router_ctx_req("req"). +.decl router_valid_read(c0:symbol) +router_valid_read("valid"). +// router_handler_spread(Name): `...x.name(a, b)` spreads its arguments as handlers +.decl router_handler_spread(c0:symbol) +router_handler_spread("createHandlers"). + +// ── the request context's environment and store (framework-behavior/http-router-ctx-type.dl) ── +// the member of an environment type that lists the context keys and their types +.decl router_env_vars(c0:symbol) +router_env_vars("Variables"). +// a context's keyed read and write, and its whole-store view +.decl router_ctx_get(c0:symbol) +router_ctx_get("get"). +.decl router_ctx_set(c0:symbol) +router_ctx_set("set"). +.decl router_ctx_var(c0:symbol) +router_ctx_var("var"). +// a helper whose first type argument is the environment of the function it is handed +.decl router_env_call(c0:symbol) +router_env_call("createMiddleware"). +// a type operator that takes a function type and gives what it returns (TypeScript's own) +.decl ts_type_return_operator(c0:symbol) +ts_type_return_operator("ReturnType"). +// validators from other packages, same (target, schema) arguments (gap census K2) +router_validator("hono-openapi", "validator"). +router_validator("@hono/valibot-validator", "vValidator"). +router_validator("@hono/typebox-validator", "tbValidator"). +router_validator("@hono/arktype-validator", "arktypeValidator"). +router_validator("@hono/standard-validator", "sValidator"). diff --git a/graph/typescript/engine/framework-behavior/destinations.dl b/graph/typescript/engine/framework-behavior/destinations.dl index 35df1c87d..dbe121ad3 100644 --- a/graph/typescript/engine/framework-behavior/destinations.dl +++ b/graph/typescript/engine/framework-behavior/destinations.dl @@ -81,7 +81,7 @@ rd_demand(c) :- rd_demand(e), expr_kind("client", "BINARY_EXPRESSION", _, e), ex expr_child("client", e, "RIGHT_OPERAND", _, c). rd_demand(c) :- rd_demand(e), expr_literal_type("client", "TEMPLATE", e), expr_child("client", e, "TEMPLATE_SPAN", _, c). -rd_demand(i) :- rd_demand(e), rd_denotes_var(e, v), var_initializer("client", _, i, v), i != "". +rd_demand(i) :- rd_demand(e), rd_denotes_var(e, v), var_initializer("client", _, i, v), i != "", !var_reassigned(v). rd_demand(val) :- rd_prop_value(_, val). rd_demand(c) :- rd_demand(e), expr_kind("client", k, _, e), expr_kind_is_transparent(k), expr_child("client", e, _, _, c). @@ -105,12 +105,23 @@ rd_prop_value(e, val) :- rd_demand(e), expr_kind("client", "PROPERTY_ACCESS", _, .decl rd_is_prop(c0:symbol) .decl rd_is_transparent(c0:symbol) rd_is_str(e) :- rd_demand(e), expr_kind("client", "LITERAL", _, e), expr_literal_type("client", "STRING", e). +rd_is_str(e) :- rd_demand(e), expr_kind("client", "LITERAL", _, e), expr_literal_type("client", "NO_SUBSTITUTION_TEMPLATE", e). rd_is_tmpl(e) :- rd_demand(e), expr_literal_type("client", "TEMPLATE", e). rd_is_plus(e) :- rd_demand(e), expr_kind("client", "BINARY_EXPRESSION", _, e), expr_operator("client", "+", e). -rd_is_ref(e) :- rd_demand(e), rd_denotes_var(e, v), var_initializer("client", _, i, v), i != "". +// a `let` assigned again anywhere is not a constant: its use is a computed part `{}`, never its +// first value (`let id = ''` later set by a test step) +rd_is_ref(e) :- rd_demand(e), rd_denotes_var(e, v), var_initializer("client", _, i, v), i != "", !var_reassigned(v). rd_is_prop(e) :- rd_prop_value(e, _). rd_is_transparent(e) :- rd_demand(e), expr_kind("client", k, _, e), expr_kind_is_transparent(k), expr_child("client", e, _, _, _). +// `this.baseUrl`, a field with an initializer that nothing assigns again +.decl rd_is_field(c0:symbol, c1:symbol) +.decl rd_field_rewritten(c0:symbol) +rd_field_rewritten(f) :- expr_kind("client", k, _, x), (k = "ASSIGNMENT_EXPRESSION" ; k = "COMPOUND_ASSIGNMENT"), + expr_child("client", x, "LEFT_OPERAND", _, l), ts_field_access_target(l, f). +rd_is_field(e, i) :- rd_demand(e), expr_kind("client", "PROPERTY_ACCESS", _, e), ts_field_access_target(e, f), + field_initializer("client", i, f), i != "", !rd_field_rewritten(f). +rd_demand(i) :- rd_is_field(_, i). .decl rd_val(c0:symbol, c1:symbol) // literalValue is the text between the quotes; an empty string has no row at all @@ -119,11 +130,48 @@ rd_val(e, "") :- rd_is_str(e), !expr_literal_value("client", _, e). rd_val(e, cat(l, r)) :- rd_is_plus(e), expr_child("client", e, "LEFT_OPERAND", _, lc), expr_child("client", e, "RIGHT_OPERAND", _, rc), rd_val(lc, l), rd_val(rc, r), strlen(l) + strlen(r) < 400. -rd_val(e, v) :- rd_demand(e), rd_denotes_var(e, x), var_initializer("client", _, i, x), i != "", rd_val(i, v). +rd_val(e, v) :- rd_demand(e), rd_denotes_var(e, x), var_initializer("client", _, i, x), i != "", !var_reassigned(x), rd_val(i, v). rd_val(e, v) :- rd_prop_value(e, val), rd_val(val, v). rd_val(e, v) :- rd_is_transparent(e), expr_child("client", e, _, _, c), rd_val(c, v). +rd_val(e, v) :- rd_is_field(e, i), rd_val(i, v). +// a call with no arguments of a function with exactly one return (`getBasePath() { return '/dashboard' }`): +// the value it returns (SPEC 3.2, G8) +.decl rd_call0(c0:symbol, c1:symbol) +rd_call0(ce, w) :- call_site("client", _, _, _, _, ce, _), + call_chain_edge(ce, _, "-", w, "client", st, _), st != "callback_registered". +rd_call0(ce, w) :- loop_elem_callee(ce, w). +.decl rd_ret_top(c0:symbol, c1:symbol) +// the returned expression itself: a ROOT (method_returns_expr also holds every sub-expression under a +// `return`). Read off the expression's own root flag rather than by joining each returned expression with +// its parents, which ran over every returned sub-expression of every called function in the program. +rd_ret_top(w, e) :- rd_call0(_, w), method_returns_expr(w, e), expr_kind("client", _, "ROOT", e). +.decl rd_ret_one(c0:symbol, c1:symbol) +rd_ret_one(w, e) :- rd_ret_top(w, e), 1 = count : { rd_ret_top(w, _) }. +.decl rd_call0_one(c0:symbol, c1:symbol) +rd_call0_one(ce, e) :- rd_call0(ce, w), rd_ret_one(w, e), 1 = count : { rd_call0(ce, _) }. +rd_demand(e) :- rd_demand(ce), rd_call0_one(ce, e). +// the value ONE method returns, whatever calls it (a call reaching several methods, `g.prefix(v)` over a loop of +// classes, is then read per method by whoever knows which one runs) +rd_demand(e) :- rd_demand(ce), rd_call0(ce, w), rd_ret_one(w, e). +.decl rd_mval(c0:symbol, c1:symbol) +rd_mval(w, v) :- rd_ret_one(w, e), rd_demand(e), rd_val(e, v). +rd_val(ce, v) :- rd_call0_one(ce, e), rd_val(e, v). +.decl rd_is_call0(c0:symbol) +rd_is_call0(ce) :- rd_demand(ce), rd_call0_one(ce, _). +// a parameter of a function called from exactly one place: the value that place passes +.decl rd_param_calls(c0:symbol, c1:number) +rd_param_calls(w, n) :- param_decl("client", _, _, _, w, _), n = count : { rd_call0(_, w) }. +.decl rd_param_one(c0:symbol, c1:symbol) +rd_param_one(e, a) :- rd_demand(e), expr_referenced("client", "PARAMETER", p, e), param_decl("client", _, pos, _, w, p), + rd_param_calls(w, 1), rd_call0(ce, w), expr_child("client", ce, "ARGUMENT", pos, a). +rd_demand(a) :- rd_param_one(_, a). +rd_val(e, v) :- rd_param_one(e, a), rd_val(a, v). +.decl rd_is_param_one(c0:symbol) +rd_is_param_one(e) :- rd_param_one(e, _). +.decl rd_is_field_any(c0:symbol) +rd_is_field_any(e) :- rd_is_field(e, _). rd_val(e, "{}") :- rd_demand(e), !rd_is_str(e), !rd_is_tmpl(e), !rd_is_plus(e), !rd_is_ref(e), - !rd_is_prop(e), !rd_is_transparent(e). + !rd_is_prop(e), !rd_is_transparent(e), !rd_is_field_any(e), !rd_is_param_one(e), !rd_is_call0(e). // ── a template: its raw text, split at each `${…}` ────────────────────────── // The parser keeps the template as written, backticks included, and gives each hole @@ -176,7 +224,11 @@ rd_route_fn_arg(ce, p, m) :- rd_route_call(ce, _), cfg_named_fn_arg(ce, pos, m), .decl rd_route_last(c0:symbol, c1:number) rd_route_last(ce, p) :- rd_route_fn_arg(ce, _, _), p = max q : { rd_route_fn_arg(ce, q, _) }. rd_route_raw(m, p, verb) :- rd_route_call(ce, verb), rd_route_last(ce, k), rd_route_fn_arg(ce, k, m), - expr_child("client", ce, "ARGUMENT", "0", a), rd_val(a, p), strlen(p) >= 1, substr(p, 0, 1) = "/". + expr_child("client", ce, "ARGUMENT", "0", a), rd_val(a, p), strlen(p) >= 1, substr(p, 0, 1) = "/", !hr_reg(ce, _, _). +// a registration on an application whose route table the engine composes (http-router-routes.dl): joined on +// the FULL path a request reaches it by, never on the path written at the call (a `/health` registered on a +// `basePath('/api')` app is served at `/api/health` only) +rd_route_raw(m, p, verb) :- http_route(m, verb, p, _, _). // A handler registered under a path read from a constant is as much a root as one // under a literal: config-resolution/entry-points.dl reads the literal only. @@ -244,7 +296,22 @@ rd_fetch_verb(ce, v) :- rd_fetch_init(ce, o), !expr_kind("client", "OBJECT_LITER rd_demand(a) :- rd_fetch_call(ce), expr_child("client", ce, "ARGUMENT", "0", a). rd_send(ce, from, verb, u) :- rd_fetch_verb(ce, verb), expr_child("client", ce, "ARGUMENT", "0", a), rd_val(a, u), expr_enclosing_method(ce, from). -rd_send_site(ce, from) :- rd_fetch_call(ce), expr_enclosing_method(ce, from). +rd_send_site(ce, from) :- rd_fetch_call(ce), expr_enclosing_method(ce, from), !rd_file_fetch(ce). +// `fetch(new URL('./x.wasm', import.meta.url))` reads a file shipped beside the module: not a request at all +.decl rd_file_fetch(c0:symbol) +rd_file_fetch(ce) :- rd_fetch_call(ce), expr_child("client", ce, "ARGUMENT", "0", u), call_site("client", "CONSTRUCTOR_CALL", "URL", _, _, u, _), + expr_child("client", u, "ARGUMENT", "1", b), rd_module_url(b). +// `fetch(new URL('/x', base))`: the path under a base the program does not spell +.decl rd_fetch_url_obj(c0:symbol, c1:symbol) +rd_fetch_url_obj(ce, p) :- rd_fetch_call(ce), expr_child("client", ce, "ARGUMENT", "0", u), + call_site("client", "CONSTRUCTOR_CALL", "URL", _, _, u, _), expr_child("client", u, "ARGUMENT", "0", p), + expr_child("client", u, "ARGUMENT", "1", b), !rd_module_url(b). +// `new URL('../fonts/x.ttf', import.meta.url)` names a file next to the module, never a request to a route +.decl rd_module_url(c0:symbol) +rd_module_url(b) :- expr_kind("client", "PROPERTY_ACCESS", _, b), property_access_name(b, "url"), !expr_child("client", b, "RECEIVER", _, _). +rd_demand(p) :- rd_fetch_url_obj(_, p). +rd_send(ce, from, verb, cat("{}", pv)) :- rd_fetch_url_obj(ce, p), rd_fetch_verb(ce, verb), rd_val(p, pv), + substr(pv, 0, 1) = "/", expr_enclosing_method(ce, from). // ── .(url, …) ───────────────────────────────────────────────── // The receiver is the package's import itself, or a const its factory made: @@ -329,7 +396,13 @@ rd_pn_nonempty_at(n, i) :- rd_pn_seg_at(n, i, t), t != "". rd_pn_seg_raw(n, k, t) :- rd_pn_seg_at(n, i, t), t != "", k = count : { rd_pn_nonempty_at(n, x), x < i }. .decl rd_seg_ph(c0:symbol) rd_seg_ph(t) :- rd_pn_seg_raw(_, _, t), substr(t, 0, 1) = ":". -rd_seg_ph(t) :- rd_pn_seg_raw(_, _, t), contains("{", t). +rd_seg_ph(t) :- rd_pn_seg_raw(_, _, t), contains("{", t), !rd_mixed_lit(t, _). +// a client segment that starts with a literal and ends in a computed part (`skills${path}`): it keeps the literal, and +// fits only a segment starting with it; at the end of the path the computed part may hold more segments +.decl rd_mixed_lit(c0:symbol, c1:symbol) +rd_mixed_lit(t, l) :- rd_pn_seg_raw(n, _, t), rd_norm(s, n), rd_client_path(s), strlen(t) > 2, contains("{}", t), + c = substr(t, 0, 1), c != ":", c != "{", c != "*", i = min j : { j = range(0, strlen(t) - 1), substr(t, j, 2) = "{}" }, + l = substr(t, 0, i). rd_seg_ph("*") :- rd_pn_seg_raw(_, _, "*"). .decl rd_pn_seg(c0:symbol, c1:number, c2:symbol) rd_pn_seg(n, k, "{}") :- rd_pn_seg_raw(n, k, t), rd_seg_ph(t). @@ -373,12 +446,33 @@ rd_dest(s, d) :- rd_client_path(s), rd_ccount(s, c), c > 0, rd_dest_step(s, c, d rd_dest(p, d) :- rd_server_path(p), rd_scount(p, c), c > 0, rd_dest_step(p, c, d). rd_dest(p, "/") :- rd_server_path(p), rd_scount(p, 0). +// ── a send to a PUBLIC host is not a request to this program ─────────────── +// `https://api.example.com/health` names a host on the internet by its DNS name: another +// party's server, even when a route here happens to spell the same path. A single-label host +// (`http://billing:9000`, `localhost`), an address, or a computed host stays joinable: those +// are how services of one deployment, and tests, reach each other. +.decl rd_host(c0:symbol, c1:symbol) +rd_host(s, h) :- rd_after_scheme(s, r), rd_slash_in(r, _), m = min i : rd_slash_in(r, i), h = substr(r, 0, m). +rd_host(s, r) :- rd_after_scheme(s, r), !rd_slash_in(r, _). +.decl rd_foreign(c0:symbol) +rd_foreign(s) :- rd_client_path(s), rd_host(s, h), contains(".", h), !contains("{}", h), strlen(h) >= 1, + c = substr(h, 0, 1), c != "[", !rd_digit(c). +.decl rd_digit(c0:symbol) +rd_digit("0"). rd_digit("1"). rd_digit("2"). rd_digit("3"). rd_digit("4"). +rd_digit("5"). rd_digit("6"). rd_digit("7"). rd_digit("8"). rd_digit("9"). + // ── the join ──────────────────────────────────────────────────────────────── .decl rd_route_pair(c0:symbol, c1:symbol) -rd_route_pair(s, p) :- rd_ccount(s, c), rd_scount(p, c), rd_chas_literal(s). -rd_route_pair(s, p) :- rd_ccount(s, c), rd_scount(p, c + 1), rd_server_last_optional(p), rd_chas_literal(s). +rd_route_pair(s, p) :- rd_ccount(s, c), rd_scount(p, c), rd_chas_literal(s), !rd_foreign(s). +rd_route_pair(s, p) :- rd_ccount(s, c), rd_scount(p, c + 1), rd_server_last_optional(p), rd_chas_literal(s), !rd_foreign(s). +rd_route_pair(s, p) :- rd_ccount(s, c), rd_scount(p, c2), c2 > c, rd_ctail_mixed(s), rd_chas_literal(s), !rd_foreign(s). +.decl rd_ctail_mixed(c0:symbol) +rd_ctail_mixed(s) :- rd_ccount(s, c), rd_cseg(s, c - 1, a), rd_mixed_lit(a, _), substr(a, strlen(a) - 2, 2) = "{}". +.decl rd_mixed_fits(c0:symbol, c1:symbol) +rd_mixed_fits(a, b) :- rd_route_pair(s, p), rd_cseg(s, k, a), rd_sseg(p, k, b), rd_mixed_lit(a, l), strlen(b) >= strlen(l), + substr(b, 0, strlen(l)) = l. .decl rd_seg_conflict(c0:symbol, c1:symbol) -rd_seg_conflict(s, p) :- rd_route_pair(s, p), rd_cseg(s, k, a), rd_sseg(p, k, b), a != b, a != "{}", b != "{}". +rd_seg_conflict(s, p) :- rd_route_pair(s, p), rd_cseg(s, k, a), rd_sseg(p, k, b), a != b, a != "{}", b != "{}", !rd_mixed_fits(a, b). .decl rd_seg_literal_eq(c0:symbol, c1:symbol) rd_seg_literal_eq(s, p) :- rd_route_pair(s, p), rd_cseg(s, k, a), rd_sseg(p, k, a), a != "{}". .decl rd_seg_differs(c0:symbol, c1:symbol) @@ -401,7 +495,49 @@ rd_verb_ok(a, b) :- rd_send(_, _, a, _), rd_route_raw(_, _, b), ts_http_verb_any rd_seg_diff_n(s, p, n) :- rd_route_match(s, p, _), n = count : { rd_cseg(s, k, a), rd_sseg(p, k, b), a != b }. .decl rd_candidate(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:number) rd_candidate(e, from, to, p, conf, n) :- rd_send(e, from, sv, s), rd_route_match(s, p, conf), - rd_route_raw(to, p, rv), rd_verb_ok(sv, rv), rd_seg_diff_n(s, p, n), from != to. + rd_route_raw(to, p, rv), rd_verb_ok(sv, rv), rd_seg_diff_n(s, p, n), from != to, !rd_base_unknown_to(s, to, p), !rd_method_unknown(e). +// …whose method is not decidable: it MAY reach the route, on whatever verb (SPEC ruling R17) +rd_candidate(e, from, to, p, conf, n) :- rd_send(e, from, sv, s), rd_route_match(s, p, _), + rd_route_raw(to, p, rv), rd_verb_ok(sv, rv), rd_seg_diff_n(s, p, n), from != to, !rd_base_unknown_to(s, to, p), rd_method_unknown(e), + ts_remote_confidence_method_unknown(conf). +.decl rd_method_unknown(c0:symbol) +rd_method_unknown(ce) :- rd_fetch_has_method(ce), !rd_fetch_has_verb(ce). +rd_method_unknown(ce) :- rd_fetch_init(ce, o), !expr_kind("client", "OBJECT_LITERAL", _, o). +// a request whose base address is computed (`${base}/x`, a host from the environment) joined to a route of a +// composed route table: it MAY reach it, and says so (SPEC ruling R14) +rd_candidate(e, from, to, p, conf, n) :- rd_send(e, from, sv, s), rd_route_match(s, p, _), + rd_route_raw(to, p, rv), rd_verb_ok(sv, rv), rd_seg_diff_n(s, p, n), from != to, rd_base_unknown_to(s, to, p), + !contains("*", p), !rd_bu_test_only(e, to, p), ts_remote_confidence_base_unknown(conf). +// what a request with an unknown base may NOT be said to reach: a catch-all (`*`) route, which any path fits, and, +// from code outside the tests, a route only an app built in a test file serves (that app is never deployed) +.decl rd_test_path(c0:symbol) +rd_test_path(fp) :- module_decl("client", _, _, fp, _, _), + (contains(".test.", fp) ; contains(".spec.", fp) ; contains("__tests__/", fp) ; contains("/test/", fp) ; contains("/tests/", fp) ; + contains("/e2e/", fp) ; substr(fp, 0, 5) = "test/" ; substr(fp, 0, 6) = "tests/" ; substr(fp, 0, 4) = "e2e/"). +.decl rd_route_in_test(c0:symbol, c1:symbol) +rd_route_in_test(to, p) :- rd_base_unknown_to(_, to, p), http_route(to, _, p, a, _), expr_module("client", m, a), + module_decl("client", _, _, fp, _, m), rd_test_path(fp). +.decl rd_route_served_outside_tests(c0:symbol, c1:symbol) +rd_route_served_outside_tests(to, p) :- rd_base_unknown_to(_, to, p), http_route(to, _, p, a, _), expr_module("client", m, a), + module_decl("client", _, _, fp, _, m), !rd_test_path(fp). +.decl rd_bu_test_only(c0:symbol, c1:symbol, c2:symbol) +rd_bu_test_only(e, to, p) :- rd_send(e, _, _, s), rd_base_unknown_to(s, to, p), rd_route_in_test(to, p), + !rd_route_served_outside_tests(to, p), expr_module("client", m, e), module_decl("client", _, _, fp, _, m), !rd_test_path(fp). +.decl rd_base_unknown(c0:symbol) +rd_base_unknown(s) :- rd_client_drops_base(s). +// a computed host name (a computed port alone keeps the host: `http://localhost:${port}` is this machine) +rd_base_unknown(s) :- rd_host(s, h), contains("{}", h), !contains(":", h). +rd_base_unknown(s) :- rd_host(s, h), contains(":", h), i = min j : { j = range(0, strlen(h)), substr(h, j, 1) = ":" }, + contains("{}", substr(h, 0, i)). +// a literal SINGLE-LABEL host (`http://billing:9000`): a service of the same deployment, which app serves it is not +// known here (SPEC ruling R14a); localhost is this machine +rd_base_unknown(s) :- rd_host(s, h), rd_hostname(h, hn), hn != "", !contains("{}", hn), !contains(".", hn), hn != "localhost", + substr(hn, 0, 1) != "[". +.decl rd_hostname(c0:symbol, c1:symbol) +rd_hostname(h, substr(h, 0, i)) :- rd_host(_, h), contains(":", h), i = min j : { j = range(0, strlen(h)), substr(h, j, 1) = ":" }. +rd_hostname(h, h) :- rd_host(_, h), !contains(":", h). +.decl rd_base_unknown_to(c0:symbol, c1:symbol, c2:symbol) +rd_base_unknown_to(s, to, p) :- rd_base_unknown(s), rd_route_match(s, p, _), http_route(to, _, p, _, _). .decl rd_candidate_best(c0:symbol, c1:number) rd_candidate_best(e, b) :- rd_candidate(e, _, _, _, _, _), b = min n : rd_candidate(e, _, _, _, _, n). diff --git a/graph/typescript/engine/framework-behavior/http-router-chain.dl b/graph/typescript/engine/framework-behavior/http-router-chain.dl new file mode 100644 index 000000000..b348c63ec --- /dev/null +++ b/graph/typescript/engine/framework-behavior/http-router-chain.dl @@ -0,0 +1,102 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP ROUTER CHAIN (what the router does at request time) +// +// config-resolution/http-router-routes.dl says which functions a request runs and in +// what order (middleware_applies). This file adds what follows from running them: +// +// ctx_key_flow(Setter, Reader, Key) +// the request context is a keyed store: a function on the chain writes a key +// (`c.set('user', u)`) and a LATER function on the same chain reads it +// (`c.get('user')`, `c.var.user`). Neither calls the other; the key ties them. +// +// The context is the FIRST PARAMETER of a function the router calls (a handler or a +// middleware), so `c.get` on anything else (a Map, a cache) is never read here. +// A key that is not a literal or a const is declared, not guessed; a read whose key +// no earlier function on any of its chains sets is declared too: it reads nothing +// the program put there (or something a library middleware did). +// ============================================================================ + +// the context parameter of a function the router calls +.decl hb_ctx_param(c0:symbol, c1:symbol) +hb_ctx_param(m, p) :- hr_node_fn(_, _, m), param_decl("client", _, "0", _, m, p). +// an expression that is that context +.decl hb_ctx_ref(c0:symbol, c1:symbol) +hb_ctx_ref(e, m) :- hb_ctx_param(m, p), expr_referenced("client", "PARAMETER", p, e). + +// `c.set(K, v)` / `c.get(K)`: (function, call, key expression) +.decl hb_set_site(c0:symbol, c1:symbol, c2:symbol) +hb_set_site(m, ce, k) :- call_site("client", "METHOD_CALL", "set", _, r, ce, _), hb_ctx_ref(r, m), + expr_child("client", ce, "ARGUMENT", "0", k). +.decl hb_get_site(c0:symbol, c1:symbol, c2:symbol) +hb_get_site(m, ce, k) :- call_site("client", "METHOD_CALL", "get", _, r, ce, _), hb_ctx_ref(r, m), + expr_child("client", ce, "ARGUMENT", "0", k). +rd_demand(k) :- hb_set_site(_, _, k). +rd_demand(k) :- hb_get_site(_, _, k). + +// (function, key, site) +.decl hb_set_at(c0:symbol, c1:symbol, c2:symbol) +hb_set_at(m, key, ce) :- hb_set_site(m, ce, k), rd_val(k, key), !contains("{}", key). +.decl hb_get_at(c0:symbol, c1:symbol, c2:symbol) +hb_get_at(m, key, ce) :- hb_get_site(m, ce, k), rd_val(k, key), !contains("{}", key). +// `c.var.K` +hb_get_at(m, key, e) :- property_access_name(e, key), expr_child("client", e, "RECEIVER", _, v), + property_access_name(v, "var"), expr_child("client", v, "RECEIVER", _, c), hb_ctx_ref(c, m). +// `const { K } = c.var` (and `{ K: x }`): each destructured property is a read of that key, at the `c.var` +hb_get_at(m, key, v) :- ts_variable(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, v, _, _, "true", "PROPERTY", key, _, _, _, _), + hb_var_expr(v, m). +// `c.var`, on a context +.decl hb_var_expr(c0:symbol, c1:symbol) +hb_var_expr(v, m) :- property_access_name(v, "var"), expr_child("client", v, "RECEIVER", _, c), hb_ctx_ref(c, m). +.decl hb_set(c0:symbol, c1:symbol) +hb_set(m, key) :- hb_set_at(m, key, _). +.decl hb_get(c0:symbol, c1:symbol) +hb_get(m, key) :- hb_get_at(m, key, _). +// source order of a site inside its function +.decl hb_site(c0:symbol) +hb_site(e) :- hb_set_at(_, _, e). +hb_site(e) :- hb_get_at(_, _, e). +.decl hb_pos(c0:symbol, c1:number, c2:number) +hb_pos(e, to_number(l), to_number(c)) :- hb_site(e), + ts_expression(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, l, c, _, _, _, _, _, _, _, _, _, _, _, e). +.decl hb_set_before_get(c0:symbol, c1:symbol) +hb_set_before_get(m, key) :- hb_set_at(m, key, s), hb_get_at(m, key, g), hb_pos(s, sl, sc), hb_pos(g, gl, gc), + (sl < gl ; sl = gl, sc < gc). +framework_undetermined(m, "ctx_key", "dynamic_ctx_key") :- hb_set_site(m, _, k), rd_val(k, key), contains("{}", key). +framework_undetermined(m, "ctx_key", "dynamic_ctx_key") :- hb_get_site(m, _, k), rd_val(k, key), contains("{}", key). + +// positions on one chain: (handler, verb, path, function, position); the handler last +.decl hb_chain(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number) +hb_chain(h, vv, p, mw, to_number(pos)) :- middleware_applies(mw, h, vv, p, pos, _). +hb_chain(h, vv, p, h, 100000) :- http_route(h, vv, p, _, _). +// …and on a PARTIAL route (SPEC R23): the key flows along its decided chain (middleware_applies under the partial +// path) whatever the path is. A middleware that only MAY apply (middleware_may_apply) is no position on it. +hb_chain(h, vv, p, h, 100000) :- http_route_partial(h, vv, p, _, _). + +// ctx_key_flow(Setter, Reader, Key) — on some route's chain, Setter runs before Reader +// (or is Reader) and writes the context key Reader reads. +ctx_key_flow(s, r, key) :- hb_set_live(s, key), hb_get(r, key), hb_chain(h, vv, p, s, i), hb_chain(h, vv, p, r, j), i < j. +// a set a middleware makes after calling its `next` runs once every later function on the chain has +// returned: only the middleware itself reads it back (hb_set_before_get) +.decl hb_set_live(c0:symbol, c1:symbol) +hb_set_live(m, key) :- hb_set_at(m, key, ce), !hb_after_next(m, ce). +.decl hb_next_call(c0:symbol, c1:symbol) +hb_next_call(m, nc) :- hb_set_at(m, _, _), param_decl("client", _, "1", _, m, p), expr_referenced("client", "PARAMETER", p, n), + call_callee_expr(_, nc, n). +.decl hb_next_pos(c0:symbol, c1:number, c2:number) +hb_next_pos(nc, to_number(l), to_number(c)) :- hb_next_call(_, nc), + ts_expression(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, l, c, _, _, _, _, _, _, _, _, _, _, _, nc). +.decl hb_after_next(c0:symbol, c1:symbol) +hb_after_next(m, ce) :- hb_set_at(m, _, ce), hb_next_call(m, nc), !hb_next_guarded(nc), hb_next_pos(nc, nl, ncol), hb_pos(ce, sl, sc), + (nl < sl ; nl = sl, ncol < sc). +// a `next()` in a branch, a loop or a try (`if (skip) return next()`) may not have run before a later set +.decl hb_next_up(c0:symbol, c1:symbol, c2:symbol) +hb_next_up(m, nc, b) :- hb_next_call(m, nc), expr_owner("client", "BLOCK", b, _, nc), block_owner("client", m, _, b). +hb_next_up(m, nc, p) :- hb_next_up(m, nc, b), block_parent("client", p, b), block_owner("client", m, _, p). +.decl hb_next_guarded(c0:symbol) +hb_next_guarded(nc) :- hb_next_up(_, nc, b), block_kind("client", k, b), (hr_cond_kind(k) ; hr_loop_kind(k) ; k = "TRY"). +ctx_key_flow(s, s, key) :- hb_set_before_get(s, key), hb_chain(_, _, _, s, _). + +framework_undetermined(r, "ctx_key", "no_setter_on_chain") :- hb_get(r, key), hb_chain(_, _, _, r, _), + !hb_read_served(r, key). +.decl hb_read_served(c0:symbol, c1:symbol) +hb_read_served(r, key) :- ctx_key_flow(_, r, key). diff --git a/graph/typescript/engine/framework-behavior/http-router-ctx-type.dl b/graph/typescript/engine/framework-behavior/http-router-ctx-type.dl new file mode 100644 index 000000000..da1526616 --- /dev/null +++ b/graph/typescript/engine/framework-behavior/http-router-ctx-type.dl @@ -0,0 +1,180 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP ROUTER CONTEXT VALUE TYPES (what a context read holds) +// +// http-router-chain.dl ties a context write to the reads that see it (ctx_key_flow). +// This file gives the READ a type, so a call on the value it returns resolves like a +// call on any typed receiver: +// +// const { keys } = c.get('services') // the type declared for key `services` +// await keys.verify(id) // ... so this reaches KeyService.verify +// c.var.db.query(...) // the same through the `var` view +// +// The type of key k is declared once, in the app's environment type: the first type +// argument of the context type, of the app class, of the factory or of the middleware +// helper (`Context`, `new App()`, `createFactory()`, +// `createMiddleware(fn)`, `MiddlewareHandler`), an object whose +// variables member (knob router_env_vars) lists the keys. The environment is found +// from the context PARAMETER of the function that reads it: +// (a) the parameter is annotated with a type carrying an environment; +// (b) the function is the initializer of a variable annotated with one; +// (c) the function is handed to a call whose first type argument is one +// (knob router_env_call); +// (d) the function is handed to a method call on an app value whose environment is +// known: built with one, declared with one (directly, through an alias, or as +// `ReturnType` of a function returning such an app), or reached through +// the calls that return the app (knob router_returns_app, router_base_path). +// +// Typing only: the rules add expr_type / expr_shape rows, never an edge, so a call on +// the value still goes through the ordinary member lookup and dispatch. Everything here +// is POSITIVE (no negation): it sits in the expr_type fixpoint, and it must not read the +// route table (http_route reads the call graph under negation), which is why app values +// are followed here by their syntax and declarations, not by hr_app. +// ============================================================================ + +// ── an environment type: an object type with a variables member ───────────── +// (env reference, the variables field) +.decl hcx_env_vars(c0:symbol, c1:symbol) +hcx_env_vars(e, fv) :- hr_on(), type_ref("client", _, _, _, _, _, _, e), ref_shape_target(e, o), + declared_field(o, vn, _, fv), router_env_vars(vn). +hcx_env_vars(e, fv) :- hr_on(), type_ref("client", _, _, _, _, _, _, e), ref_type_target(e, _, o), + declared_field(o, vn, _, fv), router_env_vars(vn). + +// ── a type reference that carries an environment as its first argument ────── +// (reference, env reference) +.decl hcx_envref(c0:symbol, c1:symbol) +hcx_envref(r, e) :- type_ref("client", "TYPE_REFERENCE", _, _, _, _, _, r), + type_ref_parent("client", r, "0", e), hcx_env_vars(e, _). +// `type AppContext = Context`, `type App = OpenAPIApp` +hcx_envref(r, e) :- alias_rhs(r, "client", rhs), hcx_envref(rhs, e). +// `type App = ReturnType`: the app the function returns +hcx_envref(r, e) :- hcx_return_of_query(r, f), method_returns_expr(f, x), hcx_app_env(x, e). + +// `ReturnType` (the reference, the function the query names in its module) +.decl hcx_return_of_query(c0:symbol, c1:symbol) +hcx_return_of_query(r, f) :- type_ref("client", "TYPE_REFERENCE", _, rt, _, _, _, r), ts_type_return_operator(rt), + type_ref_parent("client", r, "0", q), type_ref("client", "TYPE_QUERY", _, tn, _, _, _, q), + type_ref_module("client", m, q), scope_name_binds("client", m, tn, _, "METHOD", f). +hcx_return_of_query(r, f) :- type_ref("client", "TYPE_REFERENCE", _, rt, _, _, _, r), ts_type_return_operator(rt), + type_ref_parent("client", r, "0", q), type_ref("client", "TYPE_QUERY", _, tn, _, _, _, q), + type_ref_module("client", m, q), scope_name_binds("client", m, tn, _, "VARIABLE", v), var_is_function(v, f). + +// ── an app value whose environment is known ───────────────────────────────── +// (expression, env reference) +.decl hcx_app_env(c0:symbol, c1:symbol) +// built with it: `new App()`, `createFactory()` +hcx_app_env(x, e) :- hr_new(x), call_type_argument(x, "0", e), hcx_env_vars(e, _). +hcx_app_env(x, e) :- hr_factory_call(x), call_type_argument(x, "0", e), hcx_env_vars(e, _). +// `factory.createApp()`, and every call that returns the app it was called on +hcx_app_env(x, e) :- call_site("client", "METHOD_CALL", cn, _, r, x, _), router_factory_app(cn), hcx_app_env(r, e). +hcx_app_env(x, e) :- call_site("client", "METHOD_CALL", cn, _, r, x, _), router_returns_app(cn), hcx_app_env(r, e). +hcx_app_env(x, e) :- call_site("client", "METHOD_CALL", cn, _, r, x, _), router_base_path(cn), hcx_app_env(r, e). +// parentheses, `await`, casts +hcx_app_env(x, e) :- hcx_app_env(c, e), expr_child("client", x, _, _, c), + expr_kind("client", k, _, x), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +// a variable holding one (here or imported), or declared as one +hcx_app_env(x, e) :- hr_denotes_var(x, v), var_initializer("client", _, i, v), i != "", hcx_app_env(i, e). +hcx_app_env(x, e) :- hr_denotes_var(x, v), var_type_ref("client", r, v), hcx_envref(r, e). +// a parameter declared as one (`app: App`, `app: OpenAPIApp`) +hcx_app_env(x, e) :- expr_referenced("client", "PARAMETER", p, x), param_type_ref("client", r, p), hcx_envref(r, e). +// a call of a project function that returns one (`const app = newApp()`) +hcx_app_env(x, e) :- expr_call_candidate(x, w), method_returns_expr(w, y), hcx_app_env(y, e). + +// ── the environment a function's context parameter has ────────────────────── +// (function, env reference) +.decl hcx_fn_env(c0:symbol, c1:symbol) +// (a) annotated: `(c: Context) => …`, `(c: AppContext) => …` +hcx_fn_env(m, e) :- param_decl("client", _, "0", _, m, p), param_type_ref("client", r, p), hcx_envref(r, e). +// (b) the initializer of a variable declared `MiddlewareHandler` +hcx_fn_env(m, e) :- var_is_function(v, m), var_type_ref("client", r, v), hcx_envref(r, e). +// (b2) returned from a function declared to return one (`function auth(): MiddlewareHandler { return async (c, next) => .. }`) +hcx_fn_env(m, e) :- method_return_ref("client", r, f), hcx_envref(r, e), method_returns_expr(f, x), expr_anon_decl("client", m, x). +// (c) handed to `createMiddleware(fn)` +hcx_fn_env(m, e) :- callback_arg(ce, _, m), call_type_argument(ce, "0", e), hcx_env_vars(e, _), + call_site("client", _, cn, _, _, ce, _), router_env_call(cn). +// (d) handed to a method of an app value with a known environment (a route, a middleware) +hcx_fn_env(m, e) :- callback_arg(ce, _, m), call_site("client", "METHOD_CALL", _, _, r, ce, _), hcx_app_env(r, e). +// …or to a factory's handler helper (`factory.createHandlers(fn)`, `factory.createMiddleware(fn)`) +hcx_fn_env(m, e) :- callback_arg(ce, _, m), call_site("client", "METHOD_CALL", cn, _, r, ce, _), + (router_handler_spread(cn) ; router_factory_mw(cn)), hcx_app_env(r, e). + +// ── the context expression, and its environment ───────────────────────────── +.decl hcx_ctx(c0:symbol, c1:symbol) +hcx_ctx(x, e) :- expr_referenced("client", "PARAMETER", p, x), param_decl("client", _, "0", _, m, p), hcx_fn_env(m, e). + +// the variables object (env reference, the variables field) +// the field of key k (env reference, key, field) +.decl hcx_key_field(c0:symbol, c1:symbol, c2:symbol) +hcx_key_field(e, k, fk) :- hcx_env_vars(e, fv), field_type_ref("client", vr, fv), ref_shape_target(vr, vo), + declared_field(vo, k, _, fk). +hcx_key_field(e, k, fk) :- hcx_env_vars(e, fv), field_type_ref("client", vr, fv), ref_type_target(vr, _, vo), + declared_field(vo, k, _, fk). + +// ── `c.get(k)`: the type declared for k ───────────────────────────────────── +.decl hcx_get(c0:symbol, c1:symbol, c2:symbol) +hcx_get(ce, e, key) :- call_site("client", "METHOD_CALL", gn, _, r, ce, _), router_ctx_get(gn), hcx_ctx(r, e), + expr_child("client", ce, "ARGUMENT", "0", k), expr_literal_value("client", key, k). +expr_type(ce, prov, t) :- hcx_get(ce, e, key), hcx_key_field(e, key, fk), field_type(fk, prov, t). +expr_shape(ce, s) :- hcx_get(ce, e, key), hcx_key_field(e, key, fk), field_shape(fk, s). + +// ── `c.var`: the variables object, so `c.var.k` and `const { k } = c.var` are its members ─ +.decl hcx_var(c0:symbol, c1:symbol) +hcx_var(x, e) :- property_access_recv(x, vn, r), router_ctx_var(vn), hcx_ctx(r, e). +expr_type(x, prov, t) :- hcx_var(x, e), hcx_env_vars(e, fv), field_type(fv, prov, t). +expr_shape(x, s) :- hcx_var(x, e), hcx_env_vars(e, fv), field_shape(fv, s). + +// ── NO ENVIRONMENT DECLARED: the type of what the app's own middleware writes ─ +// `new App()` (or `App`, or a context parameter written `c: any`) declares no key +// types, and the compiler types every read `any`. What the read holds is then what a +// function handed to the SAME app writes under that key (`c.set('orders', new +// OrderService(..))`): the value's type, wherever it is known. Keyed by the app the +// writer and the reader are registered on, never by the key alone, so two apps that use +// one key for different things do not mix. (A write in a parent app read in a sub-app it +// mounts is not followed here: the mount is in the route table, which this stratum may +// not read.) +// (expression, the expression that created the app's route list) +.decl hcx_app_root(c0:symbol, c1:symbol) +hcx_app_root(x, x) :- hr_new(x). +hcx_app_root(x, x) :- hr_factory_call(x). +hcx_app_root(x, a) :- call_site("client", "METHOD_CALL", cn, _, r, x, _), router_factory_app(cn), hcx_app_root(r, a). +hcx_app_root(x, a) :- call_site("client", "METHOD_CALL", cn, _, r, x, _), router_returns_app(cn), hcx_app_root(r, a). +hcx_app_root(x, a) :- call_site("client", "METHOD_CALL", cn, _, r, x, _), router_base_path(cn), hcx_app_root(r, a). +hcx_app_root(x, a) :- hcx_app_root(c, a), expr_child("client", x, _, _, c), + expr_kind("client", k, _, x), (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +hcx_app_root(x, a) :- hr_denotes_var(x, v), var_initializer("client", _, i, v), i != "", hcx_app_root(i, a). +hcx_app_root(x, a) :- expr_call_candidate(x, w), method_returns_expr(w, y), hcx_app_root(y, a). +// (function, app root): a function handed to a method of the app (a route, a middleware) +.decl hcx_fn_root(c0:symbol, c1:symbol) +hcx_fn_root(m, a) :- callback_arg(ce, _, m), call_site("client", "METHOD_CALL", _, _, r, ce, _), hcx_app_root(r, a). +// the context parameter of such a function, typed or not +.decl hcx_ctx_root(c0:symbol, c1:symbol) +hcx_ctx_root(x, a) :- expr_referenced("client", "PARAMETER", p, x), param_decl("client", _, "0", _, m, p), hcx_fn_root(m, a). +// (app root, key, written value) +.decl hcx_set_root(c0:symbol, c1:symbol, c2:symbol) +hcx_set_root(a, key, v) :- call_site("client", "METHOD_CALL", sn, _, r, ce, _), router_ctx_set(sn), hcx_ctx_root(r, a), + expr_child("client", ce, "ARGUMENT", "0", k), expr_literal_value("client", key, k), + expr_child("client", ce, "ARGUMENT", "1", v). +// `c.get(k)` and `c.var.k` on the same app take the written value's type +.decl hcx_read_root(c0:symbol, c1:symbol, c2:symbol) +hcx_read_root(ce, a, key) :- call_site("client", "METHOD_CALL", gn, _, r, ce, _), router_ctx_get(gn), hcx_ctx_root(r, a), + expr_child("client", ce, "ARGUMENT", "0", k), expr_literal_value("client", key, k). +hcx_read_root(x, a, key) :- property_access_recv(x, key, v), property_access_recv(v, vn, r), router_ctx_var(vn), hcx_ctx_root(r, a). +expr_type(x, prov, t) :- hcx_read_root(x, a, key), hcx_set_root(a, key, v), expr_type(v, prov, t). +expr_shape(x, s) :- hcx_read_root(x, a, key), hcx_set_root(a, key, v), expr_shape(v, s). + +// ── `c.req.valid(target)` after a function validator: what the validator returns ── +// `app.post(p, validator('json', (value) => new Role(..)), (c) => c.req.valid('json').toJSON())`: the +// validated value IS the validator function's result. Read off the registration's own arguments (the +// validator before the handler in one call), not off the route table, for the stratum reason above. +.decl hcx_valid_fn(c0:symbol, c1:symbol, c2:symbol) // (registration call, target, validator function) +hcx_valid_fn(rce, t, f) :- expr_child("client", rce, "ARGUMENT", vp, vce), hr_knob_call(vce, spec, n), router_validator_fn(spec, n), + expr_child("client", vce, "ARGUMENT", "0", tx), expr_literal_value("client", t, tx), callback_arg(vce, "1", f), + expr_child("client", rce, "ARGUMENT", hp, _), to_number(vp) < to_number(hp). +.decl hcx_valid_read(c0:symbol, c1:symbol) // (read, validator function) +hcx_valid_read(ce, f) :- hcx_valid_fn(rce, t, f), callback_arg(rce, hp, m), expr_child("client", rce, "ARGUMENT", vp, vce), + hr_knob_call(vce, _, _), to_number(vp) < to_number(hp), + expr_referenced("client", "PARAMETER", p, cx), param_decl("client", _, "0", _, m, p), + property_access_recv(rq, rn, cx), router_ctx_req(rn), + call_site("client", "METHOD_CALL", vn, _, rq, ce, _), router_valid_read(vn), + expr_child("client", ce, "ARGUMENT", "0", tx), expr_literal_value("client", t, tx). +expr_type(ce, prov, t) :- hcx_valid_read(ce, f), method_returns_expr(f, x), expr_kind("client", _, "ROOT", x), expr_type(x, prov, t). +expr_shape(ce, s) :- hcx_valid_read(ce, f), method_returns_expr(f, x), expr_kind("client", _, "ROOT", x), expr_shape(x, s). diff --git a/graph/typescript/engine/framework-behavior/http-router-schema.dl b/graph/typescript/engine/framework-behavior/http-router-schema.dl new file mode 100644 index 000000000..e57b62dca --- /dev/null +++ b/graph/typescript/engine/framework-behavior/http-router-schema.dl @@ -0,0 +1,149 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP ROUTER SCHEMAS (what a route validates, and who reads it) +// +// route_schema(Handler, Target, SchemaDecl) +// the route's request part Target (json, query, param, form, header, cookie) or +// its `response` is validated by the schema declared at SchemaDecl: a variable, +// or the schema expression itself when it is written in place. A schema built from +// another (`Base.extend(..)`, `Base.merge(X)`, `z.array(Base)`, `Base.openapi('N')`) +// carries its bases too, so a change to Base reaches every route that validates +// with something derived from it. +// valid_read(ReadExpr, Handler, Target, SchemaDecl) +// `c.req.valid(Target)` in a route's handler reads what that route's validator for +// Target produced. A read with no validator for its target on the route is declared +// (framework_undetermined `valid_without_validator`). +// +// Two sources: a validator middleware argument (`zValidator('json', S)`, knob +// router_validator) and an OpenAPI route definition's `request` and `responses`. +// ============================================================================ + +// ── (route call, handler, target, schema expression) ──────────────────────── +.decl hs_validates(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hs_validates(ce, h, t, sx) :- hr_harg(ce, _, a), hr_knob_call(a, spec, n), router_validator(spec, n), + expr_child("client", a, "ARGUMENT", "0", tx), rd_val(tx, t), expr_child("client", a, "ARGUMENT", "1", sx), + hr_last(ce, l), hr_node_fn(ce, l, h). +// a function validator validates its target, with no schema +.decl hs_validates_fn(c0:symbol, c1:symbol, c2:symbol) +hs_validates_fn(ce, h, t) :- hr_harg(ce, _, a), hr_knob_call(a, spec, n), router_validator_fn(spec, n), + expr_child("client", a, "ARGUMENT", "0", tx), rd_val(tx, t), hr_last(ce, l), hr_node_fn(ce, l, h). +rd_demand(tx) :- hr_harg(_, _, a), hr_knob_call(a, spec, n), (router_validator(spec, n) ; router_validator_fn(spec, n)), + expr_child("client", a, "ARGUMENT", "0", tx). +// an OpenAPI definition: request.params / query / headers / cookies, request.body's +// content schemas, and every response's content schemas +hs_validates(ce, h, t, sx) :- hr_openapi_def(ce, o), hr_node_fn(ce, 100, h), + rd_obj_prop(o, rk, rq), router_def_key(rk, "request"), rd_obj_prop(rq, k, sx), router_def_request_target(k, t). +hs_validates(ce, h, t, sx) :- hr_openapi_def(ce, o), hr_node_fn(ce, 100, h), + rd_obj_prop(o, rk, rq), router_def_key(rk, "request"), rd_obj_prop(rq, bk, body), router_def_key(bk, "body"), + rd_obj_prop(body, ck, ct), router_def_key(ck, "content"), rd_obj_prop(ct, mime, mt), router_def_body_target(mime, t), + rd_obj_prop(mt, sk, sx), router_def_key(sk, "schema"). +// the definition's responses, one per status entry: under any key, a computed one too +// (`[Status.OK]: ..`), and the entries of a module-level object spread into it (`...errorResponses`) +.decl hs_resp_obj(c0:symbol, c1:symbol) +hs_resp_obj(o, rs) :- hr_openapi_def(_, o), rd_obj_prop(o, rk, rs), router_def_key(rk, "responses"), + expr_kind("client", "OBJECT_LITERAL", _, rs). +hs_resp_obj(o, ro) :- hr_openapi_def(_, o), rd_obj_prop(o, rk, rs), router_def_key(rk, "responses"), + hr_denotes_var(rs, v), rd_init_obj(v, ro). +hs_resp_obj(o, ro) :- hs_resp_obj(o, rs), expr_child("client", rs, _, _, sp), expr_kind("client", "SPREAD_ELEMENT", _, sp), + expr_child("client", sp, _, _, x), hr_denotes_var(x, v), rd_init_obj(v, ro). +hs_resp_obj(o, ro) :- hs_resp_obj(o, rs), expr_child("client", rs, _, _, sp), expr_kind("client", "SPREAD_ELEMENT", _, sp), + expr_child("client", sp, _, _, x), expr_kind("client", "OBJECT_LITERAL", _, x), ro = x. +.decl hs_resp(c0:symbol, c1:symbol) +hs_resp(o, r1) :- hs_resp_obj(o, rs), expr_child("client", rs, "OBJECT_PROPERTY_VALUE", _, r1). +hs_validates(ce, h, "response", sx) :- hr_openapi_def(ce, o), hr_node_fn(ce, 100, h), hs_resp(o, r1), + rd_obj_prop(r1, ck, ct), router_def_key(ck, "content"), rd_obj_prop(ct, _, mt), + rd_obj_prop(mt, sk, sx), router_def_key(sk, "schema"). +// a response or a request body built by a project helper (`200: jsonBody(User, 'ok')` returning `{ content: { +// 'application/json': { schema } } }`, a helper spreading another `{ ...jsonBody(s, d), required: true }`): the +// schema is the argument the outermost call passes for the parameter the innermost object names +.decl hs_hneed(c0:symbol) +hs_hneed(r1) :- hs_resp(_, r1). +hs_hneed(b) :- hr_openapi_def(_, o), rd_obj_prop(o, rk, rq), router_def_key(rk, "request"), rd_obj_prop(rq, bk, b), + router_def_key(bk, "body"). +hs_hneed(ro) :- hs_hneed(x), hr_call_of(x, w), hr_ret_expr(w, ro). +hs_hneed(c) :- hs_hneed(o), expr_kind("client", "OBJECT_LITERAL", _, o), expr_child("client", o, _, _, sp), + expr_kind("client", "SPREAD_ELEMENT", _, sp), expr_child("client", sp, _, _, c). +// (object or call, content type, schema expression, possibly a parameter of the helper) +.decl hs_cs(c0:symbol, c1:symbol, c2:symbol) +hs_cs(o, mime, sx) :- hs_hneed(o), rd_obj_prop(o, ck, ct), router_def_key(ck, "content"), rd_obj_prop(ct, mime, mt), + rd_obj_prop(mt, sk, sx), router_def_key(sk, "schema"). +hs_cs(o, mime, sx) :- hs_hneed(o), expr_kind("client", "OBJECT_LITERAL", _, o), expr_child("client", o, _, _, sp), + expr_kind("client", "SPREAD_ELEMENT", _, sp), expr_child("client", sp, _, _, c), hs_cs(c, mime, sx). +hs_cs(x, mime, sx) :- hs_hneed(x), hr_call_of(x, w), hr_ret_expr(w, ro), hs_cs(ro, mime, sx), !hs_param_of(sx, w, _). +hs_cs(x, mime, ax) :- hs_hneed(x), hr_call_of(x, w), hr_ret_expr(w, ro), hs_cs(ro, mime, px), hs_param_of(px, w, pos), + expr_child("client", x, "ARGUMENT", pos, ax). +.decl hs_param_of(c0:symbol, c1:symbol, c2:symbol) +hs_param_of(px, w, pos) :- hr_on(), expr_referenced("client", "PARAMETER", pp, px), param_decl("client", _, pos, _, w, pp). +.decl hs_is_param(c0:symbol) +hs_is_param(px) :- hr_on(), expr_referenced("client", "PARAMETER", _, px). +hs_validates(ce, h, "response", sx) :- hr_openapi_def(ce, o), hr_node_fn(ce, 100, h), + hs_resp(o, r1), call_site("client", _, _, _, _, r1, _), + hs_cs(r1, _, sx), !hs_is_param(sx). +hs_validates(ce, h, t, sx) :- hr_openapi_def(ce, o), hr_node_fn(ce, 100, h), + rd_obj_prop(o, rk, rq), router_def_key(rk, "request"), rd_obj_prop(rq, bk, b), router_def_key(bk, "body"), + call_site("client", _, _, _, _, b, _), hs_cs(b, mime, sx), router_def_body_target(mime, t), !hs_is_param(sx). + +// ── the declaration a schema expression names ─────────────────────────────── +// (expression, declaration): a const (here, imported, re-exported, a namespace member), +// else the expression itself +.decl hs_decl_var(c0:symbol, c1:symbol) +hs_decl_var(sx, v) :- hs_validates(_, _, _, sx), hr_denotes_var(sx, v). +hs_decl_var(sx, v) :- hs_validates(_, _, _, sx), property_access_name(sx, n), expr_child("client", sx, "RECEIVER", _, r), + expr_referenced("client", "IMPORT_BINDING", ih, r), import_binds_namespace(ih, "client", m), + module_export_any("client", m, n, "VARIABLE", v). +.decl hs_named(c0:symbol) +hs_named(sx) :- hs_decl_var(sx, _). +.decl hs_decl(c0:symbol, c1:symbol) +hs_decl(sx, v) :- hs_decl_var(sx, v). +hs_decl(sx, sx) :- hs_validates(_, _, _, sx), !hs_named(sx). + +// ── composition: a schema and every schema it is built from ───────────────── +// the expressions of a declaration's tree (a variable's initializer, or the expression) +.decl hs_root(c0:symbol, c1:symbol) +hs_root(d, i) :- hs_need(d), var_initializer("client", _, i, d), i != "". +hs_root(d, d) :- hs_need(d), expr_kind("client", _, _, d). +.decl hs_need(c0:symbol) +hs_need(d) :- hs_decl(_, d). +hs_need(b) :- hs_base(_, b). +.decl hs_desc(c0:symbol, c1:symbol) +hs_desc(d, i) :- hs_root(d, i). +hs_desc(d, c) :- hs_desc(d, e), expr_child("client", e, _, _, c). +// a reference to the schema library +.decl hs_lib_ref(c0:symbol) +hs_lib_ref(e) :- hr_on(), expr_referenced("client", "IMPORT_BINDING", ih, e), hr_import_spec(ih, spec), router_schema_module(spec). +// a variable referenced in the tree, which is itself a schema +.decl hs_base_cand(c0:symbol, c1:symbol) +hs_base_cand(d, v) :- hs_desc(d, e), hr_denotes_var(e, v), v != d. +.decl hs_base(c0:symbol, c1:symbol) +hs_base(d, v) :- hs_base_cand(d, v), hs_lib_tree(v). +// (decided without the recursion through hs_base: a candidate is a schema when its own +// tree names the library, or names a variable whose tree does, transitively) +.decl hs_lib_tree(c0:symbol) +hs_lib_tree(v) :- hs_base_cand(_, v), var_initializer("client", _, i, v), i != "", hs_tdesc(i, e), hs_lib_ref(e). +hs_lib_tree(v) :- hs_base_cand(_, v), var_initializer("client", _, i, v), i != "", hs_tdesc(i, e), + hr_denotes_var(e, w), w != v, hs_lib_tree(w). +.decl hs_tdesc(c0:symbol, c1:symbol) +hs_tdesc(i, i) :- hs_base_cand(_, v), var_initializer("client", _, i, v), i != "". +hs_tdesc(i, c) :- hs_tdesc(i, e), expr_child("client", e, _, _, c). +.decl hs_closure(c0:symbol, c1:symbol) +hs_closure(d, d) :- hs_need(d). +hs_closure(d, b) :- hs_closure(d, x), hs_base(x, b). + +// route_schema(Handler, Target, SchemaDecl) — the route's Target is validated by the +// schema declared at SchemaDecl, or by one built from it +route_schema(h, t, b) :- hs_validates(_, h, t, sx), hs_decl(sx, d), hs_closure(d, b). + +// ── `c.req.valid(target)` ─────────────────────────────────────────────────── +.decl hs_read(c0:symbol, c1:symbol, c2:symbol) +hs_read(ce, m, t) :- call_site("client", "METHOD_CALL", vn, _, q, ce, _), router_valid_read(vn), + property_access_name(q, rn), router_ctx_req(rn), expr_child("client", q, "RECEIVER", _, c), hb_ctx_ref(c, m), + expr_child("client", ce, "ARGUMENT", "0", tx), rd_val(tx, t). +rd_demand(tx) :- hr_on(), call_site("client", "METHOD_CALL", vn, _, q, ce, _), router_valid_read(vn), + property_access_name(q, rn), router_ctx_req(rn), expr_child("client", ce, "ARGUMENT", "0", tx). +// valid_read(ReadExpr, Handler, Target, SchemaDecl) — the read gets what the route's +// validator for Target produced +valid_read(ce, h, t, d) :- hs_read(ce, h, t), hs_validates(_, h, t, sx), hs_decl(sx, d). +.decl hs_read_ok(c0:symbol) +hs_read_ok(ce) :- hs_read(ce, h, t), hs_validates(_, h, t, _). +hs_read_ok(ce) :- hs_read(ce, h, t), hs_validates_fn(_, h, t). +framework_undetermined(h, "valid_read", "valid_without_validator") :- hs_read(ce, h, _), !hs_read_ok(ce), + hr_node_fn(_, _, h). diff --git a/graph/typescript/engine/framework-behavior/http-rpc-client.dl b/graph/typescript/engine/framework-behavior/http-rpc-client.dl new file mode 100644 index 000000000..bb51f59fa --- /dev/null +++ b/graph/typescript/engine/framework-behavior/http-rpc-client.dl @@ -0,0 +1,272 @@ +// ============================================================================ +// FRAMEWORK-BEHAVIOR · HTTP RPC CLIENT (a request that names a route of a known app) +// +// Three ways a program sends a request to an app whose route table this engine has +// (config-resolution/http-router-routes.dl), all in one language: +// * `app.request('/items/42', { method })` the app value itself, in a test; +// * `testClient(app).items[':id'].$get()` a client over an app value; +// * `hc(base).users[':id'].$get()` a typed client, where AppType is +// `typeof ` (directly or through a type alias, imported or not). +// Each property is a path segment (`index` adds none, `[':id']` adds the written +// segment) and `$` sends. The send is joined to the route of that app whose full +// path it fits: `exact` when every segment is equal, `route_shape` when a route +// parameter stood in for a written segment; of several, the fewest stand-ins win. +// +// remote_edge(Sender, Handler, "http", " ", Confidence) +// remote_unserved(Sender, "http", " ") a send no route of the app fits +// +// Names (the client functions, the `$verb` methods) live in knobs.dl. +// ============================================================================ + +// ── the app a client is over ──────────────────────────────────────────────── +// (client root expression, app list) +.decl hc_client_root(c0:symbol, c1:symbol) +hc_client_root(ce, a) :- hr_knob_call(ce, spec, n), router_test_client(spec, n), + expr_child("client", ce, "ARGUMENT", "0", x), hr_app(x, a). +// `hc(...)`: T is `typeof v`, or a type alias of it +.decl hc_typed_call(c0:symbol, c1:symbol) +hc_typed_call(ce, r) :- hr_knob_call(ce, spec, n), router_rpc_client(spec, n), + type_ref("client", _, "METHOD_TYPE_ARGUMENT", _, _, ce, _, r), hc_tref_pos0(r). +.decl hc_tref_pos0(c0:symbol) +hc_tref_pos0(r) :- hr_on(), ts_type_reference(_, "METHOD_TYPE_ARGUMENT", _, _, _, _, "0", _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, r). +.decl hc_type_query(c0:symbol, c1:symbol) +hc_type_query(ce, q) :- hc_typed_call(ce, q), type_ref("client", "TYPE_QUERY", _, _, _, _, _, q). +hc_type_query(ce, q) :- hc_typed_call(ce, r), type_ref_resolves("client", r, t), type_alias_target("client", q, t), + type_ref("client", "TYPE_QUERY", _, _, _, _, _, q). +// the variable a type query names: by its name in the module the query is written in +// (the IR does not link a TYPE_QUERY to its variable) +.decl hc_query_var(c0:symbol, c1:symbol) +hc_query_var(ce, v) :- hc_type_query(ce, q), type_ref("client", _, _, tn, _, _, _, q), type_ref_module("client", m, q), + var_decl("client", tn, _, _, _, m, v). +// …or imported into that module under the name (`import { todos } from './api'; hc`) +hc_query_var(ce, v) :- hc_type_query(ce, q), type_ref("client", _, _, tn, _, _, _, q), type_ref_module("client", m, q), + import_binding("client", _, tn, _, m, ih), import_binds(ih, "client", "VARIABLE", v). +hc_client_root(ce, a) :- hc_query_var(ce, v), var_initializer("client", _, i, v), i != "", hr_app(i, a). +rd_demand(p) :- hr_app(r, _), call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_app_request(cn), + expr_child("client", ce, "ARGUMENT", "0", p). + +// ── the path a client expression has accumulated ──────────────────────────── +.decl hc_cpath(c0:symbol, c1:symbol, c2:symbol) +hc_cpath(ce, a, "") :- hc_client_root(ce, a). +hc_cpath(r, a, p) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hc_cpath(i, a, p). +hc_cpath(e, a, p) :- property_access_name(e, n), router_rpc_index(n), expr_child("client", e, "RECEIVER", _, q), + hc_cpath(q, a, p). +hc_cpath(e, a, cat(p, cat("/", n))) :- property_access_name(e, n), !router_rpc_index(n), !router_rpc_verb(n, _), + expr_child("client", e, "RECEIVER", _, q), hc_cpath(q, a, p), strlen(p) < 300. +hc_cpath(e, a, cat(p, cat("/", k))) :- expr_kind("client", "ELEMENT_ACCESS", _, e), expr_child("client", e, "RECEIVER", _, q), + hc_cpath(q, a, p), expr_child("client", e, "INDEX_ARGUMENT", _, x), hc_lit_index(x), expr_literal_value("client", k, x), strlen(p) < 300. +hc_cpath(e, a, cat(p, "/{}")) :- expr_kind("client", "ELEMENT_ACCESS", _, e), expr_child("client", e, "RECEIVER", _, q), + hc_cpath(q, a, p), expr_child("client", e, "INDEX_ARGUMENT", _, x), !hc_lit_index(x), strlen(p) < 300. +.decl hc_lit_index(c0:symbol) +hc_lit_index(x) :- hr_on(), expr_child("client", _, "INDEX_ARGUMENT", _, x), (expr_literal_type("client", "STRING", x) ; expr_literal_type("client", "NO_SUBSTITUTION_TEMPLATE", x)). +hc_cpath(e, a, p) :- hc_cpath(c, a, p), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + expr_kind_is_transparent(k). +// a function that returns a client: each call is that client +hc_cpath(ce, a, p) :- hr_call_of(ce, w), method_returns_expr(w, e), hc_cpath(e, a, p). +// A BUNDLE OF CLIENTS: an object literal whose members are clients, or functions returning one +// (`{ health: hc(..), config: (id) => hc(`../${id}/config`) }`), returned by a factory and +// kept in a variable; `bundle.health.$get()` and `bundle.config(id).identity.$put()` are sends +.decl hc_objval(c0:symbol) +hc_objval(v) :- hc_cpath(v, _, _). +hc_objval(v) :- expr_anon_decl("client", m, v), hr_ret_expr(m, r), hc_cpath(r, _, _). +.decl hc_obj(c0:symbol, c1:symbol) +hc_obj(o, o) :- rd_obj_prop(o, _, v), hc_objval(v). +hc_obj(r, o) :- hr_denotes_var(r, v), var_initializer("client", _, i, v), i != "", hc_obj(i, o). +hc_obj(r, o) :- hr_denotes_var(r, v), var_reassigned_value(v, i), hc_obj(i, o). +hc_obj(ce, o) :- hr_call_of(ce, w), hr_ret_expr(w, e), hc_obj(e, o). +hc_obj(e, o) :- hc_obj(c, o), expr_child("client", e, _, _, c), expr_kind("client", k, _, e), + (expr_kind_is_transparent(k) ; k = "AWAIT_EXPRESSION"). +hc_cpath(e, a, p) :- property_access_name(e, n), expr_child("client", e, "RECEIVER", _, q), hc_obj(q, o), + rd_obj_prop(o, n, v), hc_cpath(v, a, p). +hc_cpath(ce, a, p) :- call_site("client", "METHOD_CALL", n, _, q, ce, _), hc_obj(q, o), rd_obj_prop(o, n, fv), + expr_anon_decl("client", m, fv), hr_ret_expr(m, r), hc_cpath(r, a, p). + +// ── the sends: (site, sender, app, verb, path) ────────────────────────────── +.decl hc_send(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol) +hc_send(ce, from, a, vv, p) :- call_site("client", "METHOD_CALL", cn, _, q, ce, _), router_rpc_verb(cn, vv), + hc_cpath(q, a, p0), p0 != "", p = p0, expr_enclosing_method(ce, from). +hc_send(ce, from, a, vv, "/") :- call_site("client", "METHOD_CALL", cn, _, q, ce, _), router_rpc_verb(cn, vv), + hc_cpath(q, a, ""), expr_enclosing_method(ce, from). +// `app.request(path, init?)`: GET unless the init names a method +.decl hc_req(c0:symbol, c1:symbol, c2:symbol) +hc_req(ce, a, p) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_app_request(cn), hr_app(r, a), + expr_child("client", ce, "ARGUMENT", "0", x), rd_val(x, raw), strlen(raw) >= 1, substr(raw, 0, 1) = "/", + hc_strip(raw, p), !hc_preq_any(ce). +// an init the request does not write in place (a parameter, a parsed value), or one whose method is computed: the +// verb is not decidable (SPEC ruling R17), so the send stands for every verb (`*`) and joins as method_unknown +.decl hc_req_mu(c0:symbol) +hc_req_mu(ce) :- hc_req(ce, _, _), expr_child("client", ce, "ARGUMENT", "1", o), !expr_kind("client", "OBJECT_LITERAL", _, o). +hc_req_mu(ce) :- hc_req(ce, _, _), expr_child("client", ce, "ARGUMENT", "1", o), rd_obj_prop(o, key, _), ts_http_init_method_key(key), + !hc_req_has_method(ce). +// A TEST HELPER that requests the path it is handed (`async function hit(path, init?) { return app.request(path, init) }`): +// one send per call of the helper, its path and init that call's arguments. (request, helper, path position) +.decl hc_preq(c0:symbol, c1:symbol, c2:symbol) +hc_preq(ce, w, pos) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_app_request(cn), hr_app(r, _), + expr_child("client", ce, "ARGUMENT", "0", x), expr_referenced("client", "PARAMETER", pp, x), param_decl("client", _, pos, _, w, pp), + expr_enclosing_method(ce, w). +.decl hc_preq_any(c0:symbol) +hc_preq_any(ce) :- hc_preq(ce, _, _). +rd_demand(ax) :- hc_preq(_, w, pos), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, ax). +// (call of the helper, request, app, path) +.decl hc_preq_at(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hc_preq_at(oc, ce, a, p) :- hc_preq(ce, w, pos), call_site("client", _, _, _, r, ce, _), hr_app(r, a), hr_call_of(oc, w), + expr_child("client", oc, "ARGUMENT", pos, ax), rd_val(ax, raw), strlen(raw) >= 1, substr(raw, 0, 1) = "/", hc_strip(raw, p). +hc_strip_need(raw) :- hc_preq(_, w, pos), hr_call_of(oc, w), expr_child("client", oc, "ARGUMENT", pos, ax), rd_val(ax, raw), + strlen(raw) >= 1, substr(raw, 0, 1) = "/". +// the init that call hands it: none (GET), an object literal (its literal method, or GET), anything else (`*`) +.decl hc_preq_init(c0:symbol, c1:symbol, c2:symbol) +hc_preq_init(oc, ce, ia) :- hc_preq_at(oc, ce, _, _), expr_child("client", ce, "ARGUMENT", "1", x1), expr_referenced("client", "PARAMETER", ip, x1), + param_decl("client", _, ipos, _, _, ip), expr_child("client", oc, "ARGUMENT", ipos, ia). +// …or the init the helper writes in place (`app.request(path, { method: 'POST', body })`): the same for every call +hc_preq_init(oc, ce, x1) :- hc_preq_at(oc, ce, _, _), expr_child("client", ce, "ARGUMENT", "1", x1), !expr_referenced("client", "PARAMETER", _, x1). +.decl hc_preq_has_init(c0:symbol, c1:symbol) +hc_preq_has_init(oc, ce) :- hc_preq_init(oc, ce, _). +.decl hc_preq_verb(c0:symbol, c1:symbol, c2:symbol) +hc_preq_verb(oc, ce, "GET") :- hc_preq_at(oc, ce, _, _), !expr_child("client", ce, "ARGUMENT", "1", _). +hc_preq_verb(oc, ce, "GET") :- hc_preq_at(oc, ce, _, _), expr_child("client", ce, "ARGUMENT", "1", _), !hc_preq_has_init(oc, ce). +hc_preq_verb(oc, ce, vv) :- hc_preq_init(oc, ce, o), rd_obj_prop(o, key, val), ts_http_init_method_key(key), + expr_literal_value("client", w, val), ts_http_verb_name(w, vv). +hc_preq_verb(oc, ce, "GET") :- hc_preq_init(oc, ce, o), expr_kind("client", "OBJECT_LITERAL", _, o), !hc_obj_has_method_key(o). +hc_preq_verb(oc, ce, "*") :- hc_preq_init(oc, ce, o), !expr_kind("client", "OBJECT_LITERAL", _, o). +// …a method key whose value is not a literal verb: not decidable (SPEC ruling R17) +hc_preq_verb(oc, ce, "*") :- hc_preq_init(oc, ce, o), hc_obj_has_method_key(o), !hc_obj_lit_method(o). +.decl hc_obj_lit_method(c0:symbol) +hc_obj_lit_method(o) :- hc_preq_init(_, _, o), rd_obj_prop(o, key, val), ts_http_init_method_key(key), expr_literal_value("client", w, val), + ts_http_verb_name(w, _). +.decl hc_obj_has_method_key(c0:symbol) +hc_obj_has_method_key(o) :- hc_preq_init(_, _, o), rd_obj_prop(o, key, _), ts_http_init_method_key(key). +hc_send(oc, from, a, vv, p) :- hc_preq_at(oc, ce, a, p), hc_preq_verb(oc, ce, vv), expr_enclosing_method(ce, from). +.decl hc_req_method(c0:symbol, c1:symbol) +hc_req_method(ce, vv) :- hc_req(ce, _, _), expr_child("client", ce, "ARGUMENT", "1", o), rd_obj_prop(o, key, val), + ts_http_init_method_key(key), expr_literal_value("client", w, val), ts_http_verb_name(w, vv). +.decl hc_req_has_method(c0:symbol) +hc_req_has_method(ce) :- hc_req_method(ce, _). +hc_send(ce, from, a, vv, p) :- hc_req(ce, a, p), hc_req_method(ce, vv), expr_enclosing_method(ce, from). +hc_send(ce, from, a, "*", p) :- hc_req(ce, a, p), hc_req_mu(ce), expr_enclosing_method(ce, from). +// `app.request(new Request(url, init?))` / `app.fetch(new Request(url, init?), env)`: the +// URL's path (scheme and host dropped), the verb from the request's init +.decl hc_reqobj(c0:symbol, c1:symbol, c2:symbol) +hc_reqobj(ce, a, nq) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), (router_app_request(cn) ; router_app_fetch(cn)), + hr_app(r, a), expr_child("client", ce, "ARGUMENT", "0", nq), + call_site("client", "CONSTRUCTOR_CALL", rc, _, _, nq, _), router_request_class(rc). +rd_demand(u) :- hc_reqobj(_, _, nq), expr_child("client", nq, "ARGUMENT", "0", u). +.decl hc_reqobj_url(c0:symbol, c1:symbol) +hc_reqobj_url(ce, url) :- hc_reqobj(ce, _, nq), expr_child("client", nq, "ARGUMENT", "0", u), rd_val(u, url). +.decl hc_url_sch(c0:symbol, c1:number) +hc_url_sch(url, i) :- (hc_reqobj_url(_, url) ; hc_req_abs(_, _, url)), strlen(url) >= 3, i = range(0, strlen(url) - 2), substr(url, i, 3) = "://". +.decl hc_url_after(c0:symbol, c1:symbol) +hc_url_after(url, r) :- hc_url_sch(url, _), i = min x : { hc_url_sch(url, x) }, r = substr(url, i + 3, strlen(url) - i - 3). +.decl hc_url_slash(c0:symbol, c1:number) +hc_url_slash(r, i) :- hc_url_after(_, r), i = range(0, strlen(r)), substr(r, i, 1) = "/". +.decl hc_url_path(c0:symbol, c1:symbol) +hc_url_full(url, p) :- hc_url_after(url, r), m = min x : { hc_url_slash(r, x) }, p = substr(r, m, strlen(r) - m). +hc_url_full(url, "/") :- hc_url_after(url, r), !hc_url_slash(r, _). +hc_url_full(url, url) :- hc_reqobj_url(_, url), strlen(url) >= 1, substr(url, 0, 1) = "/". +hc_url_path(url, p) :- hc_url_full(url, raw), hc_strip(raw, p). +// a request's query string and fragment are not part of the path (SPEC ruling R9): `/x?path=…` +// and `/x#top` are requests for `/x` +.decl hc_url_full(c0:symbol, c1:symbol) +.decl hc_strip_need(c0:symbol) +hc_strip_need(raw) :- hc_url_full(_, raw). +hc_strip_need(raw) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_app_request(cn), hr_app(r, _), + expr_child("client", ce, "ARGUMENT", "0", x), rd_val(x, raw), strlen(raw) >= 1, substr(raw, 0, 1) = "/". +.decl hc_cut(c0:symbol, c1:number) +hc_cut(raw, i) :- hc_strip_need(raw), i = range(0, strlen(raw)), (substr(raw, i, 1) = "?" ; substr(raw, i, 1) = "#"). +.decl hc_strip(c0:symbol, c1:symbol) +hc_strip(raw, raw) :- hc_strip_need(raw), !hc_cut(raw, _). +hc_strip(raw, p) :- hc_strip_need(raw), m = min i : { hc_cut(raw, i) }, p0 = substr(raw, 0, m), + ((p0 = "", p = "/") ; (p0 != "", p = p0)). + +.decl hc_reqobj_method(c0:symbol, c1:symbol) +hc_reqobj_method(ce, vv) :- hc_reqobj(ce, _, nq), expr_child("client", nq, "ARGUMENT", "1", o), rd_obj_prop(o, key, val), + ts_http_init_method_key(key), expr_literal_value("client", w, val), ts_http_verb_name(w, vv). +.decl hc_reqobj_has_method(c0:symbol) +hc_reqobj_has_method(ce) :- hc_reqobj_method(ce, _). +hc_send(ce, from, a, vv, p) :- hc_reqobj(ce, a, _), hc_reqobj_url(ce, url), hc_url_path(url, p), !contains("{}", p), + hc_reqobj_method(ce, vv), expr_enclosing_method(ce, from). +hc_send(ce, from, a, "GET", p) :- hc_reqobj(ce, a, _), hc_reqobj_url(ce, url), hc_url_path(url, p), !contains("{}", p), + !hc_reqobj_has_method(ce), expr_enclosing_method(ce, from). +hc_send(ce, from, a, "GET", p) :- hc_req(ce, a, p), !hc_req_has_method(ce), !hc_req_mu(ce), expr_enclosing_method(ce, from). +// `app.request('http://localhost/x')`: the URL's path +.decl hc_req_abs(c0:symbol, c1:symbol, c2:symbol) +hc_req_abs(ce, a, url) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), router_app_request(cn), hr_app(r, a), + expr_child("client", ce, "ARGUMENT", "0", x), rd_val(x, url), contains("://", url). +hc_req(ce, a, p) :- hc_req_abs(ce, a, url), hc_url_path(url, p). + +// ── the routes a send may reach: those of the app's root, under its prefix ── +// (app, verb, full path relative to the app, handler) +.decl hc_app_route(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +// The app a send names is flattened AS IF it were served on its own: a request sent to a +// sub-app (`subApp.request('/posts')`, `hc`) is answered by its routes relative +// to it, not by the mounting app's full paths. Same flattening as http-router-routes.dl. +.decl hc_target(c0:symbol) +hc_target(a) :- hc_send(_, _, a, _, _). +.decl hc_flat(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:symbol, c5:symbol) +hc_flat(a, a, "/", "", "", "") :- hc_target(a). +hc_flat(r, s, np, nk, cut, cm) :- hc_flat(r, a, p, kp, _, _), hr_inc(a, s, site, pre, kd), kd != "mount_each", + hr_merge(p, pre, np), hr_key(site, k), nk = cat(kp, cat(k, ".")), strlen(nk) < 160, hr_cutoff(site, cut, cm). +hc_flat(r, s, np, nk, "", "") :- hc_flat(r, a, p, kp, _, _), hr_inc(a, s, site, pre, "mount_each"), hr_each_ord(site, s, o), + hr_merge(p, pre, np), hr_key(site, k), nk = cat(kp, cat(k, cat("~", cat(o, ".")))), strlen(nk) < 160. +hr_mreq(p, pre) :- hc_flat(_, a, p, _, _, _), hr_inc(a, _, _, pre, _). +.decl hc_fcand(c0:symbol, c1:symbol, c2:symbol, c3:symbol, c4:number, c5:symbol) +hc_fcand(r, vv, p, ce, n, pre) :- hc_flat(r, a, pre, _, "", _), hr_entry(a, _, "route", vv, p, ce, n). +hc_fcand(r, vv, p, ce, n, pre) :- hc_flat(r, a, pre, _, cut, _), cut != "", hr_entry(a, k, "route", vv, p, ce, n), k < cut. +hc_fcand(r, vv, p, ce, n, pre) :- hc_flat(r, a, pre, _, cut, cm), cut != "", hr_entry(a, _, "route", vv, p, ce, n), + expr_module("client", em, ce), em != cm. +hr_mreq(pre, p) :- hc_fcand(_, _, p, _, _, pre). +hc_app_route(a, vv, fp, h) :- hc_fcand(a, vv, p, ce, n, pre), hr_last(ce, n), hr_route_node(ce, n, h), + hr_merge(pre, p, fp), !contains("{}", fp). + +// segments of both ends +.decl hc_path(c0:symbol) +hc_path(p) :- hc_send(_, _, _, _, p). +hc_path(p) :- hc_app_route(_, _, p, _). +.decl hc_slash(c0:symbol, c1:number) +hc_slash(p, i) :- hc_path(p), i = range(0, strlen(p)), substr(p, i, 1) = "/". +.decl hc_next(c0:symbol, c1:number, c2:number) +hc_next(p, i, j) :- hc_slash(p, i), j = min x : { hc_slash(p, x), x > i }. +.decl hc_has_next(c0:symbol, c1:number) +hc_has_next(p, i) :- hc_next(p, i, _). +.decl hc_seg_at(c0:symbol, c1:number, c2:symbol) +hc_seg_at(p, i, t) :- hc_next(p, i, j), t = substr(p, i + 1, j - i - 1). +hc_seg_at(p, i, t) :- hc_slash(p, i), !hc_has_next(p, i), t = substr(p, i + 1, strlen(p) - i - 1). +.decl hc_seg_ne(c0:symbol, c1:number) +hc_seg_ne(p, i) :- hc_seg_at(p, i, t), t != "". +.decl hc_seg(c0:symbol, c1:number, c2:symbol) +hc_seg(p, k, t) :- hc_seg_at(p, i, t), t != "", k = count : { hc_seg_ne(p, x), x < i }. +.decl hc_nseg(c0:symbol, c1:number) +hc_nseg(p, n) :- hc_path(p), n = count : { hc_seg(p, _, _) }. +.decl hc_param(c0:symbol) +hc_param(t) :- hc_seg(_, _, t), substr(t, 0, 1) = ":". +hc_param("*"). +// a computed segment of a send (`${id}`) is one segment of anything +.decl hc_hole(c0:symbol) +hc_hole(x) :- hc_seg(_, _, x), contains("{}", x). + +// a send fits a route of the same app: same segment count, each written segment equal or +// under a route parameter; the verb equal, or the route's ANY +.decl hc_pair(c0:symbol, c1:symbol, c2:symbol, c3:symbol) +hc_pair(ce, h, p, rp) :- hc_send(ce, _, a, sv, p), hc_app_route(a, rv, rp, h), (rv = sv ; rv = "ANY" ; sv = "*"), + hc_nseg(p, n), hc_nseg(rp, n). +.decl hc_conflict(c0:symbol, c1:symbol) +hc_conflict(p, rp) :- hc_pair(_, _, p, rp), hc_seg(p, k, x), hc_seg(rp, k, y), x != y, !hc_param(y), !hc_hole(x). +.decl hc_ndiff(c0:symbol, c1:symbol, c2:number) +hc_ndiff(p, rp, n) :- hc_pair(_, _, p, rp), !hc_conflict(p, rp), n = count : { hc_seg(p, k, x), hc_seg(rp, k, y), x != y }. +.decl hc_best(c0:symbol, c1:number) +hc_best(ce, b) :- hc_pair(ce, _, p, _), hc_ndiff(p, _, _), b = min n : { hc_pair(ce, _, p2, rp2), hc_ndiff(p2, rp2, n) }. + +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "exact") :- hc_send(ce, from, _, sv, p), sv != "*", hc_pair(ce, h, p, rp), + hc_ndiff(p, rp, 0), hc_best(ce, 0), from != h. +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "route_shape") :- hc_send(ce, from, _, sv, p), sv != "*", hc_pair(ce, h, p, rp), + hc_ndiff(p, rp, n), n > 0, hc_best(ce, n), from != h. +// a send with a computed segment can be any request of its shape: every route it fits +remote_edge(from, h, "http", cat(sv, cat(" ", p)), "route_shape") :- hc_send(ce, from, _, sv, p), sv != "*", contains("{}", p), + hc_pair(ce, h, p, rp), hc_ndiff(p, rp, n), n > 0, from != h. +// a send whose verb is not decidable: every route of any verb its path fits best (SPEC ruling R17) +remote_edge(from, h, "http", cat("* ", p), conf) :- hc_send(ce, from, _, "*", p), hc_pair(ce, h, p, rp), + hc_ndiff(p, rp, n), (hc_best(ce, n) ; contains("{}", p)), from != h, ts_remote_confidence_method_unknown(conf). +.decl hc_served(c0:symbol) +hc_served(ce) :- hc_best(ce, _). +remote_unserved(from, "http", cat(sv, cat(" ", p))) :- hc_send(ce, from, _, sv, p), !contains("{}", p), !hc_served(ce). +// a send with a computed segment that no route fits: where it goes is not known here +remote_undetermined(from, "http", "dynamic_rpc_path") :- hc_send(ce, from, _, _, p), contains("{}", p), !hc_served(ce). diff --git a/graph/typescript/engine/resolution/dynamic-import.dl b/graph/typescript/engine/resolution/dynamic-import.dl new file mode 100644 index 000000000..a8aaf30d2 --- /dev/null +++ b/graph/typescript/engine/resolution/dynamic-import.dl @@ -0,0 +1,61 @@ +// ============================================================================ +// RESOLUTION · DYNAMIC IMPORTS (what `await import('./m')` loads) +// +// `const { x } = await import('./m.ts')` binds x to module m's export x, exactly as +// `import { x } from './m.ts'` would. Test suites write it this way so a mock is in +// place before the module runs; nothing else in the engine read it, so every value the +// test took from the module (an app, a factory, a handler) had no origin. +// +// dynamic_import_module(Call, Module) the module an import() call loads +// var_dynamic_import_binding(Var, Kind, Entity) a destructured name and the export it takes +// +// The specifier must be a string literal. A relative one is joined to the importing +// file's directory (`./`, any number of `../`) and tried as written and with each source +// extension; a bare one resolves wherever a static import of the same specifier does. +// ============================================================================ + +.decl dyn_import_spec(c0:symbol, c1:symbol, c2:symbol) +dyn_import_spec(ce, spec, p) :- call_site("client", "DYNAMIC_IMPORT_CALL", _, _, _, ce, _), + expr_child("client", ce, "ARGUMENT", "0", a), expr_literal_value("client", spec, a), spec != "", + expr_module("client", mod, ce), module_file("client", p, mod). + +// the directory a path is in, with its trailing `/` ("" at the root) +.decl dyn_dir_of(c0:symbol, c1:symbol) +.decl dyn_dir_need(c0:symbol) +dyn_dir_need(p) :- dyn_import_spec(_, _, p). +.decl dyn_slash(c0:symbol, c1:number) +dyn_slash(p, i) :- dyn_dir_need(p), i = range(0, strlen(p)), substr(p, i, 1) = "/". +dyn_dir_of(p, d) :- dyn_dir_need(p), dyn_slash(p, _), i = max x : { dyn_slash(p, x) }, d = substr(p, 0, i + 1). +dyn_dir_of(p, "") :- dyn_dir_need(p), !dyn_slash(p, _). + +// (call, directory, rest of the specifier): `./` stays, each `../` climbs one directory +.decl dyn_rel(c0:symbol, c1:symbol, c2:symbol) +dyn_rel(ce, d, spec) :- dyn_import_spec(ce, spec, p), substr(spec, 0, 1) = ".", dyn_dir_of(p, d). +dyn_rel(ce, d, r) :- dyn_rel(ce, d, s), strlen(s) > 2, substr(s, 0, 2) = "./", r = substr(s, 2, strlen(s) - 2). +dyn_rel(ce, up, r) :- dyn_rel(ce, d, s), strlen(s) > 3, substr(s, 0, 3) = "../", dyn_parent(d, up), + r = substr(s, 3, strlen(s) - 3). +.decl dyn_parent_need(c0:symbol) +dyn_parent_need(d) :- dyn_rel(_, d, s), strlen(s) > 3, substr(s, 0, 3) = "../", d != "". +// (no aggregate here: the climb is recursive, so the parent is the prefix up to the slash that +// has no other slash after it) +.decl dyn_parent(c0:symbol, c1:symbol) +dyn_parent(d, up) :- dyn_parent_need(d), i = range(0, strlen(d) - 1), substr(d, i, 1) = "/", + !contains("/", substr(d, i + 1, strlen(d) - i - 2)), up = substr(d, 0, i + 1). +dyn_parent(d, "") :- dyn_parent_need(d), !contains("/", substr(d, 0, strlen(d) - 1)). + +.decl dynamic_import_module(c0:symbol, c1:symbol) +dynamic_import_module(ce, m) :- dyn_rel(ce, d, r), substr(r, 0, 1) != ".", module_file("client", cat(d, r), m). +dynamic_import_module(ce, m) :- dyn_rel(ce, d, r), substr(r, 0, 1) != ".", ts_source_extension(ext), + module_file("client", cat(cat(d, r), ext), m). +dynamic_import_module(ce, m) :- dyn_import_spec(ce, spec, _), substr(spec, 0, 1) != ".", + specifier_global_target(spec, "client", m). + +// the value an initializer takes from an import() call: the call itself, or its awaited result +.decl dyn_import_value(c0:symbol, c1:symbol) +dyn_import_value(ce, ce) :- dynamic_import_module(ce, _). +dyn_import_value(e, ce) :- dynamic_import_module(ce, _), expr_child("client", e, _, _, ce), + expr_kind("client", "AWAIT_EXPRESSION", _, e). + +.decl var_dynamic_import_binding(c0:symbol, c1:symbol, c2:symbol) +var_dynamic_import_binding(v, k, ent) :- var_binding("client", _, "PROPERTY", src, e, v), e != "", + dyn_import_value(e, ce), dynamic_import_module(ce, m), module_export_any("client", m, src, k, ent). diff --git a/graph/typescript/engine/resolution/element-values.dl b/graph/typescript/engine/resolution/element-values.dl new file mode 100644 index 000000000..ada71b4e3 --- /dev/null +++ b/graph/typescript/engine/resolution/element-values.dl @@ -0,0 +1,42 @@ +// ============================================================================ +// Resolution · TYPES THAT ARRIVE AS AN ELEMENT (SPEC R19, framework-free) +// +// The no-library clauses in contextual-params.dl type a callback's element parameter from +// the RECEIVER'S DECLARED REFERENCE (`xs: Role[]`, `getItems(): Role[]`). Three readings of +// the same reference were missing, and each left a parameter or a binding untyped: +// +// * a call whose function declares no return type gives back what it returns: +// `roles() { return this.entries }` then `ledger.roles().map((r) => r.toJSON())`; +// * the element-taking members of a built-in container hand back one element: +// `pairs.shift()!`, `pairs.pop()`, `pairs.at(0)`, `pairs.find(..)`; +// * an array pattern over a value whose reference is a tuple binds the member at its +// position: `const [, first] = pairs.shift()!` binds `first` to the tuple's member 1. +// +// References only, positive, inside the expr_type fixpoint like the rules they extend. +// ============================================================================ +.decl elem_taking_member(c0:symbol) +elem_taking_member("shift"). elem_taking_member("pop"). elem_taking_member("at"). +elem_taking_member("find"). elem_taking_member("findLast"). + +// a call of a function with no declared return: the reference of what it returns +expr_decl_ref(e, r) :- expr_call_candidate(e, callee), + !method_declares_return(callee), + method_returns_expr(callee, x), + expr_kind("client", _, "ROOT", x), + expr_decl_ref(x, r). +// `xs.shift()`: one element of a built-in container +expr_decl_ref(e, c) :- call_site("client", "METHOD_CALL", n, _, recv, e, _), + elem_taking_member(n), + expr_decl_ref(recv, rr), + builtin_elem_ref(rr, c). +// `x!`, `(x)`: the same reference +expr_decl_ref(e, r) :- expr_kind("client", k, _, e), (k = "NON_NULL_EXPRESSION" ; k = "PARENTHESIZED_EXPRESSION"), + expr_child("client", e, _, _, x), + expr_decl_ref(x, r). +// `const [, first] = `: the member at the bound position +var_type(v, prov, t) :- var_binding("client", _, "INDEX", i, e, v), e != "", + !var_has_declared_type(v), + expr_decl_ref(e, tr), + type_ref(_, "TUPLE", _, _, _, _, _, tr), + type_ref_parent(_, tr, i, mr), + ref_type_target(mr, prov, t). diff --git a/graph/typescript/engine/resolution/lexical-this.dl b/graph/typescript/engine/resolution/lexical-this.dl new file mode 100644 index 000000000..2843cdb3c --- /dev/null +++ b/graph/typescript/engine/resolution/lexical-this.dl @@ -0,0 +1,33 @@ +// ============================================================================ +// Resolution · LEXICAL `this` (an arrow function has no `this` of its own) +// +// `this` inside an arrow is the `this` of the nearest enclosing function that is NOT an +// arrow, at any depth: `static fail(e) { return e.issues.map((i) => this.norm(i)) }` calls +// the class's static `norm`. expr-type.dl decides "this is the class, search the statics" +// from the flags of the function the expression sits in, and for a `this` written inside +// the arrow that function is the arrow, which is never static, so the call was searched in +// the instance table and found nothing. Same for a declared `this` parameter of the outer +// function. The instance type of `this` is unaffected: expr_enclosing_type already names +// the class for an expression at any depth inside it. +// ============================================================================ + +.decl lx_arrow(c0:symbol, c1:symbol) +// (arrow declaration, the expression that writes it) +lx_arrow(lm, x) :- expr_anon_decl("client", lm, x), expr_kind("client", "ARROW_FUNCTION", _, x). +// the function `this` is bound by, for a function: itself unless it is an arrow +.decl lx_home(c0:symbol, c1:symbol) +lx_home(m, m) :- method_decl("client", _, _, _, m), !lx_arrow(m, _). +lx_home(lm, h) :- lx_arrow(lm, x), expr_enclosing_method(x, m), m != lm, lx_home(m, h). + +// `this` in an arrow nested in a STATIC method is the class +expr_static_type(e, "client", t) :- this_expr(e), + expr_enclosing_type(e, t), + expr_enclosing_method(e, em), + lx_arrow(em, _), + lx_home(em, h), + method_flags(_, "true", _, _, h). +// …and in an arrow nested in a function that declares its `this` parameter +expr_type(e, prov, t) :- this_expr(e), expr_enclosing_method(e, em), lx_arrow(em, _), lx_home(em, h), + method_declared_this(h, p), param_type(p, prov, t). +expr_shape(e, s) :- this_expr(e), expr_enclosing_method(e, em), lx_arrow(em, _), lx_home(em, h), + method_declared_this(h, p), param_shape_target(p, s). diff --git a/graph/typescript/engine/resolution/reference-types.dl b/graph/typescript/engine/resolution/reference-types.dl index 04b5345bb..013f53eda 100644 --- a/graph/typescript/engine/resolution/reference-types.dl +++ b/graph/typescript/engine/resolution/reference-types.dl @@ -202,6 +202,7 @@ var_type(v, prov, t) :- var_initializer("client", _, e, v), var_shape(v, s) :- var_initializer("client", _, e, v), e != "", !var_has_declared_type(v), + !var_is_destructured(v), expr_shape(e, s). // `const s = "text"` and friends — a literal initializer types the variable by its diff --git a/graph/typescript/engine/resolution/shape-members.dl b/graph/typescript/engine/resolution/shape-members.dl new file mode 100644 index 000000000..cfca70ec8 --- /dev/null +++ b/graph/typescript/engine/resolution/shape-members.dl @@ -0,0 +1,40 @@ +// ============================================================================ +// Resolution · MEMBERS OF AN ANONYMOUS SHAPE (a shape's field is a value too) +// +// An object type written in place (`{ keys: KeyService; db: { primary: Db } }`) owns +// its members through the type-reference row (ref_shape_target). A property access on +// a shape-typed receiver already gives the member's NAMED type (expr-type.dl), but two +// readings of the same member had no rule: +// +// * the member is itself a shape: `services.db.primary` -- `services.db` had no shape, +// so `.primary` and everything below it was untyped; +// * the member is DESTRUCTURED out of a shape-typed value: `const { keys } = services` +// -- var_binding_target reads expr_type only, so a name bound out of a shape had no +// type at all, while `services.keys` one line up resolved. +// +// Both are the shape mirror of rules that exist for a named owner (expr-type.dl's +// field_shape clause, reference-types.dl's var_binding_target), and read the same +// member tables. Positive and inside the expr_type fixpoint, like their mirrors. +// ============================================================================ + +// `services.db` where `services` is a shape and `db` is declared with an object type +expr_shape(e, s) :- property_access_recv(e, n, q), + expr_shape(q, qs), + field_in_scope(qs, n, _, f), + field_shape(f, s). +expr_decl_ref(e, r) :- property_access_recv(e, n, q), + expr_shape(q, qs), + field_in_scope(qs, n, _, f), + field_type_ref(_, r, f). + +// `const { keys, db } = services` where `services` is a shape +var_type(v, prov, ft) :- var_binding("client", _, "PROPERTY", src, e, v), + e != "", + expr_shape(e, s), + field_in_scope(s, src, _, f), + field_type(f, prov, ft). +var_shape(v, sh) :- var_binding("client", _, "PROPERTY", src, e, v), + e != "", + expr_shape(e, s), + field_in_scope(s, src, _, f), + field_shape(f, sh). diff --git a/graph/typescript/engine/resolution/value-flow.dl b/graph/typescript/engine/resolution/value-flow.dl index acc74483b..e05dffcc6 100644 --- a/graph/typescript/engine/resolution/value-flow.dl +++ b/graph/typescript/engine/resolution/value-flow.dl @@ -782,6 +782,7 @@ holder_elem_fn(h, m) :- holder_value(h, e), // ── the reads ─────────────────────────────────────────────────────────────── // `h[i]`, `h[kind]`: any element (an index or a computed key picks one we cannot) elem_read_fn(x, m) :- expr_kind("client", "ELEMENT_ACCESS", _, x), + !elem_key_is_decided(x), expr_child("client", x, "RECEIVER", _, r), expr_holder(r, h), holder_elem_fn(h, m). @@ -837,5 +838,75 @@ array_method_element_param("every", "0"). array_method_element_param("reduce", "1"). array_method_element_param("reduceRight", "1"). -// `h[i](x)`, `h.run(x)` -call_runs(ce, m) :- call_callee_expr(_, ce, ne), elem_read_fn(ne, m). +// `h[i](x)`, `h.run(x)` -- and, for an element access, only when its key is decided (SPEC R21a): a table +// read with a key the program computes (`handlers[op](x)`) can run any element, so the call stays unknown +// and the elements stay reachable from it only as its candidates (elem_call_candidate), never as calls it makes +call_runs(ce, m) :- call_callee_expr(_, ce, ne), elem_read_fn(ne, m), !elem_key_undecided(ne). +elem_key_undecided(x) :- expr_kind("client", "ELEMENT_ACCESS", _, x), !elem_key_is_decided(x). +elem_call_candidate(ce, m) :- call_callee_expr(_, ce, ne), elem_key_undecided(ne), elem_read_fn(ne, m). +// …and where the table is TYPED (`const factories: { [k: string]: (n: number) => Shape }`), the call resolves to the +// call signature of its element type: each element is then a `value` candidate of that signature, the tier that says +// "may run" (SPEC R21a), not a call the site makes +method_dispatch_candidate(sig, m, "value") :- elem_call_candidate(ce, m), + expr_resolves_to_method(ce, sig), + method_kind(_, k, _, sig), + method_kind_is_call_signature(k), + m != sig. + +// loop_elem_callee(Call, Method) — `for (const g of groups) g.prefix(v)` where `groups` is a const array literal of typed +// elements (`[new UserRoutes()]`): the method of each element's class. A value fact the call graph does not draw +// (the loop variable's declared type is the elements' union, which it leaves ambiguous); read by the string +// evaluation only. +loop_elem_callee(ce, w) :- call_site("client", "METHOD_CALL", cn, _, r, ce, _), expr_referenced("client", "VARIABLE", v, r), + for_binding_iterable(v, it), expr_referenced("client", "VARIABLE", d, it), var_initializer("client", _, arr, d), + expr_kind("client", "ARRAY_LITERAL", _, arr), expr_child("client", arr, _, _, el), expr_type(el, _, tt), method_in_scope(tt, cn, _, w), + !call_chain_edge(ce, _, "-", _, "client", _, _). + +// ── a DECIDED key picks its own element (SPEC R21a) ───────────────────────── +.decl elem_key_decided(c0:symbol, c1:symbol) +.decl elem_key_is_decided(c0:symbol) +.decl elem_key_undecided(c0:symbol) +.decl elem_value_fn(c0:symbol, c1:symbol) +.decl elem_call_candidate(c0:symbol, c1:symbol) // (call, function): a table read with an undecided key may run it +// `handlers['archive'](id)`, `handlers[ACTION](id)` with `const ACTION = 'restore'`, and +// `pipeline[1](id)` name ONE element of a literal the holder holds. Joining them to every +// element ran `purge` from a call that can only run `archive`. A key written as a literal, +// or a const initialised with one, is decided; it selects the property of that name of an +// object literal, or the element at that position of an array literal, and nothing else. +// A key that is not decided still reaches every element (the rule above), as a dispatch +// candidate of a call that stays unknown. +// (element access, the key) +elem_key_decided(x, k) :- expr_kind("client", "ELEMENT_ACCESS", _, x), + expr_child("client", x, "INDEX_ARGUMENT", _, i), + expr_kind("client", "LITERAL", _, i), + expr_literal_value("client", k, i). +elem_key_decided(x, k) :- expr_kind("client", "ELEMENT_ACCESS", _, x), + expr_child("client", x, "INDEX_ARGUMENT", _, i), + expr_literal_type("client", "NO_SUBSTITUTION_TEMPLATE", i), + expr_literal_value("client", k, i). +elem_key_decided(x, k) :- expr_kind("client", "ELEMENT_ACCESS", _, x), + expr_child("client", x, "INDEX_ARGUMENT", _, i), + expr_referenced("client", "VARIABLE", v, i), + !var_reassigned(v), + var_initializer("client", _, li, v), + expr_kind("client", "LITERAL", _, li), + expr_literal_value("client", k, li). +elem_key_is_decided(x) :- elem_key_decided(x, _). +// the property of that name / the element at that position +elem_read_fn(x, m) :- elem_key_decided(x, k), + expr_child("client", x, "RECEIVER", _, r), + expr_holder(r, h), + holder_value(h, e), + value_branch(e, l), + objlit_prop(l, k, val), + elem_value_fn(val, m). +elem_read_fn(x, m) :- elem_key_decided(x, k), + expr_child("client", x, "RECEIVER", _, r), + expr_holder(r, h), + holder_value(h, e), + value_branch(e, l), + expr_kind("client", "ARRAY_LITERAL", _, l), + expr_child("client", l, "ARRAY_ELEMENT", k, val), + elem_value_fn(val, m). +elem_value_fn(val, m) :- !expr_kind("client", "CALL_EXPRESSION", _, val), expr_callable(val, m). +elem_value_fn(val, m) :- expr_holder(val, h2), holder_holds_function(h2, m). diff --git a/graph/typescript/souffle/decls_all.dl b/graph/typescript/souffle/decls_all.dl index be835f2c9..cd8d54e95 100644 --- a/graph/typescript/souffle/decls_all.dl +++ b/graph/typescript/souffle/decls_all.dl @@ -371,6 +371,7 @@ .decl method_has_rest(c0:symbol) .decl method_has_unknown_call(c0:symbol,c1:symbol) .decl method_in_scope(c0:symbol,c1:symbol,c2:symbol,c3:symbol) +.decl loop_elem_callee(c0:symbol,c1:symbol) .decl method_is_client_body(c0:symbol) .decl method_kind(c0:symbol,c1:symbol,c2:symbol,c3:symbol) .decl method_kind_is_call_signature(c0:symbol) @@ -781,3 +782,18 @@ .decl sat_source_method(c0:symbol,c1:symbol,c2:symbol) .decl sat_target_method(c0:symbol,c1:symbol,c2:symbol) .decl sat_visible_source_method(c0:symbol,c1:symbol) +.decl http_route(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol) +.decl http_route_partial(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol) +.decl http_mount(c0:symbol,c1:symbol,c2:symbol,c3:symbol) +.decl middleware_applies(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol,c5:symbol) +.decl middleware_may_apply(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol,c5:symbol) +.decl middleware_site(c0:symbol,c1:symbol,c2:symbol,c3:symbol) +.decl middleware_registered_at(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol,c5:symbol) +.decl http_served_by(c0:symbol,c1:symbol,c2:symbol) +.decl router_node_at(c0:symbol,c1:symbol,c2:symbol,c3:symbol) +.decl registration_conditional(c0:symbol,c1:symbol) +.decl framework_undetermined(c0:symbol,c1:symbol,c2:symbol) +.decl ctx_key_flow(c0:symbol,c1:symbol,c2:symbol) +.decl route_registered_by(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol) +.decl route_schema(c0:symbol,c1:symbol,c2:symbol) +.decl valid_read(c0:symbol,c1:symbol,c2:symbol,c3:symbol) diff --git a/graph/typescript/souffle/export_manifest.tsv b/graph/typescript/souffle/export_manifest.tsv index f9e9ca385..0c951316c 100644 --- a/graph/typescript/souffle/export_manifest.tsv +++ b/graph/typescript/souffle/export_manifest.tsv @@ -56,3 +56,18 @@ remote_unserved remote-unserved.csv remote_unsent remote-unsent.csv remote_undetermined remote-undetermined.csv dispatch_assumes_closed_world assumption-dispatch-closed-world.csv +http_route http-route.csv +http_route_partial http-route-partial.csv +http_mount http-mount.csv +middleware_applies middleware-applies.csv +middleware_may_apply middleware-may-apply.csv +middleware_site middleware-site.csv +middleware_registered_at middleware-registered-at.csv +http_served_by http-served-by.csv +router_node_at router-node-at.csv +registration_conditional registration-conditional.csv +framework_undetermined framework-undetermined.csv +ctx_key_flow ctx-key-flow.csv +route_schema route-schema.csv +valid_read valid-read.csv +route_registered_by route-registered-by.csv diff --git a/plugins/axiomcode/skills/axiomcode/scripts/ax_blocks.py b/plugins/axiomcode/skills/axiomcode/scripts/ax_blocks.py index c20053e78..19427acab 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/ax_blocks.py +++ b/plugins/axiomcode/skills/axiomcode/scripts/ax_blocks.py @@ -192,7 +192,7 @@ def is_lead(p): f"(confirmed callers; no code shown): " + ', '.join(refs[:8]) + (f" +{len(refs) - 8}" if len(refs) > 8 else '')) other = grep_others(repo, names, {(p['f'], n) for p in plain for n in p['marks']}) if other: out.append(f" {other} other line(s) grep matches for that name are NOT this declaration (another symbol of the same name, or text)") - if not out: return None + if not out and not doc.get('router'): return None if len(places) > CAP: out.append(f"… {len(places) - CAP} more place(s) not shown — ask a narrower question to see them") # a bound: line is the answer saying where it stops being complete — an agent writing "only X reaches this" # from these places needs it as much as the verified: line, so it is never tidied away here. @@ -200,7 +200,10 @@ def is_lead(p): kept = [x for x in foot if x.startswith(('verified', 'bound:'))][:3] out += kept + unknown(doc, repo) + [x for x in foot if x.startswith('run:')][:1] # what the question resolved to goes first (ax_grep.head): the places are a page of the answer, not all of it - return ax_grep.head({'tests': 'test-impact'}.get(verb, verb), doc) + out + # an HTTP router's answer (impact's `router` lines: the routes a function registers, the apps it creates, the + # chain before a handler, the context keys a middleware sets): the route table speaks before the places + rt = [str(x) for x in (doc.get('router') or [])] + return ax_grep.head({'tests': 'test-impact'}.get(verb, verb), doc) + rt + out UNKNOWN_SHOWN = 5 # unresolved sites listed under an answer: the nearest; the verbs' --json carries up to 30 diff --git a/plugins/axiomcode/skills/axiomcode/scripts/ax_edges.py b/plugins/axiomcode/skills/axiomcode/scripts/ax_edges.py index 98764b89a..dce8841a8 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/ax_edges.py +++ b/plugins/axiomcode/skills/axiomcode/scripts/ax_edges.py @@ -47,6 +47,7 @@ 'dispatch': 2, # a base method to an override that is actually instantiated 'overload': 0, # the overload signature a call selected runs its set's implementation: one body, certain 'callback_registered': 3, # handed over as a value and invoked by whoever holds it + 'callback_handed': 3, # handed to a project function whose body can run it 'event_dispatch': 3, # emitted here, handled there 'asserted': 3, # a link someone recorded (axiomcode link) where the engine resolved nothing: read, not derived 'remote': 5, # a request crosses a process to its handler (remote_edge): no call site names it. @@ -71,6 +72,7 @@ 'dispatch': 'a base method to an override the project instantiates', 'overload': 'the call selected an overload signature; this is the implementation that runs', 'callback_registered': 'handed over as a value and invoked by whoever holds it', + 'callback_handed': 'handed to a project function whose body can run it', 'event_dispatch': 'emitted here, handled there', 'asserted': 'ASSERTED by a link (axiomcode-links.tsv): someone read the call and recorded its target; the engine did not resolve it', 'remote': 'NOT a call site: a request crosses a process to the handler that serves it (transport and destination on the hop)', @@ -179,7 +181,7 @@ def legend(tiers): 'implicit_constructor': 'resolved', 'written': 'resolved', 'known_implicit_ctor': 'resolved', 'known_builtin_operator': 'resolved', 'runtime_observed': 'resolved', 'multi_inferred': 'one of a set', - 'callback_registered': 'registered', 'event_dispatch': 'registered', + 'callback_registered': 'registered', 'callback_handed': 'registered', 'event_dispatch': 'registered', 'ambient_terminal': 'registered', 'dynamic_terminal': 'registered', 'intrinsic_terminal': 'registered', 'fan_capped': 'capped set', 'asserted': 'asserted', # a link someone recorded (ax_links.py): an edge, never `resolved` diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-context b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-context index 160637dc7..df420db32 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-context +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-context @@ -354,10 +354,365 @@ def _route_parts(r): return [('*' if (p.startswith('{') or p.startswith(':') or p.startswith('<') or p == '*') else p) for p in r.strip('/').split('/') if p] +def _holes_match(a, hp): + """Whether the asked segments `a` are the route parts `hp`, where None is a hole of any number of segments and + every other part is the same segment (a parameter `*` only for a parameter).""" + if not hp: return not a + if hp[0] is None: return any(_holes_match(a[i:], hp[1:]) for i in range(len(a) + 1)) + return bool(a) and a[0] == hp[0] and _holes_match(a[1:], hp[1:]) + + def _route_eq(a, b): return len(a) == len(b) and all(x == y or '*' in (x, y) for x, y in zip(a, b)) +VERB_ROUTE = re.compile(r'(?i)\b(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|ANY|ALL)\s+(/[^\s"\'`,;)]*|\*(?=[\s"\'`,;)]|$))') + + +def node_at(g, x): + """(file, line, what) of a router node that is not a call site (an app held in a parameter or a field, a served + default export), from ext_router_node_at; None when the engine wrote no row.""" + if not g.has('ext_router_node_at'): return None + try: r = g.q("SELECT c1, c2, c3 FROM ext_router_node_at WHERE c0 = ?", x) + except Exception: r = [] + if not r: return None + f, l, what = r[0] + try: p = g.q("SELECT rel FROM paths WHERE raw = ?", f) + except Exception: p = [] + return ((p[0][0] if p and p[0][0] else f), l, what) + + +def route_table_lines(g, text, cap=8): + """The ROUTE TABLE's answer to a quoted route, printed before any ranked code (SPEC 8.1 (a)/(b)): one line per + route the engine composed (ext_http_route) or could only partly compose (ext_http_route_partial), then the chain + the router runs for it on that app, in order (ext_middleware_applies). Nothing here is a text match: a line is + printed only for a row the engine wrote.""" + if not g.has('ext_http_route'): return [] + asked = [] + for m in VERB_ROUTE.finditer(text or ''): + asked.append((m.group(1).upper(), _route_parts(m.group(2)))) + if not asked: + for m in ROUTE.finditer(text or ''): + tok = m.group(1) + if tok.startswith('/') and not FILE_EXT.search(tok.rstrip('/')): asked.append((None, _route_parts(tok))) + if not asked: return [] + def vok(want, v): return want is None or v == want or v == 'ANY' or (want in ('ANY', 'ALL')) + def loc(x): return g.loc(x) if x in g.sym else None + def name(x): + if x in g.sym: return f"{g.disp(x)} {g.loc(x) or ''}".rstrip() + try: + cs = g.q("SELECT c2, c3 FROM ext_middleware_site WHERE c0 = ?", x) if g.has('ext_middleware_site') else [] + except Exception: + cs = [] + try: vk = g.q("SELECT c2 FROM ext_middleware_site WHERE c0 = ? AND c1 = 'value'", x) if g.has('ext_middleware_site') else [] + except Exception: vk = [] + if vk and vk[0][0]: return f"{vk[0][0]} (value)" + if cs and cs[0][0]: return f"{cs[0][0]}() from {cs[0][1]} (library middleware)" + try: st = g.q("SELECT callee_name, file, start_line FROM sites WHERE id = ?", x) + except Exception: st = [] + if st: return f"{st[0][0]}() at {st[0][1]}:{st[0][2]} (library middleware)" + n = node_at(g, x) + if n: return f"a middleware value at {n[0]}:{n[1]}" + return 'a middleware value the engine could not name' + # a catch-all asked as `GET *` is the route written `*` (or `/*`), not every one-segment route + def fits(w, a, path): + if a == ['*']: return path.strip() in ('*', '/*') + return _route_eq(_route_parts(path), a) + rows = [r for r in g.q("SELECT c0, c1, c2, c3, c4 FROM ext_http_route") + if any(vok(w, r[1]) and fits(w, a, r[2]) for w, a in asked)] + out = [] + roots = {r[3] for r in rows} + undet, cond = set(), set() + if g.has('ext_framework_undetermined'): + for r in g.q("SELECT c0, c1, c2 FROM ext_framework_undetermined"): + if r[1] == 'middleware_chain': undet.add(r[0]) + if r[2] in ('conditional_registration', 'loop_registration'): cond.add((r[0], r[2])) + def app_name(a): + try: r = g.q("SELECT file, start_line FROM sites WHERE id = ?", a) + except Exception: r = [] + if r: return f"{r[0][0]}:{r[0][1]}" + n = node_at(g, a) + return (f"{n[0]}:{n[1]}" + (f" ({n[2]})" if n[2] != 'expression' else '')) if n else a + # a library middleware has no function to carry the conditional row: the registering call that puts it in this + # chain (middleware_registered_at) says whether it sits in a branch or a loop (registration_conditional) + def regcond(mw, h, v, p, app): + if not (g.has('ext_middleware_registered_at') and g.has('ext_registration_conditional')): return [] + try: + rcs = {r[0] for r in g.q("SELECT c5 FROM ext_middleware_registered_at WHERE c0 = ? AND c1 = ? AND c2 = ? AND c3 = ? AND c4 = ?", mw, h, v, p, app)} + # only an app-level `use(..)`: a route's own middleware runs whenever the route is served + rcs = {rc for rc in rcs if any(r[0] == 'use' for r in g.q("SELECT callee_name FROM sites WHERE id = ?", rc))} + return sorted({r[1] for rc in rcs for r in g.q("SELECT c0, c1 FROM ext_registration_conditional WHERE c0 = ?", rc)} + & {'conditional_registration', 'loop_registration'}) + except Exception: return [] + def is_test(h): return bool((g.sym.get(h) or {}).get('is_test')) + # a handler with no name of its own (the function a wrapper returns, `traced('x', handleX)`): the registering + # call the engine attributes the route to (route_registered_by), as written, names what it wraps + def reg_line(h, v, p, app): + if not (g.has('ext_route_registered_by') and name(h).startswith('<')): return None + try: rms = {r[0] for r in g.q("SELECT c0 FROM ext_route_registered_by WHERE c1 = ? AND c2 = ? AND c3 = ? AND c4 = ?", h, v, p, app)} + except Exception: return None + files = set() + for rm in rms: + if rm in g.sym and g.loc(rm): files.add(g.loc(rm).rsplit(':', 1)[0]) + else: + n_ = node_at(g, rm) + if n_: files.add(n_[0]) + segs = [x for x in p.split('/') if x] + best = [] + for f in files: + # a chained call starts where the chain does: look through its whole span, the innermost call wins + try: st = g.q("SELECT start_line, end_line FROM sites WHERE file = ? AND callee_name IN (?, 'all', 'on')", f, v.lower()) + except Exception: st = [] + lines = source_lines(g.repo, f) + for l0, l1 in st: + l0 = int(l0); l1 = int(l1 or l0) + for ln in range(l0, min(l1, l0 + 40) + 1): + t = lines[ln - 1] if 0 < ln <= len(lines) else '' + k = max((j for j in range(1, len(segs) + 1) if any(f"{q}/{'/'.join(segs[-j:])}{q}" in t for q in '"\'`')), default=0) + if not k and p.strip() in ('/', '') and any(f"{q}/{q}" in t for q in '"\'`'): k = 1 + if k: best.append((-k, l1 - l0, f, ln, t.strip())) + best = sorted(set(best)) + if not best or (len(best) > 1 and best[0][:2] == best[1][:2] and best[0][2:4] != best[1][2:4]): return None + _k, _span, f, ln, t = best[0] + return f" registered at {f}:{ln}: {t[:160]}" + asked_lit = {'/'.join(a) for _w, a in asked} + # the order the router tries them: the served (non-test) apps first, then per app in registration order; a route + # spelled exactly as asked is never cut off by the cap + TESTISH = re.compile(r'(^|/)(tests?|__tests__|e2e)/|[._-](test|spec)\.[cm]?[jt]sx?$') + def app_test(a): return bool(TESTISH.search(app_name(a).rsplit(':', 1)[0])) + exact_apps = {r[3] for r in rows if '/'.join(_route_parts(r[2])) in {'/'.join(a) for _w, a in asked}} + ordered = sorted({tuple(r) for r in rows}, key=lambda r: (app_test(r[3]) or is_test(r[0]), r[3] not in exact_apps, app_name(r[3]), r[4])) + shown = [r for r in ordered[:cap]] + [r for r in ordered[cap:] if '/'.join(_route_parts(r[2])) in asked_lit] + # one block per distinct (route, chain): apps a helper builds per call share one creating expression, and the + # same block repeated once per call says nothing new (hono-3-06) + blocks, order_ = {}, [] + for h, v, p, app, _k in shown: + why = [w for (x, w) in cond if x == h] + head = (f"route: {v} {p} -> {name(h)}" + + ''.join(' (conditional: registered inside a branch, may not be served)' if w == 'conditional_registration' + else ' (registered inside a loop)' for w in sorted(why))) + body_ = [] + rl = reg_line(h, v, p, app) + if rl: body_.append(rl) + chain = [] + if g.has('ext_middleware_applies'): + try: + chain = g.q("SELECT c0, c4 FROM ext_middleware_applies WHERE c1 = ? AND c2 = ? AND c3 = ? AND c5 = ?", h, v, p, app) + except Exception: + chain = g.q("SELECT c0, c4 FROM ext_middleware_applies WHERE c1 = ? AND c2 = ? AND c3 = ?", h, v, p) + chain = sorted({(int(c[1]) if str(c[1]).isdigit() else 0, c[0]) for c in chain}) + if chain: + body_.append(f" runs, in order:") + # two middleware at ONE position are alternatives (an if/else registering one each): same number + nums = {q: k for k, q in enumerate(sorted({c[0] for c in chain}), 1)} + npos = collections.Counter(c[0] for c in chain) + for _i, (_pos, mw) in enumerate(chain, 1): + i = nums[_pos] + cw = sorted(w for (x, w) in cond if x == mw) or regcond(mw, h, v, p, app) + body_.append(f" {i}. {name(mw)}" + (' (one of the alternatives at this position)' if npos[_pos] > 1 else '') + ''.join(' (conditional: registered inside a branch, may not run)' if w == 'conditional_registration' + else ' (registered inside a loop)' for w in cw)) + body_.append(f" {len(nums) + 1}. {name(h)} (the handler)") + if h in undet: body_.append(" order among the known middleware; a list the engine could not read may add more at run time") + else: + body_.append(" no middleware" + ("; a list the engine could not read may add some at run time" if h in undet else '')) + key = (head, tuple(body_)) + if key not in blocks: blocks[key] = []; order_.append(key) + blocks[key].append(app_name(app)) + for key in order_: + apps_ = blocks[key] + uniq = sorted(set(apps_)) + if len(roots) > 1: + tag = (f" (app {uniq[0]})" if len(apps_) == 1 else + f" ({len(apps_)} apps built at {uniq[0]})" if len(uniq) == 1 else + f" (apps {', '.join(uniq[:3])}" + (f" +{len(uniq) - 3}" if len(uniq) > 3 else '') + ")") + else: tag = '' + out.append(key[0] + tag) + out.extend(key[1]) + if g.has('ext_http_route_partial'): + # SPEC 8.1(a): the partial whose KNOWN tail is the asked path comes first, then the ones that match it only + # through parameters and holes (`/{}/:action`), each with what is decided of its chain and what may run + hitp = [] + for h, v, p, app, why in sorted({tuple(r) for r in g.q("SELECT c0, c1, c2, c3, c4 FROM ext_http_route_partial")}): + # a hole (`{}`) is a part of the path decided at run time: any number of segments, before the known tail + # or between two known parts (`/v1/{}/ping`) + hp0 = [None if x == '\x00' else x for x in _route_parts(p.replace('{}', '\x00'))] + while hp0 and hp0[0] is None: hp0 = hp0[1:] + # an optional last parameter (`:module?`) may be left off by the request + hps = [hp0] + ([hp0[:-1]] if hp0 and hp0[-1] is not None and p.rstrip('/').endswith('?') and len(hp0) > 1 else []) + best = None + for (w, a), hp in [(x, k) for x in asked for k in hps]: + kp = [x for x in hp if x is not None] + if not (vok(w, v) and len(a) >= len(kp) and kp): continue + # a parameter the question writes stands for a parameter of the route, never for one of its literal + # segments, and at least one literal segment must be the same: `/files` is no answer to `/x/:module` + if not _holes_match(a, [None] + hp): continue + lit = sum(1 for y in kp if y != '*') + if not lit: continue + rank = (0 if len(kp) == len(a) else 1, -lit, len(a) - len(kp)) + best = rank if best is None or rank < best else best + if best is not None: hitp.append((best, is_test(h), p, v, h, app, why)) + hitp.sort(key=lambda r: (r[0], r[1], r[2], r[3])) + # one block per (route, known path, chain): several apps (a holder's two creating expressions, an app value + # nothing resolves) answering it alike are one answer, their reasons listed together + pblocks, porder = {}, [] + for rk, _t, p, v, h, app, why in hitp: + chain = [] + if g.has('ext_middleware_applies'): + chain = sorted({(int(c[1]) if str(c[1]).isdigit() else 0, c[0]) for c in + g.q("SELECT c0, c4 FROM ext_middleware_applies WHERE c1 = ? AND c2 = ? AND c3 = ? AND c5 = ?", h, v, p, app)}) + may = sorted({(r[0], r[1]) for r in g.q("SELECT c0, c4 FROM ext_middleware_may_apply WHERE c1 = ? AND c3 = ? AND c5 = ?", h, p, app)}) \ + if g.has('ext_middleware_may_apply') else [] + key = (v, p, h, tuple(m for _p, m in chain), tuple(may)) + if key not in pblocks: pblocks[key] = (rk, set(), app); porder.append(key) + pblocks[key][1].add(why) + exact_n = sum(1 for k in porder if pblocks[k][0][0] == 0 and pblocks[k][0][1] == -len(_route_parts(k[1].replace('{}', '')))) + pcap = max(cap, exact_n) + for v, p, h, chain, may in porder[:pcap]: + whys = ', '.join(sorted(w.replace('_', ' ') for w in pblocks[(v, p, h, chain, may)][1])) + why_c = [w for (x, w) in cond if x == h] + out.append(f"route: {v} {p} -> {name(h)} (prefix not known: {whys})" + + ''.join(' (conditional: registered inside a branch, may not be served)' if w == 'conditional_registration' + else ' (registered inside a loop)' for w in sorted(why_c))) + if chain: + out.append(" runs, in order (what is decided on its own app):") + for i, mw in enumerate(chain, 1): + cw = sorted(w for (x, w) in cond if x == mw) or regcond(mw, h, v, p, pblocks[(v, p, h, chain, may)][2]) + out.append(f" {i}. {name(mw)}" + ''.join(' (conditional: registered inside a branch, may not run)' + if w == 'conditional_registration' else ' (registered inside a loop)' for w in cw)) + out.append(f" {len(chain) + 1}. {name(h)} (the handler)") + if h in undet: out.append(" order among the known middleware; a list the engine could not read may add more at run time") + elif h in undet: out.append(" a middleware list the engine could not read may run before it at run time") + for mw, q in may: + out.append(f" {name(mw)} may run (scope {q} vs unknown prefix)") + if len(porder) > pcap: out.append(f" ... +{len(porder) - pcap} more route(s) whose prefix is not known could match it") + return out + + +def mount_lines(g, text, cap=8): + """`what path does analyticsRouter serve`: an app named in the question by the variable that holds it, and the + prefix every mount of it composes (http_mount, the EFFECTIVE prefix through every basePath and mount), with the + routes it serves there. Only a variable whose initializer created a mounted app is answered.""" + if not (g.has('ext_http_mount') and g.has('symbols')): return [] + out = [] + try: + mounts = g.q("SELECT m.c0, m.c1, m.c2, s.file, s.start_line FROM ext_http_mount m JOIN sites s ON s.id = m.c1") + except Exception: + return [] + words = set(re.findall(r'[A-Za-z_$][\w$]*', text or '')) + for w in sorted(words): + if len(w) < 3: continue + try: vs = g.q("SELECT file, line, end_line FROM symbols WHERE name = ? AND kind IN ('const', 'let', 'var', 'field', 'property')", w) + except Exception: vs = [] + for f, l0, l1 in vs: + l1 = l1 or l0 + hit = sorted({(m[2], m[0]) for m in mounts if m[3] == f and l0 <= m[4] <= l1}) + for pre, parent in hit[:cap]: + try: pr = g.q("SELECT file, start_line FROM sites WHERE id = ?", parent) + except Exception: pr = [] + n_ = None if pr else node_at(g, parent) + pn = f"{pr[0][0]}:{pr[0][1]}" if pr else ((f"{n_[0]}:{n_[1]}" + (f" ({n_[2]})" if n_[2] != 'expression' else '')) if n_ else parent) + out.append(f"mount: {w} ({f}:{l0}) is served under {pre} (mounted on the app at {pn})") + try: + rs = g.q("""SELECT DISTINCT r.c1, r.c2, s.display, s.file, s.line FROM ext_http_route r JOIN symbols s ON s.method_id = r.c0 + WHERE s.file = ? AND (r.c2 = ? OR r.c2 LIKE ?) ORDER BY r.c4""", f, pre, pre.rstrip('/') + '/%') + except Exception: rs = [] + for v, p_, d, hf, hl in rs[:cap]: out.append(f" serves {v} {p_} -> {d} {hf}:{hl}") + if len(rs) > cap: out.append(f" ... +{len(rs) - cap} more") + return out + + +STOP = set('a an and are does do for from how is it of on or the this that to what when where which who whom why with route routes ' + 'serve serves served call calls reach reaches path paths run runs before after middleware handler request ' + 'app apps http get post put delete patch any all use'.split()) + + +def worded_route_lines(g, text, cap=6): + """A route question with no quoted path (`which route does apiClient.kb.admin general-knowledge $post call`, `who + serves the users list route`): the routes, composed or partial, whose literal path segments or handler file name + carry at least two of the question's words, a `$verb` narrowing the verb. Labelled as a word match, never as the + route table's answer to a quoted route.""" + if not g.has('ext_http_route') or VERB_ROUTE.search(text or ''): return [] + vm = re.search(r'\$(get|post|put|delete|patch|options|head)\b', text or '', re.I) + verb = vm.group(1).upper() if vm else None + words = {w.lower() for w in re.findall(r'[A-Za-z][\w-]*', (text or '').replace('$', ' ').replace('.', ' ').replace('[', ' ').replace(']', ' '))} + words = {w for w in words if w not in STOP and len(w) > 1} + if len(words) < 2: return [] + def segs(p): return {x.lower() for x in p.split('/') if x and not x.startswith(':') and '{' not in x and x != '*'} + rows = [(h, v, p, '') for h, v, p in g.q("SELECT DISTINCT c0, c1, c2 FROM ext_http_route")] + if g.has('ext_http_route_partial'): + rows += [(h, v, p, why) for h, v, p, why in g.q("SELECT DISTINCT c0, c1, c2, c4 FROM ext_http_route_partial")] + scored = [] + for h, v, p, why in rows: + if verb and v not in (verb, 'ANY'): continue + f = ((g.sym.get(h) or {}).get('file') or '').lower() + fw = set(re.findall(r'[a-z][a-z0-9-]*', f.rsplit('/', 1)[-1])) | set(re.findall(r'[a-z][a-z0-9-]*', f)) + # the handler's own name (`export const list = ...` serves the users LIST route) + fw |= {x.lower() for x in re.findall(r'[A-Za-z][a-z0-9]*', (g.sym.get(h) or {}).get('name') or '')} + hit = (segs(p) & words) | (fw & words if why else set()) + if len(hit) >= 2 or (len(hit) == len(segs(p) & words) == len(segs(p)) and len(hit) >= 2): + scored.append((-len(hit), bool((g.sym.get(h) or {}).get('is_test')), p, v, h, why)) + out = [] + for _n, _t, p, v, h, why in sorted(set(scored))[:cap]: + nm = f"{g.disp(h)} {g.loc(h) or ''}".rstrip() if h in g.sym else h + out.append(f"route (by the question's words): {v} {p} -> {nm}" + (f" (prefix not known: {why.replace('_', ' ')})" if why else '')) + return out + + +# a question about how a request gets IN (not "who serves GET /x", which the route table answers) +SERVE_WORDS = re.compile(r'(?i)\b(reach(es)?|entry|entries|fetch|request[s]?|start[s]?|listen[s]?|boot[s]?)\b') +SERVED_HOW = {'default_export_fetch': 'the default export { fetch }', 'default_export': 'the default export', 'fetch_handed': "its fetch handed to", + 'request': 'a request sent in place'} + + +def served_lines(g, text, cap=6): + """`how does a request reach the routers`: where each served app is handed to what serves it (http_served_by): the + default export `{ fetch: app.fetch }`, `export default app`, `serve({ fetch: app.fetch })`. Production apps first.""" + if not (g.has('ext_http_served_by') and SERVE_WORDS.search(text or '')): return [] + def site(x): + try: r = g.q("SELECT callee_name, file, start_line FROM sites WHERE id = ?", x) + except Exception: r = [] + if r: return r[0] + n = node_at(g, x) + return ('', n[0], n[1]) if n else None + TESTISH = re.compile(r'(^|/)(tests?|__tests__|e2e)/|[._-](test|spec)\.[cm]?[jt]sx?$') + rows = [] + for app, at, how in sorted({tuple(r) for r in g.q("SELECT c0, c1, c2 FROM ext_http_served_by")}): + a, s_ = site(app), site(at) + an = f"{a[1]}:{a[2]}" if a else app + sn = f"{s_[1]}:{s_[2]}" if s_ else at + call = f" {s_[0]}(..)" if (s_ and how == 'fetch_handed' and s_[0]) else '' + rows.append((bool(TESTISH.search(an.rsplit(':', 1)[0])), an, f"served: the app created at {an} is served through {SERVED_HOW.get(how, how)}{call} at {sn}")) + rows.sort() + out = [r[2] for r in rows if not r[0]][:cap] or [r[2] for r in rows][:cap] + n = sum(1 for r in rows if not r[0]) if any(not r[0] for r in rows) else len(rows) + return out + ([f" ... +{n - cap} more"] if n > cap else []) + + +def declared_unknown_lines(g, text, cap=6): + """A question whose words name a declared unknown (`except` -> dynamic_except, `list` -> dynamic_middleware_list): + the rows the engine wrote, so the answer says what cannot be decided instead of guessing an exclusion set.""" + if not g.has('ext_framework_undetermined'): return [] + words = {w.lower() for w in re.findall(r'[A-Za-z]+', text or '')} + out, head = [], [] + # where a run-time middleware list enters the chains (registration_conditional on the registering call): the line + # to read first, before the routes it stands in + regs = set() + if g.has('ext_registration_conditional'): + try: regs = {tuple(r) for r in g.q("SELECT c0, c1 FROM ext_registration_conditional WHERE c1 = 'dynamic_middleware_list'")} + except Exception: regs = set() + for rc, why in sorted(regs): + if not (set(why.split('_')) & words - {'route', 'path', 'registration'}): continue + try: st = g.q("SELECT callee_name, file, start_line FROM sites WHERE id = ?", rc) + except Exception: st = [] + if st: head.append(f"declared unknown: {why.replace('_', ' ')} registered at {st[0][1]}:{st[0][2]} ({st[0][0]}(..) with a middleware read at run time); the chains below may hold more") + for m, what, why in sorted({tuple(r) for r in g.q("SELECT c0, c1, c2 FROM ext_framework_undetermined")}): + toks = set(why.split('_')) + if not (toks & words - {'route', 'path', 'registration'}): continue + nm = f"{g.disp(m)} {g.loc(m) or ''}".rstrip() if m in g.sym else m + out.append(f"declared unknown: {why.replace('_', ' ')} ({what.replace('_', ' ')}) at {nm}") + return sorted(set(head))[:cap] + out[:cap] + ([f" ... +{len(out) - cap} more"] if len(out) > cap else []) + + def route_seeds(g, text): """[(symbol id, why)] for a route the question quotes (`GET /api/widgets`, `/orders/{id}`), at the declaration the graph records as serving it: a remote-edge row, a route attribute or annotation, or the innermost callable around @@ -390,6 +745,20 @@ def route_seeds(g, text): WHERE e.c2 = 'url_dispatch' AND e.c3 LIKE '/%'"""): tables.add(r['tf']) if any(_route_eq(_route_parts(r['path']), a) for a in asked): serve(r['sid'], r['path']) + # an HTTP router's route table: the full path the engine composed through every basePath and mount (http_route), + # and the middleware the router runs before the handler there, in chain order (middleware_applies). The chain is + # seeded first so the answer walks it in the order a request does: each middleware, then the handler. + if g.has('ext_http_route') and g.has('symbols'): + for r in g.q("""SELECT s.id AS sid, e.c0 AS h, e.c1 AS verb, e.c2 AS path FROM ext_http_route e + JOIN symbols s ON s.method_id = e.c0"""): + if not any(_route_eq(_route_parts(r['path']), a) for a in asked): continue + if g.has('ext_middleware_applies'): + mws = g.q("""SELECT s.id AS sid, m.c4 AS pos FROM ext_middleware_applies m JOIN symbols s ON s.method_id = m.c0 + WHERE m.c1 = ? AND m.c2 = ? AND m.c3 = ?""", r['h'], r['verb'], r['path']) + for mw in sorted(mws, key=lambda x: int(x['pos']) if str(x['pos']).isdigit() else 0): + if mw['sid'] in g.sym and (mw['sid'], f"\x00{r['path']}") not in hits: + hits.append((mw['sid'], f"\x00{r['path']}")) + serve(r['sid'], r['path']) # a route the engine answered is not searched again as text: the literal scan below is the fallback for a route # no edge carries, and on an answered one it only adds the table's module and every literal that spells a suffix asked = [a for a in asked if not any(_route_eq(_route_parts(r), a) for _s, r in hits)] @@ -438,7 +807,10 @@ def route_seeds(g, text): if inner and not g.sym[inner[0][1]].get('is_test') and not TESTY.search(f or ''): serve(inner[0][1], v) out, seen = [], set() for sid, route in hits: - if sid not in seen: seen.add(sid); out.append((sid, f"serves the route {route.strip()}")) + if sid in seen: continue + seen.add(sid) + # a middleware seeded from a route's chain runs BEFORE the handler: it does not serve the route + out.append((sid, f"runs before the handler of {route[1:].strip()}" if route.startswith('\x00') else f"serves the route {route.strip()}")) return out[:NAMED_FAN] @@ -1325,6 +1697,12 @@ def main(argv): + ("…" if n > 4 else "") + ")") print(" no --in was given, so NOTHING below is narrowed to it — " "pass --in to narrow.\n") + # a question the route table answers (a quoted route, a mounted app's name) needs no scope: the table is the + # answer, and refusing for want of --in returned nothing while holding it (QH18, a Deno project whose words + # landed in no directory) + if not flat and not scopes and not (have_from and not fixed) and (route_table_lines(g, body) or mount_lines(g, body)): + flat = True + print("scope: the repository root (the route table answers this; --in narrows the code below)\n") bad = None if flat or (have_from and not fixed) else require_scope(g, scopes, terms, rank=rank, flag=' --in-offered') if bad is not None: return bad @@ -1367,6 +1745,21 @@ def main(argv): RESULT['entry_points'] = [{'name': g.disp(sid), 'at': g.loc(sid), 'why': (term or 'best overall match')} for sid, term, sc in seeds] + _rt = route_table_lines(g, body) + mount_lines(g, body) + _served = served_lines(g, body) + if not _rt: + _rt = worded_route_lines(g, body) + # the best word match's own chain, as the route table prints a quoted route's + for l in _rt[:1]: + m_ = re.match(r"route \(by the question's words\): (\S+) (\S+) ->", l) + if m_ and 'prefix not known' not in l: + _rt = _rt + [x for x in route_table_lines(g, f"{m_.group(1)} {m_.group(2)}", cap=2) if not x.startswith('route:')] + _rt += declared_unknown_lines(g, body) + _rt = _served + _rt + if _rt: + print("the route table (composed by the engine through every basePath and mount; read these first):") + for line in _rt: print(' ' + line) + print() print(f"task terms: {' · '.join(terms[:10])}" + (f" (+{len(terms)-10})" if len(terms) > 10 else '')) if explain is None: explain = explain_intent(task) # explaining: the flow below starts at its own roots and IS the answer, so the lexical entry points (a word @@ -1406,7 +1799,10 @@ def main(argv): cands = [s_ for s_, _t, _sc in seeds if (g.sym.get(s_) or {}).get('method_id')] cands += [x for x in type_members(g, [s_ for s_, _t, _sc in seeds], scored) if x not in cands] asked = {s_ for s_, _why in named} - roots_ = sorted(cands, key=lambda x: x not in asked and bodiless(g, x))[:FLOW_ROOTS] + # a quoted route seeds its whole chain (each middleware, then the handler) and the flow starts at each of + # them, in that order: cutting it at FLOW_ROOTS dropped the handler, the one the question was about + n_route = sum(1 for _s, w in named if w.startswith(('serves the route', 'runs before the handler of'))) + roots_ = sorted(cands, key=lambda x: x not in asked and bodiless(g, x))[:max(FLOW_ROOTS, min(n_route, 8))] roots_ = producer_first(g, roots_, [s_ for s_, _t, _sc in seeds], task, terms) # a producer joined only by name is shown as one step: its code holds the call, and the budget goes to the # mechanism the task asked about rather than to everything else the producer does @@ -1550,7 +1946,9 @@ def main(argv): "destination both ends name):") for d, _a, _b, fr, to, tr, dest, conf, near_is_sender in rows[:REMOTE_SHOWN]: far = to if near_is_sender else fr - print(f" [remote] {tr} {dest} ({conf}) {g.disp(fr)} → {g.disp(to)} " + cw = {'base_unknown': 'may reach: the base address is not known', + 'method_unknown': 'may reach: the HTTP method is not known'}.get(conf, conf) + print(f" [remote] {tr} {dest} ({cw}) {g.disp(fr)} → {g.disp(to)} " f"{'handled in' if near_is_sender else 'sent from'} {g.loc(far)}") if len(rows) > REMOTE_SHOWN: print(f" … +{len(rows) - REMOTE_SHOWN} more") RESULT['remote'] = [{'from': g.disp(fr), 'from_at': g.loc(fr), 'to': g.disp(to), 'to_at': g.loc(to), diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact index 83b0a0f53..4888ce911 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact @@ -2460,6 +2460,34 @@ class Impact: g.q("SELECT c0, c1, c2, c3, c4 FROM ext_framework_edge") if r[0] and r[1] and r[0] != r[1]}) W('framework', fw) + # AN HTTP ROUTER'S CHAIN (config-resolution/http-router-routes.dl, framework-behavior/http-router-chain.dl): + # middleware_applies(Mw, Handler, Verb, Path, Position) and ctx_key_flow(Setter, Reader, Key). Neither is a + # call: the router runs the middleware before the handler, and a context key written by one function on the + # chain is read by a later one. A change to a middleware or to what a key holds reaches those functions. + mwa = [] + if g.has('ext_middleware_applies'): + mwa = sorted({(r[0], r[1], r[2], r[3], r[4]) for r in + g.q("SELECT c0, c1, c2, c3, c4 FROM ext_middleware_applies") if r[0] and r[1] and r[0] != r[1]}) + W('mw_applies', mwa) + ctxf = [] + if g.has('ext_ctx_key_flow'): + # one row per (setter, reader) naming EVERY key that flows between them: a reader of two keys a middleware sets + # was shown under one of them + _keys = collections.defaultdict(set) + for r in g.q("SELECT c0, c1, c2 FROM ext_ctx_key_flow"): + if r[0] and r[1]: _keys[(r[0], r[1])].add(r[2]) + ctxf = sorted((a, b, "', '".join(sorted(ks))) for (a, b), ks in _keys.items()) + W('ctx_flow', ctxf) + # a schema a route validates its input with (route_schema, TS framework-behavior/http-router-schema.dl), and the + # route each handler serves (http_route), so a change to the schema names the routes it reaches + rsch = [] + if g.has('ext_route_schema'): + rsch = sorted({(r[0], r[1], r[2]) for r in g.q("SELECT c0, c1, c2 FROM ext_route_schema") if r[0] and r[2]}) + W('route_schema', rsch) + hroute = [] + if g.has('ext_http_route'): + hroute = sorted({(r[0], r[1], r[2]) for r in g.q("SELECT c0, c1, c2 FROM ext_http_route") if r[0]}) + W('http_route', hroute) # A LIBRARY CALLING BACK INTO THE CLIENT (Python framework-behavior/library-callbacks.dl): walked by the closure as # its own hop, `library callback`, so a test that drives the library reaches the client member it hands back to. libcb = [] @@ -2934,6 +2962,221 @@ def target_ext(g, pay): return '' +def own_ids(g, targets): + """the declarations the question named (each target's payload), not the closure's expanded seeds: a type's seeds + reach every function that mentions it, and the router answer is about the named thing only""" + out = set() + def walk(x): + if isinstance(x, str): + if x in g.sym: out.add(x); mid = (g.sym[x] or {}).get('method_id') + else: mid = None + if mid: out.add(mid) + if x.startswith(('TS_', 'JS_')): out.add(x) + elif isinstance(x, dict): + for v in x.values(): walk(v) + elif isinstance(x, (list, tuple, set)): + for v in x: walk(v) + else: + try: vals = list(x) # a database row + except TypeError: return + for v in vals: walk(v) + for _k, _lab, p_ in targets: walk(p_) + return out + +def router_answer(g, seeds, limit=25): + """AN HTTP ROUTER'S ANSWERS (SPEC 8.1): what the route table (http_route, http_route_partial, + route_registered_by), the middleware chains (middleware_applies) and the context-key flow (ctx_key_flow) say about + a change to the seeds. Only rows the engine wrote are printed; every list is capped by `limit` with the count + behind it. Returned as lines so the text answer and the --json document (`router`) carry the same words.""" + out = [] + if not seeds: return out + def _rq(sql, *a): + try: return g.q(sql, *a) + except Exception: return [] + def has(t): + try: return g.has(t) + except Exception: return False + S = sorted(seeds) + sp = ','.join('?' * len(S)) + def site(x): + r = _rq("SELECT callee_name, file, start_line FROM sites WHERE id = ?", x) if has('sites') else [] + if r: return r[0] + # a node that is not a call site (an app held in a parameter or a field, a middleware value): where the engine + # says it is written (router_node_at) + n = _rq("SELECT c1, c2, c3 FROM ext_router_node_at WHERE c0 = ?", x) if has('ext_router_node_at') else [] + if not n: return None + f = n[0][0] + pr = _rq("SELECT rel FROM paths WHERE raw = ?", f) if has('paths') else [] + return ('' if n[0][2] == 'expression' else n[0][2], (pr[0][0] if pr and pr[0][0] else f), n[0][1]) + def where(x): + if x in g.sym: return g.loc(x) or '' + r = site(x) + return f"{r[1]}:{r[2]}" if r else '' + def name(x): + if x in g.sym: return f"{g.disp(x)} {g.loc(x) or ''}".rstrip() + vk = _rq("SELECT c2 FROM ext_middleware_site WHERE c0 = ? AND c1 = 'value'", x) if has('ext_middleware_site') else [] + if vk and vk[0][0]: return f"{vk[0][0]} (value)" + cs = _rq("SELECT c2, c3 FROM ext_middleware_site WHERE c0 = ? AND c1 != 'value'", x) if has('ext_middleware_site') else [] + r = site(x) + at = f" at {r[1]}:{r[2]}" if r else '' + if cs and cs[0][0]: return f"{cs[0][0]}() from {cs[0][1]}{at}" + if r and r[0] and not r[0].startswith(('parameter ', 'field ')): return f"{r[0]}(){at}" + if r: return f"a value{at}" + return 'a value the engine could not name' + def app_name(a): + r = site(a) + return (f"{r[1]}:{r[2]}" + (f" ({r[0]})" if r[0].startswith(('parameter ', 'field ')) else '')) if r else a + def cap(xs, f): + for x in xs[:limit]: out.append(f(x)) + if len(xs) > limit: out.append(f" ... +{len(xs) - limit} more (--limit N)") + def hits(h): + return sorted({(r[0], r[1]) for r in _rq("SELECT c0, c3 FROM ext_remote_edge WHERE c1 = ?", h)}) if has('ext_remote_edge') else [] + undet = collections.defaultdict(set) + if has('ext_framework_undetermined'): + for r in _rq("SELECT c0, c1, c2 FROM ext_framework_undetermined"): undet[r[0]].add((r[1], r[2])) + def honesty(h): + w = [] + for what, why in sorted(undet.get(h, ())): + if why == 'conditional_registration': w.append('conditional: registered inside a branch') + elif why == 'loop_registration': w.append('registered inside a loop') + elif why == 'dynamic_middleware_list': w.append('order among the known middleware; a list the engine could not read may add more at run time') + return w + # (c)/(d) a function that REGISTERS routes: a registration function, an app factory or builder, a module body + if has('ext_route_registered_by'): + rg_all = {tuple(r) for r in _rq(f"SELECT c0, c1, c2, c3, c4 FROM ext_route_registered_by WHERE c0 IN ({sp})", *S)} + # one line per route: the same registration served by several apps (a builder called from tests) is one change + apps = sorted({r[4] for r in rg_all}, key=lambda a: (bool(re.search(r'(^|/)(tests?|__tests__)/|\.(test|spec)\.', app_name(a))), app_name(a))) + rg = sorted({(r[0], r[1], r[2], r[3], '') for r in rg_all}, key=lambda r: (r[3], r[2])) + if rg: + out.append(f"registers: {len(rg)} route(s) a change here adds to or removes from the served app" + + (f" ({', '.join('app ' + app_name(a) for a in apps[:3])}" + (f" +{len(apps) - 3} more app(s)" if len(apps) > 3 else '') + ")" if apps else '') + ":") + def reg(r): + c, h, v, p, a = r + tail = ''.join(f"; hit by {g.disp(x)} {g.loc(x) or ''} ({d})" for x, d in hits(h)[:3] if x in g.sym) + hz = honesty(h) + return f" registers {v} {p} -> {name(h)}" + (f" ({'; '.join(hz)})" if hz else '') + tail + cap(rg, reg) + # an app factory / builder: the apps whose creating expression is inside the seed function, and what they serve + if has('ext_http_route') and has('sites'): + spans = [(r[0], r[1], r[2], x) for x in S for r in _rq("SELECT file, line, end_line FROM symbols WHERE id = ? OR method_id = ?", x, x)[:1]] + made = collections.defaultdict(set) + # distinct routes: every call of a helper that builds an app is its own app (R6) reported under the one creating + # expression, so the rows repeat each route once per call + for a, n in _rq("SELECT c3, COUNT(DISTINCT c0 || char(9) || c1 || char(9) || c2) FROM ext_http_route GROUP BY c3"): + r = site(a) + if not r: continue + for f, l0, l1, x in spans: + if f and r[1] == f and l0 and l1 and l0 <= r[2] <= l1: made[x].add((a, n)) + for x in sorted(made): + for a, n in sorted(made[x], key=lambda t: -t[1])[:limit]: + eg = _rq("SELECT c1, c2 FROM ext_http_route WHERE c3 = ? GROUP BY c1, c2 ORDER BY MIN(c4) LIMIT 3", a) + out.append(f"creates app {app_name(a)} serving {n} route(s)" + (f", e.g. {', '.join(v + ' ' + p for v, p in eg)}" if eg else '')) + # a route HANDLER: every route it serves (composed or partial), in table order, and the chain the router runs first + rt = sorted({tuple(r) for r in _rq(f"SELECT c0, c1, c2, c3, c4 FROM ext_http_route WHERE c0 IN ({sp})", *S)}) if has('ext_http_route') else [] + for h, v, p, a, k in sorted(rt, key=lambda r: (r[3], r[4]))[:limit]: + mw = _rq("SELECT c0, c4 FROM ext_middleware_applies WHERE c1 = ? AND c2 = ? AND c3 = ? AND c5 = ?", h, v, p, a) if has('ext_middleware_applies') else [] + before = sorted({(int(r[1]) if str(r[1]).isdigit() else 0, r[0]) for r in mw}) + hz = honesty(h) + out.append(f"route: {g.disp(h)} serves {v} {p} (app {app_name(a)})" + (f" ({'; '.join(x for x in hz if not x.startswith('order'))})" if [x for x in hz if not x.startswith('order')] else '')) + if before: + out.append(" the router runs first, in order: " + ', '.join(f"{i}. {name(m)}" for i, (_p, m) in enumerate(before, 1))) + else: + out.append(" no middleware the engine can see runs before it") + if any(x.startswith('order') for x in hz): out.append(" " + [x for x in hz if x.startswith('order')][0]) + if has('ext_http_route_partial'): + pr = sorted({(r[0], r[1], r[2], r[4]) for r in _rq(f"SELECT c0, c1, c2, c3, c4 FROM ext_http_route_partial WHERE c0 IN ({sp})", *S)}) + for h, v, p, why in pr[:limit]: + out.append(f"route: {g.disp(h)} serves {v} {p} -- prefix not known ({why.replace('_', ' ')}); the full path is decided at run time") + if has('ext_middleware_may_apply'): + for mw, q in sorted({(r[0], r[1]) for r in _rq("SELECT c0, c4 FROM ext_middleware_may_apply WHERE c1 = ? AND c3 = ?", h, p)}): + out.append(f" {name(mw)} may run before it (scope {q} vs unknown prefix)") + # (d)/(f) a MIDDLEWARE, or a middleware FACTORY (resolved to what it returns): the routes it runs before, and the + # context keys it sets grouped by key with their readers + mws = set(S); asked_mw = set(S) + # a builder or factory (`createApp(ctx)`, `createFactory({ initApp })`): the middleware written inside it is what a + # change to it changes on every app it makes + if has('ext_middleware_site'): + for x in S: + for f, l0, l1 in _rq("SELECT file, line, end_line FROM symbols WHERE id = ? OR method_id = ?", x, x)[:1]: + if not (f and l0 and l1 and l1 > l0): continue + for (m,) in _rq("""SELECT DISTINCT e.c0 FROM ext_middleware_site e JOIN symbols s ON s.method_id = e.c0 + WHERE e.c1 = 'project_fn' AND s.file = ? AND s.line BETWEEN ? AND ?""", f, l0, l1): + mws.add(m) + if has('ext_middleware_site'): + names = {g.sym[x]['name'] for x in S if x in g.sym and g.sym[x].get('name')} + for nm in names: + fr_ = {r[0] for r in _rq("SELECT c0 FROM ext_middleware_site WHERE c1 = 'factory_result' AND c2 = ?", nm)} + mws |= fr_; asked_mw |= fr_ + if has('ext_ctx_key_flow'): + mp = ','.join('?' * len(mws)) + keys = collections.defaultdict(set) + for s_, r_, k_ in _rq(f"SELECT c0, c1, c2 FROM ext_ctx_key_flow WHERE c0 IN ({mp})", *sorted(mws)): + keys[k_].add(r_) + for k_ in sorted(keys): + rs = sorted(keys[k_], key=lambda x: name(x)) + eg = ', '.join(name(x) for x in rs[:limit]) + out.append(f"context key: sets '{k_}': read by {len(rs)} function(s), e.g. {eg}" + (f" (+{len(rs) - limit} more)" if len(rs) > limit else '')) + if has('ext_middleware_may_apply'): + for m in sorted(x for x in mws if x in seeds): + mr = sorted({(r[0], r[1], r[2]) for r in _rq("SELECT c2, c3, c4 FROM ext_middleware_may_apply WHERE c0 = ?", m)}) + if mr: + out.append(f"middleware: {name(m)} may run before {len(mr)} route(s) whose prefix is not known:") + cap(mr, lambda r: f" may run before {r[0]} {r[1]} (scope {r[2]} vs unknown prefix)") + if has('ext_middleware_applies'): + for m in sorted(mws): + rows_ = {(r[0], r[1], r[2]) for r in _rq("SELECT c2, c3, c1 FROM ext_middleware_applies WHERE c0 = ?", m)} + # production handlers first: a test app's route is an example of nothing a user requests + ro = sorted({(v, p_, bool((g.sym.get(h) or {}).get('is_test'))) for v, p_, h in rows_}, key=lambda r: (r[2], r[1], r[0])) + hs = sorted({(bool((g.sym.get(h) or {}).get('is_test')), v, p_, h) for v, p_, h in rows_}) + if ro: + hz = [x for x in honesty(m) if not x.startswith('order')] + if m not in asked_mw: + # written inside the builder asked about: one line, the routes are the builder's + eg = ', '.join(f"{x[1]} {x[2]}" for x in ([x for x in hs if not x[0]] or hs)[:3]) + out.append(f"middleware: {name(m)} (registered inside it) runs before {len(ro)} route(s), e.g. {eg}" + (f" ({'; '.join(hz)}, so it may not run)" if hz else '')) + continue + out.append(f"middleware: {name(m)} runs before {len(ro)} route(s)" + (f" ({'; '.join(hz)}, so it may not run)" if hz else '') + ":") + # EVERY route, not a sample: "does a change to it reach GET /x" is answered by finding the line + # (QD04, QD29); one line per route, production apps first, capped only far above a real app's size + full = [x for x in hs if not x[0]] or hs + # FROM WHERE (QH25, QD29): the registering call that puts it in each route's chain, an app-level + # `use(..)` or the route's own call; a route reached by two registrations names both + via = collections.defaultdict(set) + if has('ext_middleware_registered_at'): + for h_, v_, p_, rc in _rq("SELECT c1, c2, c3, c5 FROM ext_middleware_registered_at WHERE c0 = ?", m): + via[(v_, p_, h_)].add(rc) + def via_txt(v_, p_, h_): + regs = [] + for rc in sorted(via.get((v_, p_, h_), ())): + r = site(rc) + if not r: continue + # `use(..)` attaches it to every matching route; any other registering call is the route's own + regs.append(f"{r[0]}(..) at {r[1]}:{r[2]}" if r[0] == 'use' else f"per-route, in {r[0]}(..) at {r[1]}:{r[2]}") + return f" (via {'; '.join(regs)})" if regs else '' + seen_ = set() + for x in full[:500]: + if (x[1], x[2], x[3]) in seen_: continue + seen_.add((x[1], x[2], x[3])); out.append(f" runs before {x[1]} {x[2]} -> {name(x[3])}{via_txt(x[1], x[2], x[3])}") + if len(full) > 500: out.append(f" ... +{len(full) - 500} more") + nt = sum(1 for x in hs if x[0]) + if nt and any(not x[0] for x in hs): out.append(f" (and before {nt} route(s) of apps built in tests)") + # (e) a request SCHEMA: every route validating with it (or a schema composed from it), and the validated reads + if has('ext_route_schema'): + rsch = sorted({tuple(r) for r in _rq(f"SELECT c0, c1 FROM ext_route_schema WHERE c2 IN ({sp})", *S)}) + rows = [] + for h, t in rsch: + got = sorted({(r[0], r[1]) for r in _rq("SELECT c1, c2 FROM ext_http_route WHERE c0 = ?", h)}) + got += sorted({(r[0], r[1] + ' (prefix not known)') for r in _rq("SELECT c1, c2 FROM ext_http_route_partial WHERE c0 = ?", h)}) if has('ext_http_route_partial') else [] + for v, p in got or [('?', '(route not composed)')]: rows.append((v, p, t, h)) + if rows: + out.append(f"schema: validates {len(rows)} route input(s):") + cap(sorted(rows), lambda r: f" validates {r[0]} {r[1]} (target {r[2]}) -> {name(r[3])}") + if has('ext_valid_read'): + vr = sorted({(r[0], r[1]) for r in _rq(f"SELECT c1, c2 FROM ext_valid_read WHERE c3 IN ({sp})", *S)}) + if vr: cap(vr, lambda r: f" read with c.req.valid('{r[1]}') in {name(r[0])}") + return out + + def main(argv): args = list(argv); depth = 40; limit = 25; IN = None; as_json = '--json' in args; kind = None # --tests lists the tests grouped by rung and file; --tests-only prints that section and nothing else; @@ -3040,6 +3283,11 @@ def main(argv): # accessor, a record component), so every such target came back as a JSONDecodeError rather than an answer print(f"note: {a} is a field and a method of that name — both are the change (--kind field | method for one)", file=sys.stderr if as_json else sys.stdout) + elif kinds in ({'type', 'var'}, {'type', 'field'}) and not kind: + # a value and a type of one name (`const User = z.object(..)` beside `type User = z.infer`, a + # const enum object beside its union type): one concept written twice, so both are the change, as above + print(f"note: {a} is a value and a type of that name: both are the change (--kind var | type for one)", + file=sys.stderr if as_json else sys.stdout) elif len(rs) > 1 and not kind: die(f"{a} is declared as more than one kind: " + ' · '.join(f"{k} ({lab})" for k, lab, _ in rs) + " — say which with --kind " + '|'.join(k for k, _, _ in rs)) # ONE NAME, UNRELATED DECLARATIONS IN DIFFERENT FILES. A bare name answers for every declaration of it — the @@ -3646,6 +3894,7 @@ def main(argv): **({'script': True, 'run': script_cmd(m)} if m in script_ids else {})} for m, (d, fx) in sorted(tests.items(), key=lambda kv: (kv[1][0], g.disp(kv[0]), g.loc(kv[0]), kv[0]))], # the tests whose route never loads the changed file, left out of `tests` (see `unloaded` above) **({'unloaded_tests': {'count': len(unloaded), 'files': sorted({g.sym[m]['file'] for m in unloaded if g.sym[m].get('file')})}} if unloaded else {}), + **({'router': _router} if (_router := router_answer(g, own_ids(g, targets), limit)) else {}), 'framework_entries': [{'id': m, 'display': g.disp(m), 'signal': sig, 'at': g.loc(m)} for m, sig in fw_ent], 'framework_grep': fw_grep, 'stub_tests': [{'id': m, 'display': g.disp(m), 'owner': g.sym[m]['owner'], 'name': g.sym[m]['name'], 'at': g.loc(m), 'certainty': 'type test' if m in type_tests else 'stubs it', @@ -3716,6 +3965,7 @@ def main(argv): # as the direct-dependent sections already do. Tests are counted apart and not explained: a test entry point is # not a place the outside world calls, and the tests section below is what names them. ep_rows = sorted({(r['method_id'], r['reason']) for r in eps}) + for _line in router_answer(g, own_ids(g, targets) & (set(seeds) | own_ids(g, targets)), limit): print(_line) _is_t = lambda m: m in g.sym and g.sym[m]['is_test'] ep_by_reason = collections.defaultdict(list) for m, why in ep_rows: diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path index 63adb2970..51961de48 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path @@ -1129,6 +1129,16 @@ class G: for a, b, how, where, conf in self.q(f"SELECT c0, c1, c2, c3, c4 FROM {table}"): if a == b or a not in self.sym or b not in self.sym: continue self.OUTSIDE.setdefault((a, b, tier), []).append((how, where, conf)) + # an HTTP router's chain: the router runs a middleware before each handler it applies to, and a request-context + # key one function on the chain sets is read by a later one (middleware_applies, ctx_key_flow) + if self.has('ext_middleware_applies'): + for a, b, verb, path, pos in self.q("SELECT c0, c1, c2, c3, c4 FROM ext_middleware_applies"): + if a == b or a not in self.sym or b not in self.sym: continue + self.OUTSIDE.setdefault((a, b, 'framework'), []).append(('middleware', f'{verb} {path}', f'position {pos}')) + if self.has('ext_ctx_key_flow'): + for a, b, key in self.q("SELECT c0, c1, c2 FROM ext_ctx_key_flow"): + if a == b or a not in self.sym or b not in self.sym: continue + self.OUTSIDE.setdefault((a, b, 'framework'), []).append(('context_key', key, 'same route chain')) # a library summarised (from its source) to call a client member back (Python framework-behavior/ # library-callbacks.dl): `impact` walks it as the `library callback` hop, so the chain search does too if self.has('ext_lib_callback_edge'): @@ -1236,6 +1246,8 @@ def outside_hop_holds(g, a, b, t): if t != 'framework': return False if g.has('ext_lib_callback_edge') and g.q("SELECT 1 FROM ext_lib_callback_edge WHERE c0 = ? AND c1 = ? LIMIT 1", a, b): return True + for tbl in ('ext_middleware_applies', 'ext_ctx_key_flow'): + if g.has(tbl) and g.q(f"SELECT 1 FROM {tbl} WHERE c0 = ? AND c1 = ? LIMIT 1", a, b): return True import ax_registration links = getattr(g, '_filter_links', None) if links is None: links = g._filter_links = {(x, y) for x, y, _h in ax_registration.filter_links(g.q)} diff --git a/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl b/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl index a7641525e..625c68189 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl +++ b/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl @@ -337,6 +337,30 @@ direct(q, c, "uses", cat("serves what this sends across a process boundary (", c direct(q, c, "uses", cat("framework-mediated, not a call: ", cat(mech, cat(" via ", cat(detail, cat(" [", cat(conf, "]")))))), "framework", "", 0) :- target(q, "method", m, _), framework(c, m, mech, detail, conf), c != m. +// ── an HTTP router's chain ──────────────────────────────────────────────────────────────────────────── +// mw_applies(Mw, Handler, Verb, Path, Position): the router runs Mw before Handler for that route; a change to the +// middleware (what it rejects, what it puts on the request) reaches the handler with no call between them. +// ctx_flow(Setter, Reader, Key): a request-context key Setter writes and Reader, later on the same chain, reads. +// Certainty `framework`: the router joins them, not a resolved call. +.decl mw_applies(mw:symbol, h:symbol, verb:symbol, path:symbol, pos:symbol) .input mw_applies +.decl ctx_flow(s:symbol, r:symbol, key:symbol) .input ctx_flow +// route_schema(Handler, Target, SchemaDecl): the route validates its Target input (json, query, ...) with the schema +// declared at SchemaDecl or one built from it; http_route(Handler, Verb, Path): the route the handler serves +.decl route_schema(h:symbol, t:symbol, d:symbol) .input route_schema +.decl http_route(h:symbol, verb:symbol, path:symbol) .input http_route +.decl schema_route(d:symbol, h:symbol, t:symbol) +schema_route(d, h, t) :- route_schema(h, t, d). +.decl schema_routed(d:symbol, h:symbol) +schema_routed(d, h) :- route_schema(h, _, d), http_route(h, _, _). +direct(q, h, "uses", cat("validates the ", cat(t, cat(" input of ", cat(v, cat(" ", cat(p, " with this schema")))))), "framework", "", 0) + :- target(q, k, d, _), (k = "field" ; k = "var"), schema_route(d, h, t), http_route(h, v, p). +direct(q, h, "uses", cat("validates its ", cat(t, " input with this schema")), "framework", "", 0) + :- target(q, k, d, _), (k = "field" ; k = "var"), schema_route(d, h, t), !schema_routed(d, h). +direct(q, h, "uses", cat("runs after this as middleware on ", cat(v, cat(" ", cat(p, cat(" (chain position ", cat(pos, ")")))))), "framework", "", 0) + :- target(q, "method", m, _), mw_applies(m, h, v, p, pos), h != m. +direct(q, r, "reads", cat("reads the request-context key(s) '", cat(k, "' this sets, later on the same route chain")), "framework", "", 0) + :- target(q, "method", m, _), ctx_flow(m, r, k), r != m. + direct(q, c, "uses", cat("receives it by dependency injection (", kind, ") — the container hands it over, no call site"), "resolved", "", 0) :- target(q, "type", t, _), injected(t, c, kind), !inside_target(q, c). direct(q, c, "uses", cat("receives it by dependency injection (", kind, ") — the container hands it over, no call site"), "resolved", "", 0) :- target(q, "clinit", t, _), injected(t, c, kind). // a method that DEFINES a bean (@Bean): whoever is injected with the type it returns. Keyed on `bean_factory`, diff --git a/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py b/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py index 1ee917a50..a1b993fd3 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py +++ b/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py @@ -3615,6 +3615,9 @@ def _has_framework_hops(q, at=None, site_file=None): import ax_registration if at is not None and ax_registration.key_edges(q, at, site_file): return True if ax_registration.filter_links(q): return True # fw_edge "filter": a servlet filter a test's context holds + # an HTTP router's chain (dl/impact.dl mw_applies / ctx_flow): direct rows the rules have and this port does not + for t in ('ext_middleware_applies', 'ext_ctx_key_flow', 'ext_route_schema'): + if _has(q, t) and q(f"SELECT 1 FROM {t} LIMIT 1"): return True except Exception: return True # cannot tell: decline, because answering smaller is the failure try: diff --git a/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/case.json b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/case.json new file mode 100644 index 000000000..9d91dcaac --- /dev/null +++ b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/case.json @@ -0,0 +1,12 @@ +{"lang": "typescript", "src": "src", + "checks": [ + {"why": "two calls of one helper pass the objects of two DIFFERENT functions into its parameter; the helper mounts the sub-app it destructures, so each call's app serves its own module's routes only, never the other module's handler under its prefix", + "run": ["context", "who serves DELETE /orders/:invoiceId"], + "avoid": ["route: DELETE /orders/:invoiceId"]}, + {"why": "the same, the other way round", + "run": ["context", "who serves DELETE /invoices/:orderId"], + "avoid": ["route: DELETE /invoices/:orderId"]}, + {"why": "CONTROL: a helper whose parameter only ever receives the object of ONE function (called twice, mounted at /east and /west) still mounts its sub-app at each prefix", + "run": ["context", "who serves DELETE /east/:orderId"], + "want": ["route: DELETE /east/:orderId -> src/routes/orders.ts:6"]} + ]} diff --git a/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/main.ts b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/main.ts new file mode 100644 index 000000000..9c4e38248 --- /dev/null +++ b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/main.ts @@ -0,0 +1,17 @@ +import { Hono } from 'hono' +import { orderModule, invoiceModule } from './modules' + +function attach(host: Hono, mod: { http: Hono; name: string }) { + const { http } = mod + host.route('/', http) + return host +} + +const orders = attach(new Hono(), orderModule()) +const invoices = attach(new Hono(), invoiceModule()) + +const app = new Hono() +app.route('/orders', orders) +app.route('/invoices', invoices) + +export default app diff --git a/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/modules.ts b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/modules.ts new file mode 100644 index 000000000..a3ec170c6 --- /dev/null +++ b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/modules.ts @@ -0,0 +1,9 @@ +import { orderRoutes } from './routes/orders' +import { invoiceRoutes } from './routes/invoices' + +export function orderModule() { + return { http: orderRoutes(), name: 'orders' } +} +export function invoiceModule() { + return { http: invoiceRoutes(), name: 'invoices' } +} diff --git a/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/regions.ts b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/regions.ts new file mode 100644 index 000000000..3807d4c46 --- /dev/null +++ b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/regions.ts @@ -0,0 +1,17 @@ +import { Hono } from 'hono' +import { orderModule } from './modules' + +function attachRegion(host: Hono, mod: { http: Hono; name: string }) { + const { http } = mod + host.route('/', http) + return host +} + +const east = attachRegion(new Hono(), orderModule()) +const west = attachRegion(new Hono(), orderModule()) + +const regions = new Hono() +regions.route('/east', east) +regions.route('/west', west) + +export default regions diff --git a/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/routes/invoices.ts b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/routes/invoices.ts new file mode 100644 index 000000000..77feca983 --- /dev/null +++ b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/routes/invoices.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function invoiceRoutes(): Hono { + const r = new Hono() + r.get('/', (c) => c.json([])) + r.delete('/:invoiceId', (c) => c.text('voided ' + c.req.param('invoiceId'))) + return r +} diff --git a/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/routes/orders.ts b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/routes/orders.ts new file mode 100644 index 000000000..cda6967df --- /dev/null +++ b/tests/cases/typescript/returned-objects-of-two-functions-through-one-parameter/src/routes/orders.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono' + +export function orderRoutes(): Hono { + const r = new Hono() + r.get('/', (c) => c.json([])) + r.delete('/:orderId', (c) => c.text('cancelled ' + c.req.param('orderId'))) + return r +} diff --git a/tests/cases/typescript/route-hole-in-the-middle/case.json b/tests/cases/typescript/route-hole-in-the-middle/case.json new file mode 100644 index 000000000..f4af80d72 --- /dev/null +++ b/tests/cases/typescript/route-hole-in-the-middle/case.json @@ -0,0 +1,9 @@ +{"lang": "typescript", "src": "src", + "checks": [ + {"why": "a route whose mount prefix has a run-time piece in the MIDDLE (`/v1/{}/ping`) answers a question about a full path it can be (`/v1/system/ping`), with the scoped middleware that may run on it; the lookup dropped the hole and compared `/v1/ping` against the asked path's tail", + "run": ["context", "what runs before GET /v1/system/ping"], + "want": ["route: GET /v1/{}/ping", "may run (scope /v1/* vs unknown prefix)"]}, + {"why": "CONTROL: a path whose known first segment differs (`/v2/system/ping`) is not that route", + "run": ["context", "what runs before GET /v2/system/ping"], + "avoid": ["route: GET /v1/{}/ping"]} + ]} diff --git a/tests/cases/typescript/route-hole-in-the-middle/src/main.ts b/tests/cases/typescript/route-hole-in-the-middle/src/main.ts new file mode 100644 index 000000000..66e28cbeb --- /dev/null +++ b/tests/cases/typescript/route-hole-in-the-middle/src/main.ts @@ -0,0 +1,15 @@ +import { Hono } from 'hono' +import { system } from './system' + +const VERSION = 'v1' +declare const process: { env: Record } + +const app = new Hono() +app.use(`/${VERSION}/*`, async (c, next) => { + if (!c.req.header('authorization')) return c.text('no', 401) + await next() +}) +const group = process.env.GROUP ?? 'system' +app.route(`/${VERSION}/${group}`, system) + +export default app diff --git a/tests/cases/typescript/route-hole-in-the-middle/src/system.ts b/tests/cases/typescript/route-hole-in-the-middle/src/system.ts new file mode 100644 index 000000000..7f73223c2 --- /dev/null +++ b/tests/cases/typescript/route-hole-in-the-middle/src/system.ts @@ -0,0 +1,5 @@ +import { Hono } from 'hono' + +export const system = new Hono() +system.get('/ping', (c) => c.text('pong')) +system.get('/status/:part', (c) => c.json({ part: c.req.param('part') }))