@flareapp/svelte 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -97,6 +97,15 @@ Profiling and component tracking are independent. You can run either on its own:
97
97
  withFlareConfig(config, { componentTracking: false, profileComponents: [/\+page$/] });
98
98
  ```
99
99
 
100
+ ### Self time
101
+
102
+ Every component span carries `flare.component.self_time_ns`: the span's duration minus the time its own
103
+ profiled children account for. Children that overlap in time are counted once, so the value never goes
104
+ below zero.
105
+
106
+ A child that mounts after its parent's span closed is not subtracted. Its work happened outside the
107
+ parent's window, so the parent keeps its full duration.
108
+
100
109
  ### Preprocessor ordering
101
110
 
102
111
  Both features are injected by a Svelte preprocessor, which `withFlareConfig` installs for you. It parses
@@ -1,7 +1,3 @@
1
1
  import type ErrorStackParser from 'error-stack-parser';
2
2
  import type { SvelteErrorOrigin } from './types.js';
3
- /**
4
- * Classify a parsed stack trace's error origin: 'event' (DOM handler), 'effect' (async side-effect),
5
- * 'render' (component render phase), or 'unknown' (no frames or no recognizable pattern).
6
- */
7
3
  export declare function getErrorOrigin(frames: ErrorStackParser.StackFrame[]): SvelteErrorOrigin;
@@ -1,6 +1,5 @@
1
- // Origins are indistinguishable at the boundary catch site; the stack trace is the only signal.
2
- // Checked in priority order event > effect > render > unknown, so an event handler inside a
3
- // component wins over the .svelte filename check.
1
+ // The boundary catch site can't tell origins apart, so the stack trace is the only signal.
2
+ // Checked in order event > effect > render > unknown: an event handler wins over a .svelte match.
4
3
  // Inline event handlers and DOM event API calls. Svelte compiles `onclick={handler}` to
5
4
  // `.onclick = ...` or `addEventListener(...)`, so these match compiled output and manual DOM calls.
6
5
  const EVENT_PATTERNS = [
@@ -28,10 +27,8 @@ const EVENT_PATTERNS = [
28
27
  // Async side-effects: $effect callbacks (Svelte 5 schedules via queueMicrotask), onMount
29
28
  // microtasks, promise continuations, MutationObserver callbacks. Not render-phase code.
30
29
  const EFFECT_PATTERNS = [/queueMicrotask/, /Promise\.then/, /Promise\.catch/, /MutationObserver/];
31
- /**
32
- * Classify a parsed stack trace's error origin: 'event' (DOM handler), 'effect' (async side-effect),
33
- * 'render' (component render phase), or 'unknown' (no frames or no recognizable pattern).
34
- */
30
+ // Classify a parsed stack trace's error origin: 'event' (DOM handler), 'effect' (async side-effect),
31
+ // 'render' (component render phase), or 'unknown' (no frames or no recognizable pattern).
35
32
  export function getErrorOrigin(frames) {
36
33
  if (frames.length === 0) {
37
34
  return 'unknown';
@@ -1,5 +1,3 @@
1
1
  import type { Flare } from '@flareapp/js/browser';
2
- /** Web path: full identity on the default singleton. Svelte's framework has no version. */
3
2
  export declare function registerSvelteSdkIdentity(flare: Flare): void;
4
- /** Injected path: framework tag only, never sdkInfo. */
5
3
  export declare function tagSvelteFramework(flare: Flare): void;
package/dist/identify.js CHANGED
@@ -5,12 +5,12 @@ const tagger = createIdentityTagger({
5
5
  sdkVersion: PACKAGE_VERSION,
6
6
  frameworkName: FrameworkName.Svelte,
7
7
  });
8
- /** Web path: full identity on the default singleton. Svelte's framework has no version. */
8
+ // Web path: full identity on the default singleton. Svelte's framework has no version.
9
9
  export function registerSvelteSdkIdentity(flare) {
10
10
  tagger.registerSdkIdentity(flare);
11
11
  tagger.tagFramework(flare, undefined);
12
12
  }
13
- /** Injected path: framework tag only, never sdkInfo. */
13
+ // Injected path: framework tag only, never sdkInfo.
14
14
  export function tagSvelteFramework(flare) {
15
15
  tagger.tagFramework(flare, undefined);
16
16
  }
package/dist/inject.js CHANGED
@@ -1,6 +1,5 @@
1
- // Electron-safe entry. No @flareapp/js root import, no default registration, no import-time
2
- // identity. The caller must pass `flare` (handler option / boundary prop); resolveFlare throws
3
- // at wiring time if absent.
1
+ // Electron-safe entry: no @flareapp/js root import, no default registration, no import-time identity.
2
+ // The caller must pass `flare` (handler option or boundary prop); resolveFlare throws at wiring time if absent.
4
3
  export { default as FlareErrorBoundary } from './FlareErrorBoundary.svelte';
5
4
  export { createFlareErrorHandler } from './createFlareErrorHandler.js';
6
5
  export { __flareRegisterComponent, getComponentTreeContext } from './componentTree.js';
@@ -58,30 +58,25 @@ export function flarePreprocessor(options) {
58
58
  },
59
59
  };
60
60
  }
61
- /** Keeps the merged sourcemap's `sources` from carrying an absolute build-machine path. */
61
+ // Keeps the merged sourcemap's `sources` from carrying an absolute build-machine path.
62
62
  function basename(filename) {
63
63
  return filename.split(/[/\\]/).pop() ?? filename;
64
64
  }
65
- /**
66
- * The name error reports use. Stays a bare basename rather than reusing `resolveProfileName`, because
67
- * changing it would change component hierarchies people already have.
68
- */
65
+ // The name error reports use. Stays a bare basename instead of `resolveProfileName`, because changing
66
+ // it would change component hierarchies people already have.
69
67
  function extractComponentName(filename) {
70
68
  return basename(filename).replace(/\.svelte$/, '');
71
69
  }
72
70
  function escapeString(str) {
73
71
  return str.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
74
72
  }
75
- /** Copied from Svelte's own preprocessor, so we agree with it on what counts as a style tag. */
73
+ // Copied from Svelte's own preprocessor, so we agree with it on what counts as a style tag.
76
74
  const REGEX_STYLE_TAGS = /<!--[^]*?-->|<style((?:\s+[^=>'"/\s]+=(?:"[^"]*"|'[^']*'|[^>\s]+)|\s+[^=>'"/\s]+)*\s*)(?:\/>|>([\S\s]*?)<\/style>)/g;
77
75
  const CLOSING_STYLE_TAG = '</style>';
78
- /** One warning per file per process. A dev server runs this hook again on every save. */
76
+ // One warning per file per process. A dev server runs this hook again on every save.
79
77
  const warnedFiles = new Set();
80
- /**
81
- * Blanks out every `<style>` body, keeping the exact character count so offsets into the original
82
- * still line up. Svelte parses style bodies as CSS, so `lang="scss"` and friends throw and would
83
- * otherwise cost the file its registration.
84
- */
78
+ // Blanks out every `<style>` body, keeping the character count so offsets into the original still
79
+ // line up. Svelte parses style bodies as CSS, so `lang="scss"` and similar would throw otherwise.
85
80
  function blankStyleBodies(content) {
86
81
  return content.replace(REGEX_STYLE_TAGS, (match, _attributes, body) => {
87
82
  // The first branch of the regex matches comments, which have no body to blank.
@@ -101,7 +96,7 @@ function warnOnce(filename, reason) {
101
96
  // Silence here reads as "component tracking works", which is worse than a noisy build.
102
97
  console.warn(`[flare] Skipped component tracking for ${filename}: ${reason}`);
103
98
  }
104
- /** How many BOM characters sit at the very start of the source, back to back. */
99
+ // How many BOM characters sit at the very start of the source, back to back.
105
100
  function countLeadingBoms(content) {
106
101
  let count = 0;
107
102
  while (content.charCodeAt(count) === 0xfeff) {
@@ -109,16 +104,11 @@ function countLeadingBoms(content) {
109
104
  }
110
105
  return count;
111
106
  }
112
- /**
113
- * Where the instance script's body begins, `null` when the component has none, `undefined` when the
114
- * source cannot be parsed. Svelte hands a script hook every `<script>` in the file, nested ones
115
- * included, so only the parser can say which one belongs to the component. `bomCount` rides along
116
- * because the null case still needs to know how many bytes of BOM it must insert after.
117
- */
107
+ // Where the instance script body begins (null = none, undefined = unparseable). Only the parser can
108
+ // tell which `<script>` belongs to the component; `bomCount` tags along for the null case's BOM insert.
118
109
  async function instanceScriptStart(content, filename) {
119
- // parse() strips exactly one leading BOM itself and reports offsets against the stripped source.
120
- // Stripping every leading BOM here (not just one) before parsing means none are left for parse()'s
121
- // own stripping to act on, so the count we add back is exact no matter how many there were.
110
+ // parse() strips one leading BOM and reports offsets against the stripped source. Stripping all
111
+ // of them here first means the count we add back is exact, no matter how many BOMs there were.
122
112
  const bomCount = countLeadingBoms(content);
123
113
  const source = content.slice(bomCount);
124
114
  try {
@@ -137,14 +127,13 @@ async function instanceScriptStart(content, filename) {
137
127
  return undefined;
138
128
  }
139
129
  }
140
- /** The map matters: inserting lines shifts everything below, throwing off stack frames and breakpoints. */
130
+ // The map matters: inserting lines shifts everything below, throwing off stack frames and breakpoints.
141
131
  function injectWithMap(content, injection, filename, start, bomCount) {
142
132
  const magicSource = new MagicString(content);
143
133
  if (start === null) {
144
134
  const scriptBlock = `<script>\n${injection}</script>\n`;
145
- // prepend() inserts at offset 0, which would land ahead of the BOM(s) and move them into the
146
- // template. appendRight(bomCount, ...) inserts right after all of them instead, keeping every
147
- // BOM at the front so compile()'s own BOM stripping still fires.
135
+ // prepend() inserts at offset 0, ahead of any BOM, and would move it into the template.
136
+ // appendRight(bomCount, ...) inserts after the BOM(s) instead, so compile()'s own stripping still fires.
148
137
  if (bomCount > 0) {
149
138
  magicSource.appendRight(bomCount, scriptBlock);
150
139
  }
@@ -1,7 +1 @@
1
- /**
2
- * Records one `browser_component` span for this component's mount. The preprocessor injects the call,
3
- * don't write it by hand.
4
- *
5
- * Init runs top-down, so a child can point at a span id its parent reserved but hasn't recorded yet.
6
- */
7
1
  export declare function __flareProfileComponent(name: string): void;
@@ -3,12 +3,9 @@ import { getContext, onMount, setContext } from 'svelte';
3
3
  // Separate from the component tree's key: that one chains every component, this one only the
4
4
  // profiled ones.
5
5
  const PROFILE_KEY = '__flare_component_profile';
6
- /**
7
- * Records one `browser_component` span for this component's mount. The preprocessor injects the call,
8
- * don't write it by hand.
9
- *
10
- * Init runs top-down, so a child can point at a span id its parent reserved but hasn't recorded yet.
11
- */
6
+ // Records one `browser_component` span for this component's mount. The preprocessor injects this call;
7
+ // don't write it by hand. Init runs top-down, so a child may point at a span id its parent reserved
8
+ // but hasn't recorded yet.
12
9
  export function __flareProfileComponent(name) {
13
10
  try {
14
11
  const inherited = getContext(PROFILE_KEY) ?? null;
@@ -1,10 +1 @@
1
- /**
2
- * The name a profiled component reports, and what `profileComponents` matches against.
3
- *
4
- * Separate from `extractComponentName`, which feeds error reports and has to keep its bare basenames.
5
- * Profiling needs the route path too, otherwise every route in a SvelteKit app is just `+page`.
6
- *
7
- * @param filename Absolute path as a Svelte preprocessor receives it.
8
- * @param routesDir Project-relative routes directory, from `kit.files.routes`.
9
- */
10
1
  export declare function resolveProfileName(filename: string, routesDir?: string): string;
@@ -1,12 +1,9 @@
1
- /**
2
- * The name a profiled component reports, and what `profileComponents` matches against.
3
- *
4
- * Separate from `extractComponentName`, which feeds error reports and has to keep its bare basenames.
5
- * Profiling needs the route path too, otherwise every route in a SvelteKit app is just `+page`.
6
- *
7
- * @param filename Absolute path as a Svelte preprocessor receives it.
8
- * @param routesDir Project-relative routes directory, from `kit.files.routes`.
9
- */
1
+ // The name a profiled component reports, and what `profileComponents` matches against.
2
+ // Separate from `extractComponentName`, which feeds error reports and needs bare basenames.
3
+ // Profiling needs the route path too, or every SvelteKit route is just `+page`.
4
+ //
5
+ // `filename` is the absolute path as a Svelte preprocessor receives it; `routesDir` is the
6
+ // project-relative routes directory, from `kit.files.routes`.
10
7
  export function resolveProfileName(filename, routesDir = 'src/routes') {
11
8
  const normalized = filename.replace(/\\/g, '/');
12
9
  const base = normalized.split('/').pop() ?? normalized;
@@ -27,10 +24,8 @@ export function resolveProfileName(filename, routesDir = 'src/routes') {
27
24
  const relativeDir = normalized.slice(start, normalized.lastIndexOf('/'));
28
25
  return relativeDir ? `${relativeDir}/${name}` : name;
29
26
  }
30
- /**
31
- * Index just past the routes directory, or -1 when the path isn't in there. Anchors on the last
32
- * occurrence, so a project checked out under something like /home/src/routes/ still works.
33
- */
27
+ // Index just past the routes directory, or -1 when the path isn't there. Anchors on the last
28
+ // occurrence, so a project checked out under something like /home/src/routes/ still works.
34
29
  function routeDirStart(normalized, normalizedRoutesDir) {
35
30
  const nested = normalized.lastIndexOf(`/${normalizedRoutesDir}/`);
36
31
  if (nested !== -1) {
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "2.11.0";
1
+ export declare const PACKAGE_VERSION = "2.12.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // generated during release, do not modify
2
- export const PACKAGE_VERSION = '2.11.0';
2
+ export const PACKAGE_VERSION = '2.12.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flareapp/svelte",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "Svelte client for flareapp.io",
5
5
  "homepage": "https://flareapp.io",
6
6
  "bugs": "https://github.com/spatie/flare-client-js/issues",
@@ -73,14 +73,14 @@
73
73
  "vitest": "^4.0.0"
74
74
  },
75
75
  "peerDependencies": {
76
- "@flareapp/js": "^2.11.0",
76
+ "@flareapp/js": "^2.12.0",
77
77
  "svelte": "^5.3.0"
78
78
  },
79
79
  "publishConfig": {
80
80
  "access": "public"
81
81
  },
82
82
  "dependencies": {
83
- "@flareapp/core": "2.11.0",
83
+ "@flareapp/core": "2.12.0",
84
84
  "error-stack-parser": "^2.1.4",
85
85
  "magic-string": "^0.30.21"
86
86
  }