blogwright-analytics 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +162 -0
  2. package/dist/adapters/duckdb-ingest.d.ts +76 -0
  3. package/dist/adapters/duckdb-ingest.js +173 -0
  4. package/dist/adapters/duckdb-query.d.ts +56 -0
  5. package/dist/adapters/duckdb-query.js +80 -0
  6. package/dist/adapters/duckdb-session.d.ts +168 -0
  7. package/dist/adapters/duckdb-session.js +330 -0
  8. package/dist/app/_app/immutable/assets/0.BTQrrh5B.css +1 -0
  9. package/dist/app/_app/immutable/assets/2.CZSK3rT8.css +1 -0
  10. package/dist/app/_app/immutable/assets/BrushContext.D7c8UPey.css +1 -0
  11. package/dist/app/_app/immutable/assets/ChartAnnotations.CPxIG7Mw.css +1 -0
  12. package/dist/app/_app/immutable/assets/Circle.C5MKzgk2.css +1 -0
  13. package/dist/app/_app/immutable/assets/DefaultTooltip.C5-uctZ7.css +1 -0
  14. package/dist/app/_app/immutable/assets/Group.DV48xipa.css +1 -0
  15. package/dist/app/_app/immutable/assets/Labels.BxZ4NUVz.css +1 -0
  16. package/dist/app/_app/immutable/assets/Legend.CxnrE4Ye.css +1 -0
  17. package/dist/app/_app/immutable/assets/Line.fkmsECm9.css +1 -0
  18. package/dist/app/_app/immutable/assets/Path.CvpwNZ6g.css +1 -0
  19. package/dist/app/_app/immutable/assets/Rect.CtRaGMmQ.css +1 -0
  20. package/dist/app/_app/immutable/assets/Text.j9l35qB0.css +1 -0
  21. package/dist/app/_app/immutable/assets/TransformContext.Bs_HkpAk.css +1 -0
  22. package/dist/app/_app/immutable/assets/Voronoi.ce7atosu.css +1 -0
  23. package/dist/app/_app/immutable/chunks/-aNGNaBT.js +1 -0
  24. package/dist/app/_app/immutable/chunks/6djn-yLs.js +1 -0
  25. package/dist/app/_app/immutable/chunks/B1amyutE.js +1 -0
  26. package/dist/app/_app/immutable/chunks/B3vZDoek.js +1 -0
  27. package/dist/app/_app/immutable/chunks/B5KRA4hC.js +1 -0
  28. package/dist/app/_app/immutable/chunks/BClnVG6H.js +1 -0
  29. package/dist/app/_app/immutable/chunks/BID1NNRh.js +1 -0
  30. package/dist/app/_app/immutable/chunks/BR2LaRms.js +1 -0
  31. package/dist/app/_app/immutable/chunks/Bd1gDe3Y.js +1 -0
  32. package/dist/app/_app/immutable/chunks/Bjy-W4x2.js +81 -0
  33. package/dist/app/_app/immutable/chunks/Bl052uUt.js +1 -0
  34. package/dist/app/_app/immutable/chunks/Bye3lL0c.js +1 -0
  35. package/dist/app/_app/immutable/chunks/C58PZtCD.js +4 -0
  36. package/dist/app/_app/immutable/chunks/CAzydqEO.js +1 -0
  37. package/dist/app/_app/immutable/chunks/CCch3uox.js +1 -0
  38. package/dist/app/_app/immutable/chunks/CIlSMUH9.js +1 -0
  39. package/dist/app/_app/immutable/chunks/CO1vUXfR.js +1 -0
  40. package/dist/app/_app/immutable/chunks/CPbD8C65.js +5 -0
  41. package/dist/app/_app/immutable/chunks/CRTcXoMo.js +1 -0
  42. package/dist/app/_app/immutable/chunks/CjjyIQAO.js +1 -0
  43. package/dist/app/_app/immutable/chunks/CuXAxjvF.js +1 -0
  44. package/dist/app/_app/immutable/chunks/CvyVA_jC.js +1 -0
  45. package/dist/app/_app/immutable/chunks/CxGCFVdy.js +1 -0
  46. package/dist/app/_app/immutable/chunks/D0Ty6LN0.js +1 -0
  47. package/dist/app/_app/immutable/chunks/D2AaQUUW.js +1 -0
  48. package/dist/app/_app/immutable/chunks/D2BnX0Uk.js +3 -0
  49. package/dist/app/_app/immutable/chunks/DJc8C0NK.js +1 -0
  50. package/dist/app/_app/immutable/chunks/DKMlMI4a.js +1 -0
  51. package/dist/app/_app/immutable/chunks/DVXZkpbf.js +1 -0
  52. package/dist/app/_app/immutable/chunks/DVt8ukQ_.js +1 -0
  53. package/dist/app/_app/immutable/chunks/DZPlYdq_.js +1 -0
  54. package/dist/app/_app/immutable/chunks/Db0q5_zr.js +1 -0
  55. package/dist/app/_app/immutable/chunks/Dfvzj6n2.js +1 -0
  56. package/dist/app/_app/immutable/chunks/Dh958be7.js +1 -0
  57. package/dist/app/_app/immutable/chunks/DjKLLdnY.js +15 -0
  58. package/dist/app/_app/immutable/chunks/Doz7YX1W.js +1 -0
  59. package/dist/app/_app/immutable/chunks/DthYhn6Y.js +2 -0
  60. package/dist/app/_app/immutable/chunks/DtuTIrAM.js +1 -0
  61. package/dist/app/_app/immutable/chunks/HclGiUj8.js +1 -0
  62. package/dist/app/_app/immutable/chunks/Hx0TNsV3.js +1 -0
  63. package/dist/app/_app/immutable/chunks/RobXhXPM.js +1 -0
  64. package/dist/app/_app/immutable/chunks/V9ZjaxiY.js +1 -0
  65. package/dist/app/_app/immutable/chunks/Y5urAfNy.js +1 -0
  66. package/dist/app/_app/immutable/chunks/caXkbKD3.js +1 -0
  67. package/dist/app/_app/immutable/chunks/devYm2ud.js +1 -0
  68. package/dist/app/_app/immutable/chunks/mtZWP0zR.js +1 -0
  69. package/dist/app/_app/immutable/chunks/vDgBJUjM.js +1 -0
  70. package/dist/app/_app/immutable/chunks/xIq_fFFM.js +1 -0
  71. package/dist/app/_app/immutable/chunks/xihTtKlq.js +1 -0
  72. package/dist/app/_app/immutable/chunks/z05MoCFz.js +1 -0
  73. package/dist/app/_app/immutable/entry/app.CLAerUAN.js +2 -0
  74. package/dist/app/_app/immutable/entry/start.D3MqnNci.js +1 -0
  75. package/dist/app/_app/immutable/nodes/0.UTMEigHJ.js +1 -0
  76. package/dist/app/_app/immutable/nodes/1.Cn4f11bT.js +1 -0
  77. package/dist/app/_app/immutable/nodes/2.B39cIcr2.js +6 -0
  78. package/dist/app/_app/version.json +1 -0
  79. package/dist/app/index.html +82 -0
  80. package/dist/aws/clients.d.ts +70 -0
  81. package/dist/aws/clients.js +52 -0
  82. package/dist/aws/errors.d.ts +41 -0
  83. package/dist/aws/errors.js +70 -0
  84. package/dist/aws/firehose.d.ts +228 -0
  85. package/dist/aws/firehose.js +347 -0
  86. package/dist/aws/glue.d.ts +103 -0
  87. package/dist/aws/glue.js +225 -0
  88. package/dist/aws/lambda.d.ts +132 -0
  89. package/dist/aws/lambda.js +339 -0
  90. package/dist/aws/s3tables.d.ts +120 -0
  91. package/dist/aws/s3tables.js +281 -0
  92. package/dist/backfill.d.ts +100 -0
  93. package/dist/backfill.js +294 -0
  94. package/dist/commands.d.ts +124 -0
  95. package/dist/commands.js +336 -0
  96. package/dist/config.d.ts +162 -0
  97. package/dist/config.js +317 -0
  98. package/dist/fixture-ingest.d.ts +49 -0
  99. package/dist/fixture-ingest.js +43 -0
  100. package/dist/fixture-query.d.ts +39 -0
  101. package/dist/fixture-query.js +70 -0
  102. package/dist/index.d.ts +35 -0
  103. package/dist/index.js +35 -0
  104. package/dist/nodes.d.ts +404 -0
  105. package/dist/nodes.js +2708 -0
  106. package/dist/paths.d.ts +45 -0
  107. package/dist/paths.js +47 -0
  108. package/dist/plugin.d.ts +102 -0
  109. package/dist/plugin.js +248 -0
  110. package/dist/ports.d.ts +113 -0
  111. package/dist/ports.js +35 -0
  112. package/dist/queries.d.ts +301 -0
  113. package/dist/queries.js +414 -0
  114. package/dist/schema.d.ts +240 -0
  115. package/dist/schema.js +154 -0
  116. package/dist/server.d.ts +150 -0
  117. package/dist/server.js +499 -0
  118. package/dist/transform/bots.d.ts +47 -0
  119. package/dist/transform/bots.js +73 -0
  120. package/dist/transform/handler.d.ts +135 -0
  121. package/dist/transform/handler.js +177 -0
  122. package/dist/transform/map-record.d.ts +110 -0
  123. package/dist/transform/map-record.js +275 -0
  124. package/dist/transform/visitor-key.d.ts +83 -0
  125. package/dist/transform/visitor-key.js +120 -0
  126. package/dist/transform-bundle/index.mjs +21456 -0
  127. package/dist/transform-bundle/transform-manifest.json +4 -0
  128. package/dist/transform-hash.d.ts +135 -0
  129. package/dist/transform-hash.js +186 -0
  130. package/dist/write-transform-manifest.mjs +365 -0
  131. package/package.json +59 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * One attached DuckDB session, shared by the two adapters that need one: the
3
+ * read path behind `AnalyticsQuery` (`duckdb-query.ts`) and the write path
4
+ * behind `AnalyticsIngest` (`duckdb-ingest.ts`). The change spec asks for the
5
+ * ingest port to be "implemented by the same DuckDB adapter" as the query
6
+ * port; two files with one session module between them is what that means in
7
+ * practice, and the alternative - a second copy of the credential secret, the
8
+ * attach, the quoting and the error translation - is the duplication
9
+ * DEVELOPMENT.md §Definition of done bans, in the one module where a
10
+ * divergence would be a security difference rather than a style one.
11
+ *
12
+ * **This is the only module in the repo that imports the DuckDB node-api
13
+ * package.** (Named in prose rather than spelled as the specifier, so a check
14
+ * for that specifier over this tree is not satisfied by a comment about it.)
15
+ * Neither adapter names a vendor type, and no module outside `adapters/` names
16
+ * DuckDB at all - which is what `ports.ts` promises and what the change spec's
17
+ * §Ports → `AnalyticsQuery` requires: DuckDB's iceberg extension is documented
18
+ * as *preview*, so its attach syntax may move, and when it does the edit lands
19
+ * here rather than across the dashboard and the backfill.
20
+ *
21
+ * **Credentials are injected, never resolved by DuckDB.** A session takes a
22
+ * `CredentialProvider` - core's own chain, the one `deploy` already signs with
23
+ * (`createCredentialProvider`, `packages/core/src/aws/credentials.ts`) -
24
+ * resolves it, and names the secret it builds in the `ATTACH`. DuckDB
25
+ * therefore has exactly one credential source and no reason to consult its
26
+ * own; a session that works for `deploy` works for the dashboard and for a
27
+ * backfill, which is the spec's §Analytics dashboard → Credentials decision.
28
+ *
29
+ * **The credential values are bound, not spelled.** `CREATE SECRET` accepts
30
+ * `$name` placeholders (verified against DuckDB 1.5.5, 2026-08-30), so the
31
+ * statement this module builds is a constant and the access key, secret and
32
+ * session token travel as bind values. That is not a style preference: DuckDB's
33
+ * parser echoes the offending line back in a syntax error (`LINE 1: ...`), so a
34
+ * credential spliced into the statement text could reach an error message, a
35
+ * log, or a thrown stack. Bound, it cannot. {@link redactorFor} is the second
36
+ * half of the same property, covering a message DuckDB builds for itself.
37
+ *
38
+ * **No vendor error object escapes.** Every DuckDB call runs inside
39
+ * {@link DuckDbSession.step}, and what leaves an adapter is always a plain repo
40
+ * `Error` naming the operation, the attach target and the step that failed.
41
+ * Unlike `createNodeFileSystem`'s `contextualise`
42
+ * (`packages/core/src/adapters/node-fs.ts`) nothing is attached as `cause`: a
43
+ * `cause` keeps the vendor error reachable, and `err.cause.message` is exactly
44
+ * the string the redaction above exists to control. The vendor's own words are
45
+ * preserved - redacted - inside the raised message instead.
46
+ *
47
+ * **The relation is bound here because only here is there a context to bind it
48
+ * from.** `queries.ts` reads one fixed relation, `PAGE_VIEWS_RELATION`, because
49
+ * SQL binds values and not identifiers and that module exists to make splicing
50
+ * impossible. A session holds the plugin context, so it takes
51
+ * `resolveAnalyticsConfig(ctx)` - never a caller-supplied bucket name, so
52
+ * task 44's `ENV_DERIVED` seal is honoured and staging cannot resolve to
53
+ * production's Iceberg table - and offers the configured
54
+ * `<catalog>.<namespace>.<table>` triple as {@link DuckDbSession.relation}.
55
+ */
56
+ import type { CredentialProvider, PluginContext } from 'blogwright-core';
57
+ import { type AnalyticsConfig, type ResolvedAnalyticsConfig } from '../config.js';
58
+ import type { QueryRow } from '../ports.js';
59
+ /**
60
+ * Values bound to a statement's placeholders. Wider than the read path's own
61
+ * bindings, which are days and flags: an inserted row carries the column types
62
+ * `schema.ts` declares, so a number, a boolean and an absent (null) value all
63
+ * have to travel.
64
+ */
65
+ export type DuckDbBindings = Readonly<Record<string, string | number | boolean | null>>;
66
+ /**
67
+ * The DuckDB surface the adapters use, narrowed to the two operations they
68
+ * need. Declared here rather than in `ports.ts` because it is not a domain
69
+ * port - no domain module may name it - but the seam a test substitutes at to
70
+ * observe the statements an adapter issues without an AWS account.
71
+ */
72
+ export interface DuckDbConnection {
73
+ /** Run one statement, binding `$name` placeholders from `bindings`. */
74
+ run(sql: string, bindings: DuckDbBindings): Promise<readonly QueryRow[]>;
75
+ /** Release the connection. Called when a session's setup failed. */
76
+ close(): void;
77
+ }
78
+ /** How a {@link DuckDbConnection} is obtained. Defaults to {@link connectDuckDb}. */
79
+ export type DuckDbConnect = () => Promise<DuckDbConnection>;
80
+ /**
81
+ * The slice of a plugin context a session reads. `env`, `config` and
82
+ * `pluginConfig` are what `resolveAnalyticsConfig` needs; `accountId` and
83
+ * `config.region` are what the table bucket's ARN needs. Taken as a `Pick` of
84
+ * core's own `PluginContext` rather than a restatement, so the four members
85
+ * cannot drift from the SPI and a plugin command passes `ctx` straight
86
+ * through.
87
+ */
88
+ export type DuckDbSessionContext = Pick<PluginContext<AnalyticsConfig>, 'env' | 'config' | 'pluginConfig' | 'accountId'>;
89
+ /** What {@link createDuckDbSession} is built from. */
90
+ export interface DuckDbSessionOptions {
91
+ /**
92
+ * The plugin context. The session resolves the analytics config from it
93
+ * itself: `tableBucket` is sealed under task 44's `ENV_DERIVED` symbol and
94
+ * `resolveAnalyticsConfig` is the only way to it, so no caller can hand a
95
+ * session a bucket name that dropped the environment.
96
+ */
97
+ readonly ctx: DuckDbSessionContext;
98
+ /**
99
+ * Credentials for the catalog, resolved through core's provider chain
100
+ * (`createCredentialProvider`). A test passes `staticCredentials`.
101
+ */
102
+ readonly credentials: CredentialProvider;
103
+ /**
104
+ * Whether the catalog is attached read-only. The dashboard's read path
105
+ * attaches read-only and the backfill's write path does not; nothing else
106
+ * about the two sessions differs.
107
+ */
108
+ readonly readOnly: boolean;
109
+ /**
110
+ * How a DuckDB connection is obtained. Defaults to {@link connectDuckDb};
111
+ * a test substitutes a recording connection here.
112
+ */
113
+ readonly connect?: DuckDbConnect | undefined;
114
+ }
115
+ /**
116
+ * Quote an identifier for the statement text. `validateAnalyticsConfig` already
117
+ * holds `namespace` and `table` to `^[a-z0-9_]+$`, so there is no quote
118
+ * character to escape and this adds no second validation of a rule config owns.
119
+ * What it does add is reserved words: `web` and `page_views` need no quoting,
120
+ * but `order` and `table` match that same pattern and an operator may configure
121
+ * either.
122
+ */
123
+ export declare function quoteIdentifier(identifier: string): string;
124
+ /**
125
+ * The configured `<catalog>.<namespace>.<table>` triple every statement reads
126
+ * or writes, inside the attached catalog. This is the binding task 45
127
+ * delegated to the adapter layer.
128
+ */
129
+ export declare function pageViewsRelation(config: ResolvedAnalyticsConfig): string;
130
+ /**
131
+ * Open a real DuckDB connection - the default {@link DuckDbConnect}, and the
132
+ * one place the vendor package is called. Exported so the test suite can run
133
+ * statements against a real local table without naming the vendor package
134
+ * itself, which is what keeps DuckDB confined to this file.
135
+ */
136
+ export declare const connectDuckDb: DuckDbConnect;
137
+ /** An attached DuckDB session, and the vocabulary an adapter reports failures in. */
138
+ export interface DuckDbSession {
139
+ /** The resolved analytics config the session was built against. */
140
+ readonly config: ResolvedAnalyticsConfig;
141
+ /** The S3 Tables bucket ARN the catalog is attached from. */
142
+ readonly attachTarget: string;
143
+ /** The `<catalog>.<namespace>.<table>` triple statements name. */
144
+ readonly relation: string;
145
+ /**
146
+ * The open connection, attached and ready. Opened lazily on the first call
147
+ * and then reused, so building a session touches neither the network nor the
148
+ * native library. A session whose setup failed is closed and forgotten
149
+ * rather than cached, so a dashboard left open across an expired SSO session
150
+ * recovers on the next request instead of repeating the first failure
151
+ * forever.
152
+ */
153
+ open(): Promise<DuckDbConnection>;
154
+ /** Run one step, so no vendor error object escapes it. */
155
+ step<T>(description: string, run: () => Promise<T>): Promise<T>;
156
+ /**
157
+ * The words that follow "failed while" in an adapter's message: the failing
158
+ * step's own description when the failure came from {@link step}, and
159
+ * `fallback` with the redacted vendor text otherwise.
160
+ */
161
+ detail(err: unknown, fallback: string): string;
162
+ }
163
+ /**
164
+ * Build a session. Nothing here connects: the connection is opened on the
165
+ * first {@link DuckDbSession.open}, so a command that never reaches the table
166
+ * starts nothing and binds its own listener first.
167
+ */
168
+ export declare function createDuckDbSession(opts: DuckDbSessionOptions): DuckDbSession;
@@ -0,0 +1,330 @@
1
+ /**
2
+ * One attached DuckDB session, shared by the two adapters that need one: the
3
+ * read path behind `AnalyticsQuery` (`duckdb-query.ts`) and the write path
4
+ * behind `AnalyticsIngest` (`duckdb-ingest.ts`). The change spec asks for the
5
+ * ingest port to be "implemented by the same DuckDB adapter" as the query
6
+ * port; two files with one session module between them is what that means in
7
+ * practice, and the alternative - a second copy of the credential secret, the
8
+ * attach, the quoting and the error translation - is the duplication
9
+ * DEVELOPMENT.md §Definition of done bans, in the one module where a
10
+ * divergence would be a security difference rather than a style one.
11
+ *
12
+ * **This is the only module in the repo that imports the DuckDB node-api
13
+ * package.** (Named in prose rather than spelled as the specifier, so a check
14
+ * for that specifier over this tree is not satisfied by a comment about it.)
15
+ * Neither adapter names a vendor type, and no module outside `adapters/` names
16
+ * DuckDB at all - which is what `ports.ts` promises and what the change spec's
17
+ * §Ports → `AnalyticsQuery` requires: DuckDB's iceberg extension is documented
18
+ * as *preview*, so its attach syntax may move, and when it does the edit lands
19
+ * here rather than across the dashboard and the backfill.
20
+ *
21
+ * **Credentials are injected, never resolved by DuckDB.** A session takes a
22
+ * `CredentialProvider` - core's own chain, the one `deploy` already signs with
23
+ * (`createCredentialProvider`, `packages/core/src/aws/credentials.ts`) -
24
+ * resolves it, and names the secret it builds in the `ATTACH`. DuckDB
25
+ * therefore has exactly one credential source and no reason to consult its
26
+ * own; a session that works for `deploy` works for the dashboard and for a
27
+ * backfill, which is the spec's §Analytics dashboard → Credentials decision.
28
+ *
29
+ * **The credential values are bound, not spelled.** `CREATE SECRET` accepts
30
+ * `$name` placeholders (verified against DuckDB 1.5.5, 2026-08-30), so the
31
+ * statement this module builds is a constant and the access key, secret and
32
+ * session token travel as bind values. That is not a style preference: DuckDB's
33
+ * parser echoes the offending line back in a syntax error (`LINE 1: ...`), so a
34
+ * credential spliced into the statement text could reach an error message, a
35
+ * log, or a thrown stack. Bound, it cannot. {@link redactorFor} is the second
36
+ * half of the same property, covering a message DuckDB builds for itself.
37
+ *
38
+ * **No vendor error object escapes.** Every DuckDB call runs inside
39
+ * {@link DuckDbSession.step}, and what leaves an adapter is always a plain repo
40
+ * `Error` naming the operation, the attach target and the step that failed.
41
+ * Unlike `createNodeFileSystem`'s `contextualise`
42
+ * (`packages/core/src/adapters/node-fs.ts`) nothing is attached as `cause`: a
43
+ * `cause` keeps the vendor error reachable, and `err.cause.message` is exactly
44
+ * the string the redaction above exists to control. The vendor's own words are
45
+ * preserved - redacted - inside the raised message instead.
46
+ *
47
+ * **The relation is bound here because only here is there a context to bind it
48
+ * from.** `queries.ts` reads one fixed relation, `PAGE_VIEWS_RELATION`, because
49
+ * SQL binds values and not identifiers and that module exists to make splicing
50
+ * impossible. A session holds the plugin context, so it takes
51
+ * `resolveAnalyticsConfig(ctx)` - never a caller-supplied bucket name, so
52
+ * task 44's `ENV_DERIVED` seal is honoured and staging cannot resolve to
53
+ * production's Iceberg table - and offers the configured
54
+ * `<catalog>.<namespace>.<table>` triple as {@link DuckDbSession.relation}.
55
+ */
56
+ import { DuckDBInstance } from '@duckdb/node-api';
57
+ import { resolveAnalyticsConfig, } from '../config.js';
58
+ /**
59
+ * The name the attached catalog takes inside a DuckDB session. A module
60
+ * constant and not derived from configuration: it is private to one
61
+ * connection, so nothing is gained by letting an operator name it, and a
62
+ * fixed name keeps one more configured string out of the statement text.
63
+ */
64
+ const CATALOG_ALIAS = 'analytics';
65
+ /**
66
+ * The name of the secret the credentials land in. The `ATTACH` names it
67
+ * explicitly rather than letting DuckDB pick a secret by scope, which is what
68
+ * makes "an adapter never lets DuckDB resolve its own chain" a property of
69
+ * the statement rather than of the ambient secret table.
70
+ */
71
+ const SECRET_NAME = 'blogwright_analytics';
72
+ /**
73
+ * The extensions the S3 Tables attach needs: `iceberg` for the catalog itself,
74
+ * `httpfs` for the `s3` secret type and the object reads behind it. Loaded
75
+ * explicitly rather than left to DuckDB's autoloading, so a machine that
76
+ * cannot reach the extension repository fails at a named setup step instead of
77
+ * midway through a statement.
78
+ */
79
+ const REQUIRED_EXTENSIONS = ['httpfs', 'iceberg'];
80
+ /** What replaces a credential value in a message that came back carrying one. */
81
+ const REDACTED = '<redacted>';
82
+ /**
83
+ * A failed DuckDB step, carrying the words that follow "failed while" in the
84
+ * message a caller sees. Module-private and always caught by an adapter's own
85
+ * error translation, so it is a way of passing the step description outwards,
86
+ * never a type any caller can observe.
87
+ */
88
+ class DuckDbStepFailure extends Error {
89
+ }
90
+ /** What an error says for itself, whether or not it is an `Error`. */
91
+ function describeError(err) {
92
+ return err instanceof Error ? err.message : String(err);
93
+ }
94
+ /**
95
+ * Quote an identifier for the statement text. `validateAnalyticsConfig` already
96
+ * holds `namespace` and `table` to `^[a-z0-9_]+$`, so there is no quote
97
+ * character to escape and this adds no second validation of a rule config owns.
98
+ * What it does add is reserved words: `web` and `page_views` need no quoting,
99
+ * but `order` and `table` match that same pattern and an operator may configure
100
+ * either.
101
+ */
102
+ export function quoteIdentifier(identifier) {
103
+ return `"${identifier}"`;
104
+ }
105
+ /**
106
+ * Quote a value as a SQL string literal, doubling every `'` so the literal
107
+ * cannot be closed from inside it.
108
+ *
109
+ * This is deliberately not conditional on the value having been validated.
110
+ * `ATTACH` takes its target as a literal and DuckDB accepts no placeholder
111
+ * there, so this is the one place in this module where a configured value is
112
+ * spelled into statement text rather than bound - and `runAndReadAll` executes
113
+ * *every* statement in the string it is handed, after `CREATE SECRET` has
114
+ * already put the operator's real AWS credentials into the session. A single
115
+ * unescaped quote in the attach target is therefore arbitrary SQL execution
116
+ * under those credentials, with `httpfs` loaded.
117
+ *
118
+ * Of the ARN's three components `tableBucket` is held to `^[0-9a-z-]{3,63}$`
119
+ * and `accountId` comes from STS, but `config.region` is checked only for
120
+ * truthiness (`packages/core/src/config.ts`), so today a region *is* a way in.
121
+ * That gap is being closed upstream; this escape stays regardless. An adapter
122
+ * must not be one upstream change - a relaxed rule, a new field spliced into
123
+ * the ARN, a caller that assembles a context by hand - away from executing
124
+ * arbitrary SQL. The escape is local to the quote it protects and holds
125
+ * whatever validation elsewhere does or does not do.
126
+ */
127
+ function quoteLiteral(value) {
128
+ return `'${value.replaceAll("'", "''")}'`;
129
+ }
130
+ /**
131
+ * The configured `<catalog>.<namespace>.<table>` triple every statement reads
132
+ * or writes, inside the attached catalog. This is the binding task 45
133
+ * delegated to the adapter layer.
134
+ */
135
+ export function pageViewsRelation(config) {
136
+ return [CATALOG_ALIAS, config.namespace, config.table].map(quoteIdentifier).join('.');
137
+ }
138
+ /**
139
+ * The S3 Tables bucket's ARN - the attach target, and the string every error
140
+ * an adapter raises names, because it is what an operator checks permissions
141
+ * and region against. The `s3tables` ARN form is the one
142
+ * `S3TablesClient.createTableBucket` (`packages/analytics/src/aws/s3tables.ts`)
143
+ * documents.
144
+ */
145
+ function tableBucketArn(ctx, config) {
146
+ return `arn:aws:s3tables:${ctx.config.region}:${ctx.accountId}:bucket/${config.tableBucket}`;
147
+ }
148
+ /**
149
+ * The `CREATE SECRET` statement and the values it binds. The statement is a
150
+ * constant apart from whether the credentials carry a session token: an absent
151
+ * token drops the clause rather than binding a null, so DuckDB is never handed
152
+ * an empty `x-amz-security-token` to sign with.
153
+ */
154
+ function secretStatement(credentials, region) {
155
+ const clauses = [
156
+ 'TYPE s3',
157
+ 'PROVIDER config',
158
+ 'KEY_ID $access_key_id',
159
+ 'SECRET $secret_access_key',
160
+ 'REGION $region',
161
+ ];
162
+ const bindings = {
163
+ access_key_id: credentials.accessKeyId,
164
+ secret_access_key: credentials.secretAccessKey,
165
+ region,
166
+ };
167
+ if (credentials.sessionToken !== undefined) {
168
+ clauses.push('SESSION_TOKEN $session_token');
169
+ bindings.session_token = credentials.sessionToken;
170
+ }
171
+ return {
172
+ sql: `CREATE OR REPLACE SECRET ${SECRET_NAME} (${clauses.join(', ')})`,
173
+ bindings,
174
+ };
175
+ }
176
+ /**
177
+ * The `ATTACH` statement. `READ_ONLY` is an option the iceberg catalog accepts
178
+ * rather than one it ignores - DuckDB rejects an unrecognised attach option
179
+ * outright ("Unhandled options found"), so an attach that parses is an attach
180
+ * whose mode was understood - and on the read path it is the spec's "The
181
+ * dashboard's own attach stays read-only" as a property of the connection, not
182
+ * merely of the port's shape. The backfill's session omits it, because
183
+ * `INSERT` is the whole point of that session; nothing else about the two
184
+ * statements differs, so the difference is one clause rather than two
185
+ * statements that could drift.
186
+ */
187
+ function attachStatement(target, readOnly) {
188
+ const options = [
189
+ 'TYPE iceberg',
190
+ 'ENDPOINT_TYPE s3_tables',
191
+ `SECRET ${SECRET_NAME}`,
192
+ ...(readOnly ? ['READ_ONLY'] : []),
193
+ ];
194
+ return `ATTACH ${quoteLiteral(target)} AS ${quoteIdentifier(CATALOG_ALIAS)} (${options.join(', ')})`;
195
+ }
196
+ /**
197
+ * Replace every credential value in `text`. DuckDB builds some of its own
198
+ * messages out of the values it was handed, so a bound credential can still
199
+ * reach a message an adapter is about to raise; this is what keeps it from
200
+ * leaving. Empty values are skipped - replacing the empty string matches
201
+ * everywhere.
202
+ */
203
+ function redactorFor(credentials) {
204
+ const secrets = [
205
+ credentials.accessKeyId,
206
+ credentials.secretAccessKey,
207
+ credentials.sessionToken ?? '',
208
+ ].filter((secret) => secret.length > 0);
209
+ return (text) => secrets.reduce((redacted, secret) => redacted.replaceAll(secret, REDACTED), text);
210
+ }
211
+ /**
212
+ * One `page_views` result cell, in this package's own vocabulary. A SQL NULL
213
+ * becomes `undefined` so the caller sees an absent key, which is `QueryRow`'s
214
+ * rule. Counts arrive as `BIGINT`, and a range total as `HUGEINT`, so both
215
+ * arrive as `bigint`; anything past `Number.MAX_SAFE_INTEGER` raises rather
216
+ * than rounding, because a silently rounded view count is worse than no chart.
217
+ * DATE and the other typed columns come back as DuckDB value objects whose
218
+ * `toString` is the SQL rendering - a `day` reads back as `2026-08-01`, with
219
+ * no `Date` and so no time zone anywhere near it.
220
+ */
221
+ function toQueryValue(column, value) {
222
+ if (value === null)
223
+ return undefined;
224
+ if (typeof value === 'bigint') {
225
+ const asNumber = Number(value);
226
+ if (!Number.isSafeInteger(asNumber)) {
227
+ throw new Error(`analytics result column "${column}" is ${value}, past the largest integer JavaScript counts exactly`);
228
+ }
229
+ return asNumber;
230
+ }
231
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
232
+ return value;
233
+ }
234
+ return String(value);
235
+ }
236
+ /** One result row, with every SQL NULL dropped rather than carried as a null. */
237
+ function toQueryRow(row) {
238
+ const converted = {};
239
+ for (const [column, value] of Object.entries(row)) {
240
+ const cell = toQueryValue(column, value);
241
+ if (cell !== undefined)
242
+ converted[column] = cell;
243
+ }
244
+ return converted;
245
+ }
246
+ /**
247
+ * Open a real DuckDB connection - the default {@link DuckDbConnect}, and the
248
+ * one place the vendor package is called. Exported so the test suite can run
249
+ * statements against a real local table without naming the vendor package
250
+ * itself, which is what keeps DuckDB confined to this file.
251
+ */
252
+ export const connectDuckDb = async () => {
253
+ const instance = await DuckDBInstance.create(':memory:');
254
+ const connection = await instance.connect();
255
+ return {
256
+ async run(sql, bindings) {
257
+ const reader = await connection.runAndReadAll(sql, { ...bindings });
258
+ return reader.getRowObjects().map(toQueryRow);
259
+ },
260
+ close() {
261
+ connection.closeSync();
262
+ instance.closeSync();
263
+ },
264
+ };
265
+ };
266
+ /**
267
+ * Build a session. Nothing here connects: the connection is opened on the
268
+ * first {@link DuckDbSession.open}, so a command that never reaches the table
269
+ * starts nothing and binds its own listener first.
270
+ */
271
+ export function createDuckDbSession(opts) {
272
+ const config = resolveAnalyticsConfig(opts.ctx);
273
+ const attachTarget = tableBucketArn(opts.ctx, config);
274
+ const relation = pageViewsRelation(config);
275
+ const connect = opts.connect ?? connectDuckDb;
276
+ /**
277
+ * Redaction needs the resolved credentials, and they are resolved inside the
278
+ * session; this holds the redactor the current session installed so a failure
279
+ * raised while executing a statement is scrubbed by the same rule a failure
280
+ * raised while creating the secret is.
281
+ */
282
+ let redact = (text) => text;
283
+ let pending;
284
+ async function step(description, run) {
285
+ try {
286
+ return await run();
287
+ }
288
+ catch (err) {
289
+ throw new DuckDbStepFailure(`${description}: ${redact(describeError(err))}`);
290
+ }
291
+ }
292
+ async function openSession() {
293
+ const credentials = await step('resolving AWS credentials', () => opts.credentials());
294
+ redact = redactorFor(credentials);
295
+ const connection = await step('opening a DuckDB connection', connect);
296
+ try {
297
+ for (const extension of REQUIRED_EXTENSIONS) {
298
+ await step(`installing the ${extension} extension`, () => connection.run(`INSTALL ${extension}`, {}));
299
+ await step(`loading the ${extension} extension`, () => connection.run(`LOAD ${extension}`, {}));
300
+ }
301
+ const secret = secretStatement(credentials, opts.ctx.config.region);
302
+ await step('creating the credentials secret', () => connection.run(secret.sql, secret.bindings));
303
+ await step(opts.readOnly ? 'attaching the catalog read-only' : 'attaching the catalog', () => connection.run(attachStatement(attachTarget, opts.readOnly), {}));
304
+ }
305
+ catch (err) {
306
+ connection.close();
307
+ throw err;
308
+ }
309
+ return connection;
310
+ }
311
+ return {
312
+ config,
313
+ attachTarget,
314
+ relation,
315
+ step,
316
+ open() {
317
+ const current = (pending ??= openSession());
318
+ return current.catch((err) => {
319
+ if (pending === current)
320
+ pending = undefined;
321
+ throw err;
322
+ });
323
+ },
324
+ detail(err, fallback) {
325
+ return err instanceof DuckDbStepFailure
326
+ ? err.message
327
+ : `${fallback}: ${redact(describeError(err))}`;
328
+ },
329
+ };
330
+ }
@@ -0,0 +1 @@
1
+ @layer theme,base,components,utilities;:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;--color-surface-100:var(--lightningcss-light,#fff)var(--lightningcss-dark,#16181d);--color-surface-200:var(--lightningcss-light,#f4f5f7)var(--lightningcss-dark,#1d2026);--color-surface-content:var(--lightningcss-light,#1b1f27)var(--lightningcss-dark,#e6e8ee);--color-surface-muted:var(--lightningcss-light,#5b6473)var(--lightningcss-dark,#98a1b2);--color-surface-border:var(--lightningcss-light,#dfe2e8)var(--lightningcss-dark,#2c313a);--color-primary:var(--lightningcss-light,#2f5fd0)var(--lightningcss-dark,#7aa2f7);--radius:8px;--gap:16px}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}*{box-sizing:border-box}body{background:var(--color-surface-200);color:var(--color-surface-content);margin:0;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.5}.page{max-width:1200px;padding:var(--gap);margin:0 auto}.page-header{justify-content:space-between;align-items:flex-end;gap:var(--gap);margin-bottom:var(--gap);flex-wrap:wrap;display:flex}.page-header h1{margin:0;font-size:20px;font-weight:600}.page-header p{color:var(--color-surface-muted);margin:4px 0 0}.controls{flex-wrap:wrap;align-items:flex-end;gap:12px;display:flex}.control{flex-direction:column;gap:4px;display:flex}.control span{color:var(--color-surface-muted);font-size:12px}.control input,.control select{background:var(--color-surface-100);border:1px solid var(--color-surface-border);border-radius:var(--radius);color:inherit;font:inherit;padding:6px 8px}.range-error{border:1px solid var(--color-surface-border);border-radius:var(--radius);background:var(--color-surface-100);margin-bottom:var(--gap);border-left:3px solid #d04a4a;padding:10px 12px}.panels{gap:var(--gap);grid-template-columns:repeat(auto-fit,minmax(360px,1fr));display:grid}.panel{background:var(--color-surface-100);border:1px solid var(--color-surface-border);border-radius:var(--radius);flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex}.panel h2{margin:0;font-size:15px;font-weight:600}.panel-meaning{color:var(--color-surface-muted);margin:0;font-size:12px}.panel-state{color:var(--color-surface-muted);text-align:center;justify-content:center;align-items:center;height:220px;display:flex}.panel-error{color:#c0392b}.panel-chart{height:220px}.panel-total{border-top:1px solid var(--color-surface-border);justify-content:space-between;gap:8px;margin:0;padding-top:8px;display:flex}.panel-total dt{color:var(--color-surface-muted)}.panel-total dd{font-variant-numeric:tabular-nums;margin:0;font-weight:600}.panel-note{color:var(--color-surface-muted);margin:0;font-size:12px}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-layout-svg.svelte-4rngwg){position:absolute;inset:0;overflow:visible}:where(.lc-layout-svg.svelte-4rngwg).disablePointerEvents{pointer-events:none}:where(.lc-layout-svg.svelte-4rngwg).clip{overflow:hidden}:where(.lc-layout-canvas.svelte-dr1886){position:absolute;inset:0}:where(.lc-layout-canvas.svelte-dr1886).disablePointerEvents{pointer-events:none}:where(.lc-hit-canvas.svelte-dr1886){pointer-events:none;image-rendering:pixelated;opacity:0;position:absolute;inset:0}:where(.lc-hit-canvas.svelte-dr1886).debug{border:1px solid var(--color-danger,red);opacity:1}:where(.lc-layout-html.svelte-xy3xrb){position:absolute;inset:0}:where(.lc-layout-html.svelte-xy3xrb).disablePointerEvents{pointer-events:none}:where(.lc-layout-html.svelte-xy3xrb).clip{overflow:hidden}}@layer components{:where(.lc-tooltip-context-container.svelte-1xyc5r3){position:absolute}:where(.lc-tooltip-context.svelte-1xyc5r3){touch-action:var(--touch-action);position:absolute}:where(.lc-tooltip-context.svelte-1xyc5r3).debug{outline:1px solid var(--color-danger);background-color:color-mix(in oklab, var(--color-danger) 10%, transparent)}:where(.lc-tooltip-voronoi-path).debug{stroke:var(--color-danger);fill:color-mix(in oklab, var(--color-danger) 10%, transparent)}:where(.lc-tooltip-rect.svelte-1xyc5r3){fill:#0000}:where(.lc-tooltip-rect.svelte-1xyc5r3).debug{stroke:var(--color-danger);fill:color-mix(in oklab, var(--color-danger) 10%, transparent)}:where(.lc-tooltip-quadtree-rect.svelte-1xyc5r3){fill:#0000}:where(.lc-tooltip-quadtree-rect.svelte-1xyc5r3).debug{stroke:var(--color-danger);fill:color-mix(in oklab, var(--color-danger) 10%, transparent)}:where(.lc-debug-frame){--fill-color:color-mix(in oklab, var(--color-danger) 10%, transparent)}:where(.lc-axis-rule),:where(.lc-axis-tick){--stroke-color:color-mix(in oklab, var(--color-surface-content,currentColor) 50%, transparent)}:where(.lc-axis-grid){--stroke-color:color-mix(in oklab, var(--color-surface-content,currentColor) 10%, transparent)}:where(.lc-axis-label,.lc-axis-tick-label){stroke:var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000));stroke-width:2px;font-size:10px;font-weight:300}:where(.lc-rule-x-line,.lc-rule-y-line,.lc-rule-x-radial-line,.lc-rule-y-radial-circle):not([class*=lc-axis],[class*=lc-grid]){--stroke-color:color-mix(in oklab, var(--color-surface-content,currentColor) 50%, transparent)}:where(.lc-rule-y-radial-circle){--fill-color:none}:where(.lc-grid-x-rule,.lc-grid-x-end-rule,.lc-grid-x-radial-line,.lc-grid-y-rule,.lc-grid-y-end-rule,.lc-grid-y-radial-line){--stroke-color:color-mix(in oklab, var(--color-surface-content,currentColor) 10%, transparent)}:where(.lc-grid-y-radial-circle){--fill-color:none;--stroke-color:color-mix(in oklab, var(--color-surface-content,currentColor) 10%, transparent)}:where(.lc-highlight-area){--fill-color:color-mix(in oklab, var(--color-surface-content,currentColor) 5%, transparent)}:where(.lc-highlight-bar){--fill-color:var(--color-primary,currentColor)}:where(.lc-highlight-line){--stroke-color:color-mix(in oklab, var(--color-surface-content,currentColor) 20%, transparent);stroke-width:2px;stroke-dasharray:2 2;pointer-events:none}:where(.lc-highlight-point){--stroke-color:white;--fill-color:var(--color-primary,currentColor);paint-order:stroke;filter:drop-shadow(var(--drop-shadow-sm,0 1px 2px #00000026))}}.lc-root-container.svelte-17r60jn,.lc-root-container.svelte-17r60jn *{box-sizing:border-box}.lc-root-container.svelte-17r60jn{-webkit-user-select:var(--lc-user-select,none);user-select:var(--lc-user-select,none)}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-brush-context.svelte-3rn8dw){touch-action:none;position:absolute}:where(.lc-brush-container.svelte-3rn8dw){position:absolute}:where(.lc-brush-range.svelte-3rn8dw){cursor:move;-webkit-user-select:none;user-select:none;z-index:10;background:color-mix(in oklab, var(--color-surface-content,currentColor) 10%, transparent);position:absolute}:where(.lc-brush-handle.svelte-3rn8dw){-webkit-user-select:none;user-select:none;z-index:10;position:absolute}:where(.lc-brush-handle.svelte-3rn8dw)[data-position=top],:where(.lc-brush-handle.svelte-3rn8dw)[data-position=bottom]{cursor:ns-resize}:where(.lc-brush-handle.svelte-3rn8dw)[data-position=left],:where(.lc-brush-handle.svelte-3rn8dw)[data-position=right]{cursor:ew-resize}}
@@ -0,0 +1 @@
1
+ @layer components{:where(.lc-annotation-line){--stroke-color:var(--color-surface-content,currentColor)}:where(.lc-annotation-line-label),:where(.lc-annotation-point-label){pointer-events:none;font-size:12px}:where(.lc-annotation-point-ring){--fill-color:none;--stroke-color:var(--color-surface-content,currentColor)}:where(.lc-annotation-point-link){--stroke-color:var(--color-surface-content,currentColor);fill:none;pointer-events:none}:where(.lc-annotation-range-label){pointer-events:none;font-size:12px}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-layout-svg .lc-circle,svg.lc-circle):not([fill]){fill:var(--fill-color)}:where(.lc-layout-svg .lc-circle,svg.lc-circle):not([stroke]){stroke:var(--stroke-color)}:where(.lc-circle){--fill-color:var(--color-surface-content,currentColor);--stroke-color:initial}:where(.lc-layout-html .lc-circle){box-sizing:border-box}:where(.lc-layout-html .lc-circle):not([background]){background:var(--fill-color)}:where(.lc-layout-html .lc-circle):not([border-color]){border-color:var(--stroke-color)}}
@@ -0,0 +1 @@
1
+ @layer components{:where(.lc-tooltip-header.svelte-bwtgwj){white-space:nowrap;border-bottom:1px solid color-mix(in oklab, var(--color-surface-content,currentColor) 20%, transparent);align-items:center;gap:8px;margin-bottom:4px;padding-bottom:4px;font-weight:600;display:flex}:where(.lc-tooltip-header-color.svelte-bwtgwj){background-color:var(--color);border-radius:9999px;flex-shrink:0;width:8px;height:8px;display:inline-block}:where(.lc-tooltip-item-root.svelte-mbbltt){display:contents}:where(.lc-tooltip-item-root[data-highlighted].svelte-mbbltt)>:where(.lc-tooltip-item-label.svelte-mbbltt,.lc-tooltip-item-value.svelte-mbbltt){opacity:1;transition:opacity .15s}:where(.lc-tooltip-item-root[data-highlighted=false].svelte-mbbltt)>:where(.lc-tooltip-item-label.svelte-mbbltt,.lc-tooltip-item-value.svelte-mbbltt){opacity:.1}:where(.lc-tooltip-item-color.svelte-mbbltt){background-color:var(--color);border-radius:9999px;width:8px;height:8px;display:inline-block}:where(.lc-tooltip-item-label.svelte-mbbltt){white-space:nowrap;align-items:center;gap:8px;display:flex}:where(.lc-tooltip-item-value.svelte-mbbltt){font-variant-numeric:tabular-nums}:where(.lc-tooltip-item-value.svelte-mbbltt)[data-align=right]{text-align:right}:where(.lc-tooltip-item-value.svelte-mbbltt)[data-align=center]{text-align:center}:where(.lc-tooltip-list.svelte-1i64ej2){grid-template-columns:1fr auto;align-items:start;gap:4px 8px;display:grid}:where(.lc-tooltip-separator.svelte-13b11yj){background-color:color-mix(in oklab, var(--color-surface-content,currentColor) 20%, transparent);border-radius:4px;grid-column:1/-1;height:1px;margin-top:4px;margin-bottom:4px}:where(.lc-tooltip-root.svelte-1019wmy){z-index:50;-webkit-user-select:none;user-select:none;position:absolute}:where(.lc-tooltip-root.svelte-1019wmy).portaled{position:fixed}:where(.lc-tooltip-root.svelte-1019wmy).disablePointerEvents{pointer-events:none}:where(.lc-tooltip-container.svelte-1019wmy):not([data-variant=none]){-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);border-radius:.25rem;height:100%;padding:4px 8px;font-size:.875rem;line-height:1.25rem;box-shadow:0 2px 1px -1px #0003,0 1px 1px #00000024,0 1px 3px #0000001f}:where(.lc-tooltip-container.svelte-1019wmy)[data-variant=default]{color:var(--color-surface-content,currentColor);background-color:color-mix(in oklab, var(--lightningcss-light,var(--color-surface-100,white))var(--lightningcss-dark,var(--color-surface-300,black)) 90%, transparent)}:where(.lc-tooltip-container.svelte-1019wmy)[data-variant=default] .label{color:color-mix(in oklab, var(--color-surface-content,currentColor) 75%, transparent)}:where(.lc-tooltip-container.svelte-1019wmy)[data-variant=invert]{color:var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000));background-color:color-mix(in oklab, var(--color-surface-content,currentColor) 90%, transparent)}:where(.lc-tooltip-container.svelte-1019wmy)[data-variant=invert] .label{color:color-mix(in oklab, var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000)) 50%, transparent)}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-group-div.svelte-yxzquv){position:absolute}}
@@ -0,0 +1 @@
1
+ @layer components{:where(.lc-labels-text){--fill-color:var(--color-surface-content,currentColor);--stroke-color:var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000));font-size:12px}:where(.lc-labels-text)[data-placement=inside],:where(.lc-labels-text)[data-placement=center]{--fill-color:var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000));--stroke-color:var(--color-surface-content,currentColor)}}
@@ -0,0 +1 @@
1
+ @layer components{:where(.lc-legend-container.svelte-1s27lqi){z-index:1;display:inline-block}:where(.lc-legend-container.svelte-1s27lqi)[data-placement]{position:absolute}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=top-left]{top:0;left:0}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=top]{top:0;left:50%;transform:translate(-50%)}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=top-right]{top:0;right:0}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=left]{top:50%;left:0;transform:translateY(-50%)}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=center]{top:50%;left:50%;transform:translate(-50%,-50%)}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=right]{top:50%;right:0;transform:translateY(-50%)}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=bottom-left]{bottom:0;left:0}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=bottom]{bottom:0;left:50%;transform:translate(-50%)}:where(.lc-legend-container.svelte-1s27lqi)[data-placement=bottom-right]{bottom:0;right:0}:where(.lc-legend-title.svelte-1s27lqi){font-size:10px;font-weight:600}:where(.lc-legend-ramp-svg.svelte-1s27lqi){overflow:visible}:where(.lc-legend-tick-text.svelte-1s27lqi){fill:var(--color-surface-content,currentColor);font-size:10px}:where(.lc-legend-tick-line.svelte-1s27lqi){stroke:var(--color-surface-content,currentColor)}:where(.lc-legend-indicator.svelte-1s27lqi){fill:var(--color-surface-content,currentColor)}:where(.lc-legend-swatch-group.svelte-1s27lqi){gap:.25rem 1rem;display:flex}:where(.lc-legend-swatch-group.svelte-1s27lqi)[data-orientation=vertical]{flex-direction:column}:where(.lc-legend-swatch-button.svelte-1s27lqi){white-space:nowrap;text-overflow:ellipsis;align-items:center;gap:.25rem;display:flex;overflow:hidden}:where(.lc-legend-swatch.svelte-1s27lqi){border-radius:9999px;flex-shrink:0;width:16px;height:16px}:where(.lc-legend-swatch-label.svelte-1s27lqi){color:var(--color-surface-content,currentColor);text-overflow:ellipsis;white-space:nowrap;font-size:.75rem;line-height:1.33333;overflow:hidden}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-layout-svg .lc-line,svg.lc-line):not([stroke]){stroke:var(--stroke-color)}:where(.lc-line){--stroke-color:var(--color-surface-content,currentColor)}:where(.lc-layout-html .lc-line):not([background-color]){background-color:var(--stroke-color)}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-marker){overflow:visible}:where(.lc-marker)[data-type=arrow],:where(.lc-marker)[data-type=circle-stroke],:where(.lc-marker)[data-type=square-stroke],:where(.lc-marker)[data-type=line]{fill:none;stroke:context-stroke;stroke-linecap:round;stroke-linejoin:round}:where(.lc-marker)[data-type=circle]{stroke:var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000))}:where(.lc-marker)[data-type=triangle],:where(.lc-marker)[data-type=dot],:where(.lc-marker)[data-type=circle],:where(.lc-marker)[data-type=square]{fill:context-stroke}:where(.lc-marker)[data-type=circle-stroke],:where(.lc-marker)[data-type=square-stroke]{fill:var(--color-surface-100,var(--lightningcss-light,#fff)var(--lightningcss-dark,#000))}:where(.lc-path){--fill-color:transparent;--stroke-color:var(--color-surface-content,currentColor)}:where(.lc-layout-svg .lc-path,svg.lc-path):not([fill]){fill:var(--fill-color)}:where(.lc-layout-svg .lc-path,svg.lc-path):not([stroke]){stroke:var(--stroke-color)}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-layout-svg .lc-rect,svg.lc-rect):not([fill]){fill:var(--fill-color)}:where(.lc-layout-svg .lc-rect,svg.lc-rect):not([stroke]){stroke:var(--stroke-color)}:where(.lc-rect){--fill-color:var(--color-surface-content,currentColor);--stroke-color:initial}:where(.lc-layout-html .lc-rect){box-sizing:border-box}:where(.lc-layout-html .lc-rect):not([background]){background:var(--fill-color)}:where(.lc-layout-html .lc-rect):not([border-color]){border-color:var(--stroke-color)}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-text-svg){paint-order:stroke;overflow:visible}:where(.lc-layout-svg .lc-text,svg.lc-text):not([fill]){color:var(--fill-color);fill:currentColor}:where(.lc-layout-svg .lc-text,svg.lc-text):not([stroke]){stroke:var(--stroke-color)}:where(.lc-text){--fill-color:var(--color-surface-content,currentColor);--stroke-color:initial}:where(.lc-layout-html .lc-text):not([background-color]){color:var(--fill-color)}:where(.lc-layout-html .lc-text):not([border-color]){border-color:var(--stroke-color)}}
@@ -0,0 +1 @@
1
+ @layer base{:where(.lc-transform-context.svelte-1t4nypg){height:100%}}
@@ -0,0 +1 @@
1
+ @layer components{:where(.lc-voronoi-path,.lc-voronoi-geo-path){fill:#0000;stroke:#0000}}
@@ -0,0 +1 @@
1
+ import{G as e,dt as t,lt as n,st as r}from"./D2BnX0Uk.js";import{f as i}from"./Bd1gDe3Y.js";import{t as a}from"./Db0q5_zr.js";import{t as o}from"./CCch3uox.js";import{t as s}from"./RobXhXPM.js";var c=typeof window<`u`,l=[`TRACE`,`DEBUG`,`INFO`,`WARN`,`ERROR`],u=class{name;constructor(e){this.name=e}trace(...e){this.log(`TRACE`,...e)}debug(...e){this.log(`DEBUG`,...e)}info(...e){this.log(`INFO`,...e)}warn(...e){this.log(`WARN`,...e)}error(...e){this.log(`ERROR`,...e)}log(e,...t){let n=(c?localStorage.getItem(`logger`)?.split(`,`).map(e=>e.split(`:`))??[]:[]).find(e=>e[0]===this.name);if(n!=null&&l.indexOf(e)>=l.indexOf(n[1]??`DEBUG`))switch(e){case`TRACE`:console.trace(`%c${this.name} %c${e}`,`color: hsl(200deg, 10%, 50%)`,`color: hsl(200deg, 40%, 50%)`,...t);break;case`DEBUG`:console.log(`%c${this.name} %c${e}`,`color: hsl(200deg, 10%, 50%)`,`color: hsl(200deg, 40%, 50%)`,...t);break;case`INFO`:console.log(`%c${this.name} %c${e}`,`color: hsl(200deg, 10%, 50%)`,`color: hsl(60deg, 100%, 50%)`,...t);break;case`WARN`:console.warn(`%c${this.name} %c${e}`,`color: hsl(200deg, 10%, 50%)`,`color: hsl(30deg, 100%, 50%)`,...t);break;case`ERROR`:console.warn(`%c${this.name} %c${e}`,`color: hsl(200deg, 10%, 50%)`,`color: hsl(0deg, 100%, 50%)`,...t)}}};function d(e,t){if(e[0]==null||e[1]==null||typeof e[0]!=`string`)return e;let n=t.indexOf(e[0]),r=t.indexOf(e[1]);return n===-1||r===-1?e:t.slice(n,r+1)}function f(e){return e.length>0&&typeof e[0]==`string`}function p(e,t,n){return n.indexOf(e)<=n.indexOf(t)?e:t}function m(e,t,n){return n.indexOf(e)>=n.indexOf(t)?e:t}function h(e,t,n,r){let i=r.indexOf(e),a=r.indexOf(t),o=r.indexOf(n);return i===-1||i<a?t:i>o?n:e}var g=class{ctx;#e=t(r([null,null]));get x(){return e(this.#e)}set x(e){n(this.#e,e,!0)}#t=t(r([null,null]));get y(){return e(this.#t)}set y(e){n(this.#t,e,!0)}#n=t();get active(){return e(this.#n)}set active(e){n(this.#n,e,!0)}#r=t(`x`);get axis(){return e(this.#r)}set axis(e){n(this.#r,e,!0)}#i=t(0);get handleSize(){return e(this.#i)}set handleSize(e){n(this.#i,e,!0)}#a=t();get minExtent(){return e(this.#a)}set minExtent(e){n(this.#a,e,!0)}#o=t();get maxExtent(){return e(this.#o)}set maxExtent(e){n(this.#o,e,!0)}#s=t();get constrain(){return e(this.#s)}set constrain(e){n(this.#s,e,!0)}#c=t(!0);get constrainToDomain(){return e(this.#c)}set constrainToDomain(e){n(this.#c,e,!0)}constructor(e,t){this.ctx=e,this.x=t?.x??[null,null],this.y=t?.y??[null,null],this.active=t?.active,this.axis=t?.axis??`x`,this.minExtent=t?.minExtent,this.maxExtent=t?.maxExtent,this.constrain=t?.constrain,this.constrainToDomain=t?.constrainToDomain??!0}get xDomainMin(){return this.ctx?.baseXScale.domain()[0]}get xDomainMax(){return this.ctx?.baseXScale.domain().at(-1)}get yDomainMin(){return this.ctx?.baseYScale.domain()[0]}get yDomainMax(){return this.ctx?.baseYScale.domain().at(-1)}get range(){if(!this.ctx)return{x:0,y:0,width:0,height:0};let e=this.ctx.xScale.bandwidth?.()??0,t=this.ctx.yScale.bandwidth?.()??0,n=this.ctx.xScale(this.x?.[0]),r=this.ctx.xScale(this.x?.[1])+e,i=this.ctx.yScale(this.y?.[1]),a=this.ctx.yScale(this.y?.[0])+t;return{x:this.axis===`both`||this.axis===`x`?n:0,y:this.axis===`both`||this.axis===`y`?i:0,width:this.axis===`both`||this.axis===`x`?r-n:this.ctx.width,height:this.axis===`both`||this.axis===`y`?a-i:this.ctx.height}}reset(){this.active=!1,this.x=[null,null],this.y=[null,null]}selectAll(){this.active=!0,this.x=[this.xDomainMin,this.xDomainMax],this.y=[this.yDomainMin,this.yDomainMax],this._applyConstraints({x:this.xDomainMin,y:this.yDomainMin})}move(e){`x`in e&&(this.x=e.x??[null,null]),`y`in e&&(this.y=e.y??[null,null]),this._applyConstraints({x:this.x[0],y:this.y[0]});let t=this.x[0]!=null&&this.x[1]!=null,n=this.y[0]!=null&&this.y[1]!=null;this.active=this.axis===`x`?t:this.axis===`y`?n:t||n}setRange(e,t){this.active=!0;let n=this.ctx?.baseXScale.domain()??[],r=this.ctx?.baseYScale.domain()??[];this.x=f(n)?[h(p(e.x,t.x,n),this.xDomainMin,this.xDomainMax,n),h(m(e.x,t.x,n),this.xDomainMin,this.xDomainMax,n)]:[i(o([e.x,t.x]),this.xDomainMin,this.xDomainMax),i(a([e.x,t.x]),this.xDomainMin,this.xDomainMax)],this.y=f(r)?[h(p(e.y,t.y,r),this.yDomainMin,this.yDomainMax,r),h(m(e.y,t.y,r),this.yDomainMin,this.yDomainMax,r)]:[i(o([e.y,t.y]),this.yDomainMin,this.yDomainMax),i(a([e.y,t.y]),this.yDomainMin,this.yDomainMax)],this._applyConstraints({x:e.x,y:e.y})}moveRange(e,t){let n=this.ctx?.baseXScale.domain()??[],r=this.ctx?.baseYScale.domain()??[];if(f(n)){let r=n.indexOf(e.value.x),i=n.indexOf(t.x),a=n.indexOf(e.x[0]),o=n.indexOf(e.x[1]),s=Math.max(-a,Math.min(n.length-1-o,i-r));this.x=[n[a+s],n[o+s]]}else{let n=i(t.x-e.value.x,this.xDomainMin-+e.x[0],this.xDomainMax-+e.x[1]);this.x=[s(e.x[0],n),s(e.x[1],n)]}if(f(r)){let n=r.indexOf(e.value.y),i=r.indexOf(t.y),a=r.indexOf(e.y[0]),o=r.indexOf(e.y[1]),s=Math.max(-a,Math.min(r.length-1-o,i-n));this.y=[r[a+s],r[o+s]]}else{let n=i(t.y-e.value.y,this.yDomainMin-+e.y[0],this.yDomainMax-+e.y[1]);this.y=[s(e.y[0],n),s(e.y[1],n)]}this._applyConstraints({x:null,y:null})}adjustEdge(e,t,n){let r=this.ctx?.baseXScale.domain()??[],a=this.ctx?.baseYScale.domain()??[],o=f(r),s=f(a),c=e=>o?h(e,this.xDomainMin,this.xDomainMax,r):i(e,this.xDomainMin,this.xDomainMax),l=e=>s?h(e,this.yDomainMin,this.yDomainMax,a):i(e,this.yDomainMin,this.yDomainMax),u=(e,t)=>o?r.indexOf(e)<r.indexOf(t):e<+t,d=(e,t)=>o?r.indexOf(e)>r.indexOf(t):e>+t,p=(e,t)=>s?a.indexOf(e)<a.indexOf(t):e<+t,m=(e,t)=>s?a.indexOf(e)>a.indexOf(t):e>+t;switch(e){case`top`:this.y=[l(p(n.y,t.y[0])?n.y:t.y[0]),l(p(n.y,t.y[0])?t.y[0]:n.y)];break;case`bottom`:this.y=[l(m(n.y,t.y[1])?t.y[1]:n.y),l(m(n.y,t.y[1])?n.y:t.y[1])];break;case`left`:this.x=[c(d(n.x,t.x[1])?t.x[1]:n.x),c(d(n.x,t.x[1])?n.x:t.x[1])];break;case`right`:this.x=[c(u(n.x,t.x[0])?n.x:t.x[0]),c(u(n.x,t.x[0])?t.x[0]:n.x)]}switch(e){case`left`:this._applyConstraints({x:t.x[1]});break;case`right`:this._applyConstraints({x:t.x[0]});break;case`top`:this._applyConstraints({y:t.y[0]});break;case`bottom`:this._applyConstraints({y:t.y[1]})}}_anchorIndex(e,t){if(t==null)return null;let n=t?.valueOf?.()??t;return(e[0]?.valueOf?.()??e[0])===n?0:(e[1]?.valueOf?.()??e[1])===n?1:null}_clampExtent(e,t,n){let r=this.minExtent?.[e],a=this.maxExtent?.[e];if(r==null&&a==null||t[0]==null||t[1]==null)return t;let o=(e===`x`?this.ctx?.baseXScale:this.ctx?.baseYScale)?.domain()??[],c=e===`x`?this.xDomainMin:this.yDomainMin,l=e===`x`?this.xDomainMax:this.yDomainMax,u=this._anchorIndex(t,n);if(f(o)){let e=o.indexOf(t[0]),n=o.indexOf(t[1]);if(e===-1||n===-1)return t;e>n&&([e,n]=[n,e]);let i=n-e+1;if(a!=null&&i>a){if(u===1)e=n-(a-1);else if(u===0)n=e+(a-1);else{let t=i-a;e+=Math.ceil(t/2),n-=Math.floor(t/2)}}else if(r!=null&&i<r){if(u===1)e=n-(r-1);else if(u===0)n=e+(r-1);else{let t=r-i;e-=Math.floor(t/2),n+=Math.ceil(t/2)}}let s=o.length-1;return e<0&&(n+=-e,e=0),n>s&&(e-=n-s,n=s),e=Math.max(0,e),n=Math.min(s,n),[o[e],o[n]]}let d=t[0],p=t[1],m=+p-d;if(a!=null&&m>a){if(u===1)d=s(p,-a);else if(u===0)p=s(d,a);else{let e=(m-a)/2;d=s(d,e),p=s(p,-e)}}else if(r!=null&&m<r){if(u===1)d=s(p,-r);else if(u===0)p=s(d,r);else{let e=(r-m)/2;d=s(d,-e),p=s(p,e)}c!=null&&+d<+c&&(p=s(p,+c-d),d=c),l!=null&&+p>+l&&(d=s(d,+l-p),p=l),d=i(d,c,l),p=i(p,c,l)}return[d,p]}_clampToDomain(e,t){if(t[0]==null||t[1]==null)return t;let n=(e===`x`?this.ctx?.baseXScale:this.ctx?.baseYScale)?.domain()??[],r=e===`x`?this.xDomainMin:this.yDomainMin,a=e===`x`?this.xDomainMax:this.yDomainMax;return f(n)?[h(t[0],r,a,n),h(t[1],r,a,n)]:[i(t[0],r,a),i(t[1],r,a)]}_applyConstraints(e){if(`x`in e&&this.x[0]!=null&&this.x[1]!=null&&(this.x=this._clampExtent(`x`,[this.x[0],this.x[1]],e.x)),`y`in e&&this.y[0]!=null&&this.y[1]!=null&&(this.y=this._clampExtent(`y`,[this.y[0],this.y[1]],e.y)),this.constrain){let e=this.constrain({x:this.x,y:this.y});this.x=e.x,this.y=e.y}this.constrainToDomain&&(this.x=this._clampToDomain(`x`,this.x),this.y=this._clampToDomain(`y`,this.y))}syncFromExternal(e,t){let n=e??[null,null],r=t??[null,null];(this.x[0]?.valueOf()!==n[0]?.valueOf()||this.x[1]?.valueOf()!==n[1]?.valueOf())&&(this.x=n),(this.y[0]?.valueOf()!==r[0]?.valueOf()||this.y[1]?.valueOf()!==r[1]?.valueOf())&&(this.y=r);let i=e!=null&&e[0]!=null&&e[1]!=null&&(e[0].valueOf()!==this.xDomainMin?.valueOf()||e[1].valueOf()!==this.xDomainMax?.valueOf()),a=t!=null&&t[0]!=null&&t[1]!=null&&(t[0].valueOf()!==this.yDomainMin?.valueOf()||t[1].valueOf()!==this.yDomainMax?.valueOf()),o=this.axis===`x`?i:this.axis===`y`?a:i||a;this.active!==o&&(this.active=o)}};export{d as n,u as r,g as t};
@@ -0,0 +1 @@
1
+ import{$ as e,Ct as t,D as n,Dt as r,F as i,G as a,H as o,I as s,J as c,L as l,V as u,_ as d,_t as f,d as p,dt as m,et as h,f as g,gt as _,i as v,it as y,j as b,lt as x,ot as S,rt as C,s as w,tt as T,v as E,y as D}from"./D2BnX0Uk.js";import"./xihTtKlq.js";import{t as O}from"./Bd1gDe3Y.js";import{s as k}from"./DKMlMI4a.js";import{c as A}from"./V9ZjaxiY.js";import{t as j}from"./BID1NNRh.js";import{r as M,t as N}from"./-aNGNaBT.js";var P=l(`<div></div> <div></div>`,1),F=l(`<div></div> <!> <!>`,1),I=l(`<div><div><!></div> <!></div>`);function L(l,u){f(u,!0);let L=O(),R=v(u,`state`,15),z=v(u,`axis`,3,`x`),B=v(u,`handleSize`,3,5),ee=v(u,`clickToReset`,3,!0),te=v(u,`disabled`,3,!1),V=v(u,`constrainToDomain`,3,!0),H=v(u,`range`,19,()=>({})),U=v(u,`handle`,19,()=>({})),W=v(u,`classes`,19,()=>({})),G=v(u,`onBrushEnd`,3,()=>{}),K=v(u,`onBrushStart`,3,()=>{}),q=v(u,`onChange`,3,()=>{}),J=m(void 0),Y=new N(L,{x:u.x,y:u.y,axis:z(),minExtent:u.minExtent,maxExtent:u.maxExtent,constrain:u.constrain,constrainToDomain:V()});R(Y),h(()=>{Y.handleSize=B()}),h(()=>{Y.minExtent=u.minExtent,Y.maxExtent=u.maxExtent,Y.constrain=u.constrain,Y.constrainToDomain=V()});let X=new M(`BrushContext`);function Z(e){return t=>{X.debug(`drag start`),t.stopPropagation();let n=j(t,a(J));if(n&&(n.x<0||n.x>L.width||n.y<0||n.y>L.height)){X.debug(`ignoring click as outside of chart bounds`,{startPoint:n,width:L.width,height:L.height});return}let r={x:[Y.x[0]??Y.xDomainMin,Y.x[1]??Y.xDomainMax],y:[Y.y[0]??Y.yDomainMin,Y.y[1]??Y.yDomainMax],value:{x:A(L.xScale,n?.x??0),y:A(L.yScale,n?.y??0)}};K()({brush:Y});let i=t=>{let n=j(t,a(J));e(r,{x:A(L.xScale,n?.x??0),y:A(L.yScale,n?.y??0)}),q()({brush:Y})},o=e=>{let t=j(e,a(J)),r=Math.abs((n?.x??0)-(t?.x??0)),s=Math.abs((n?.y??0)-(t?.y??0));!Array.from(e.target.classList).some(e=>[`range`,`handle`].includes(e))&&r<1&&s<1||Y.range.width<1||Y.range.height<1?ee()?(X.debug(`resetting due to frame click`),Y.reset(),q()({brush:Y})):X.debug(`ignoring frame click reset (clickToReset: false)`):X.debug(`drag end`,{target:e.target,xPointDelta:r,yPointDelta:s,rangeWidth:Y.range.width,rangeHeight:Y.range.height}),G()({brush:Y}),window.removeEventListener(`pointermove`,i),window.removeEventListener(`pointerup`,o)};window.addEventListener(`pointermove`,i),window.addEventListener(`pointerup`,o)}}let ne=Z((e,t)=>{X.debug(`createRange`),Y.setRange(e.value,t)}),re=Z((e,t)=>{X.debug(`adjustRange`),Y.moveRange(e,t)}),ie=Z((e,t)=>{X.debug(`adjustTop`),Y.adjustEdge(`top`,e,t)}),ae=Z((e,t)=>{X.debug(`adjustBottom`),Y.adjustEdge(`bottom`,e,t)}),oe=Z((e,t)=>{X.debug(`adjustLeft`),Y.adjustEdge(`left`,e,t)}),se=Z((e,t)=>{X.debug(`adjustRight`),Y.adjustEdge(`right`,e,t)});T(()=>{if(u.x!==void 0||u.y!==void 0){let e=u.x,t=u.y;c(()=>Y.syncFromExternal(e,t))}});var Q=s(),ce=y(Q),le=e=>{var t=s(),a=y(t);n(a,()=>u.children??r,()=>({state:Y})),i(e,t)},$=s=>{var c=I();let l;var f=C(c);let m;var h=C(f);n(h,()=>u.children??r,()=>({state:Y})),t(f);var _=S(f,2),v=e=>{var t=F(),n=y(t),r=()=>{Y.reset(),q()({brush:Y})};g(n,e=>({...H(),class:e,onpointerdown:re,ondblclick:r,[p]:{left:`${Y.range.x??``}px`,top:`${Y.range.y??``}px`,width:`${Y.range.width??``}px`,height:`${Y.range.height??``}px`}}),[()=>k(`lc-brush-range`,W().range,H()?.class)],void 0,void 0,`svelte-3rn8dw`);var a=S(n,2),o=e=>{var t=P(),n=y(t),r=e=>{e.stopPropagation(),Y.y[0]&&(Y.y[0]=Y.yDomainMin,q()({brush:Y}))};g(n,e=>({...U(),"data-position":`top`,class:e,onpointerdown:ie,ondblclick:r,[p]:{left:`${Y.range.x??``}px`,top:`${Y.range.y??``}px`,width:`${Y.range.width??``}px`,height:`${B()??``}px`}}),[()=>k(`lc-brush-handle`,W().handle,U()?.class)],void 0,void 0,`svelte-3rn8dw`);var a=S(n,2),o=e=>{e.stopPropagation(),Y.y[1]&&(Y.y[1]=Y.yDomainMax,q()({brush:Y}))};g(a,e=>({...U(),"data-position":`bottom`,class:e,onpointerdown:ae,ondblclick:o,[p]:{left:`${Y.range.x??``}px`,top:`${Y.range.y+Y.range.height-B()}px`,width:`${Y.range.width??``}px`,height:`${B()??``}px`}}),[()=>k(`lc-brush-handle`,W().handle,U()?.class)],void 0,void 0,`svelte-3rn8dw`),i(e,t)};b(a,e=>{(z()===`both`||z()===`y`)&&e(o)});var s=S(a,2),c=e=>{var t=P(),n=y(t),r=e=>{e.stopPropagation(),Y.x[0]&&(Y.x[0]=Y.xDomainMin,q()({brush:Y}))};g(n,e=>({...U(),"data-position":`left`,class:e,onpointerdown:oe,ondblclick:r,[p]:{left:`${Y.range.x??``}px`,top:`${Y.range.y??``}px`,width:`${B()??``}px`,height:`${Y.range.height??``}px`}}),[()=>k(`lc-brush-handle`,W().handle,U()?.class)],void 0,void 0,`svelte-3rn8dw`);var a=S(n,2),o=e=>{e.stopPropagation(),Y.x[1]&&(Y.x[1]=Y.xDomainMax,q()({brush:Y}))};g(a,e=>({...U(),"data-position":`right`,class:e,onpointerdown:se,ondblclick:o,[p]:{left:`${Y.range.x+Y.range.width-B()+1}px`,top:`${Y.range.y??``}px`,width:`${B()??``}px`,height:`${Y.range.height??``}px`}}),[()=>k(`lc-brush-handle`,W().handle,U()?.class)],void 0,void 0,`svelte-3rn8dw`),i(e,t)};b(s,e=>{(z()===`both`||z()===`x`)&&e(c)}),i(e,t)};b(_,e=>{Y.active&&e(v)}),t(c),w(c,e=>x(J,e),()=>a(J)),e((e,t)=>{E(c,1,e,`svelte-3rn8dw`),l=d(c,``,l,{top:`${L.padding.top??``}px`,left:`${L.padding.left??``}px`,width:`${L.width??``}px`,height:`${L.height??``}px`}),E(f,1,t,`svelte-3rn8dw`),m=d(f,``,m,{top:`-${L.padding.top??0??``}px`,left:`-${L.padding.left??0??``}px`,width:`${L.containerWidth??``}px`,height:`${L.containerHeight??``}px`})},[()=>D(k(`lc-brush-context`)),()=>D(k(`lc-brush-container`))]),o(`pointerdown`,c,ne),o(`dblclick`,c,e=>{Y.selectAll(),e.stopPropagation()}),i(s,c)};b(ce,e=>{te()?e(le):e($,-1)}),i(l,Q),_()}u([`pointerdown`,`dblclick`]);export{L as default};
@@ -0,0 +1 @@
1
+ import{E as e,F as t,G as n,I as r,O as i,_t as a,a as o,ft as s,gt as c,it as l,j as u,k as d,lt as f,o as p}from"./D2BnX0Uk.js";import"./xihTtKlq.js";import{t as m}from"./Bd1gDe3Y.js";import{t as h}from"./Y5urAfNy.js";import{t as g}from"./Db0q5_zr.js";import{t as _}from"./DKMlMI4a.js";import{i as v}from"./V9ZjaxiY.js";import{C as y,o as b,r as x,x as S}from"./Dh958be7.js";import{a as C,r as w}from"./caXkbKD3.js";import{n as T,r as E,t as D}from"./DthYhn6Y.js";import{n as O,t as k}from"./CO1vUXfR.js";var A=class{#e=()=>({});ctx=m();geo=y();#t;constructor(e){this.#e=e,e(),this.ctx.registerComponent({name:`Spline`,kind:`mark`,markInfo:()=>{let t=e();return{data:t.data,x:t.x,y:t.y,seriesKey:t.seriesKey,color:typeof t.stroke==`string`?t.stroke:void 0}}}),this.#t=w(this.#p(),()=>this.d,{type:`tween`,interpolate:E})}#n(e,t,n){let r=n(e);return Array.isArray(r)&&(r=g(r)),t.domain().length?t(r):r}#r=s(()=>this.ctx.series.series.find(e=>e.key===this.#e().seriesKey));get series(){return n(this.#r)}set series(e){f(this.#r,e)}#i=s(()=>this.series?.value??(this.series?.data?void 0:this.series?.key));get seriesAccessor(){return n(this.#i)}set seriesAccessor(e){f(this.#i,e)}#a=s(()=>_(this.#e().x??(this.ctx.valueAxis===`x`?this.seriesAccessor:void 0)??this.ctx.x));get xAccessor(){return n(this.#a)}set xAccessor(e){f(this.#a,e)}#o=s(()=>_(this.#e().y??(this.ctx.valueAxis===`y`?this.seriesAccessor:void 0)??this.ctx.y));get yAccessor(){return n(this.#o)}set yAccessor(e){f(this.#o,e)}#s=s(()=>v(this.ctx.xScale)?this.ctx.xScale.bandwidth()/2:0);get xOffset(){return n(this.#s)}set xOffset(e){f(this.#s,e)}#c=s(()=>v(this.ctx.yScale)?this.ctx.yScale.bandwidth()/2:0);get yOffset(){return n(this.#c)}set yOffset(e){f(this.#c,e)}#l(e){let t=this.#e(),n=this.ctx.radial?k().angle(e=>this.#n(e,this.ctx.xScale,this.xAccessor)+0).radius(e=>this.#n(e,this.ctx.yScale,this.yAccessor)+this.yOffset):O().x(e=>this.#n(e,this.ctx.xScale,this.xAccessor)+this.xOffset).y(e=>this.#n(e,this.ctx.yScale,this.yAccessor)+this.yOffset);return n.defined(t.defined??(e=>this.xAccessor(e)!=null&&this.yAccessor(e)!=null)),t.curve&&n.curve(t.curve),n(e)??``}#u=s(()=>{let e=this.#e();return typeof e.stroke==`function`||typeof e.fill==`function`||typeof e.opacity==`function`});get hasAnyStyleFn(){return n(this.#u)}set hasAnyStyleFn(e){f(this.#u,e)}#d=s(()=>{let e=this.#e();if(this.hasAnyStyleFn&&!this.geo.projection)return``;let t=e.data??this.series?.data??this.ctx.data;if(this.geo.projection){let n={type:`LineString`,coordinates:t.filter(n=>e.defined?e.defined(n,0,t):this.xAccessor(n)!=null&&this.yAccessor(n)!=null).map(e=>[this.xAccessor(e),this.yAccessor(e)])};return h(this.geo.projection)(n)??``}return this.#l(t)});get d(){return n(this.#d)}set d(e){f(this.#d,e)}#f=s(()=>{if(!this.hasAnyStyleFn)return null;let e=this.#e(),t=e.data??this.series?.data??this.ctx.data;return this.geo.projection?null:j(t,(t,n,r)=>{let i=x(e.stroke,t,this.ctx.cScale,n,r),a=x(e.fill,t,this.ctx.cScale,n,r),o=b(e.opacity,t,n,r);return{key:`${i}\0${a}\0${o}`,style:{stroke:i,fill:a,opacity:o}}}).map(e=>({...e.style,d:this.#l(e.data)}))});get segments(){return n(this.#f)}set segments(e){f(this.#f,e)}#p(){let e=this.#e();if(!C(e.motion))return``;if(this.ctx.config.x){let t=e.data??this.series?.data??this.ctx.data,n=Math.min(this.ctx.yScale(0)??this.ctx.yRange[0],this.ctx.yRange[0]),r=this.ctx.radial?k().angle(e=>this.#n(e,this.ctx.xScale,this.xAccessor)+0).radius(()=>n):O().x(e=>this.#n(e,this.ctx.xScale,this.xAccessor)+this.xOffset).y(()=>n);return r.defined(e.defined??(e=>this.xAccessor(e)!=null&&this.yAccessor(e)!=null)),e.curve&&r.curve(e.curve),r(t)??``}return``}#m=s(()=>C(this.#e().motion)!=null);get isTweened(){return n(this.#m)}set isTweened(e){f(this.#m,e)}get tweenedPath(){return this.#t.current}#h=s(()=>this.series?.key==null||this.ctx.series.visibleSeries.length<=1||this.ctx.series.isHighlighted(this.series.key,!0)?1:.1);get seriesOpacity(){return n(this.#h)}set seriesOpacity(e){f(this.#h,e)}};function j(e,t){if(e.length<2)return[];let n=[],r=t(e[0],0,e),i=0;for(let a=1;a<e.length;a++){let o=t(e[a],a,e);o.key!==r.key&&(n.push({style:r.style,data:e.slice(i,a+1)}),i=a,r=o)}return e.length-i>=2&&n.push({style:r.style,data:e.slice(i)}),n}var M=new Set([`$$slots`,`$$events`,`$$legacy`,`Path`,`data`,`x`,`y`,`seriesKey`,`defined`,`curve`,`stroke`,`fill`,`opacity`,`motion`]);function N(f,m){a(m,!0);let h=o(m,M),g=new A(()=>({data:m.data,x:m.x,y:m.y,seriesKey:m.seriesKey,defined:m.defined,curve:m.curve,stroke:m.stroke,fill:m.fill,opacity:m.opacity,motion:m.motion}));var _=r(),v=l(_),y=a=>{var o=r(),c=l(o);i(c,17,()=>g.segments,d,(i,a)=>{var o=r(),c=l(o);{let t=s(()=>n(a).opacity??(g.seriesOpacity===1?void 0:g.seriesOpacity));e(c,()=>m.Path,(e,r)=>{r(e,p({get pathData(){return n(a).d},get stroke(){return n(a).stroke},get fill(){return n(a).fill},get opacity(){return n(t)}},()=>g.series?.props,()=>h))})}t(i,o)}),t(a,o)},b=i=>{var a=r(),o=l(a);{let t=s(()=>g.isTweened?g.tweenedPath:g.d),r=s(()=>(typeof m.stroke==`string`?m.stroke:void 0)??g.series?.color),i=s(()=>typeof m.fill==`string`?m.fill:void 0),a=s(()=>(typeof m.opacity==`number`?m.opacity:void 0)??(g.seriesOpacity===1?void 0:g.seriesOpacity));e(o,()=>m.Path,(e,o)=>{o(e,p({get pathData(){return n(t)},get stroke(){return n(r)},get fill(){return n(i)},get opacity(){return n(a)}},()=>g.series?.props,()=>h))})}t(i,a)};u(v,e=>{g.segments?e(y):e(b,-1)}),t(f,_),c()}var P=new Set([`$$slots`,`$$events`,`$$legacy`]);function F(e,t){let n=o(t,P);N(e,p({get Path(){return T}},()=>n))}var I=new Set([`$$slots`,`$$events`,`$$legacy`]);function L(e,t){let n=o(t,I);N(e,p({get Path(){return D}},()=>n))}var R=new Set([`$$slots`,`$$events`,`$$legacy`]);function z(e,n){a(n,!0);let i=S(),s=o(n,R);var d=r(),f=l(d),m=e=>{F(e,p(()=>s))},h=e=>{L(e,p(()=>s))};u(f,e=>{i===`svg`?e(m):i===`canvas`&&e(h,1)}),t(e,d),c()}export{z as default};
@@ -0,0 +1 @@
1
+ import"./D2BnX0Uk.js";
@@ -0,0 +1 @@
1
+ var e=Array.prototype.slice;function t(e){return typeof e==`object`&&`length`in e?e:Array.from(e)}export{e as n,t};