@lunora/bindings 1.0.0-alpha.92 → 1.0.0-alpha.93
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 +12 -11
- package/dist/analytics/index.d.mts +1 -63
- package/dist/analytics/index.d.ts +1 -63
- package/dist/analytics/index.mjs +1 -1
- package/dist/analytics-sql/index.d.mts +175 -0
- package/dist/analytics-sql/index.d.ts +175 -0
- package/dist/analytics-sql/index.mjs +1 -0
- package/dist/packem_shared/AnalyticsSqlQueryError-DjoIZv5O.mjs +1 -0
- package/dist/packem_shared/FUNCTION_USAGE_PANELS-C5yhnDmF.mjs +1 -0
- package/dist/packem_shared/R2SqlError-5z-ShSB5.mjs +1 -0
- package/dist/packem_shared/createAnalyticsSql-BLoq02Nf.mjs +1 -0
- package/dist/packem_shared/createAnalyticsSqlRest-3Zndhp1B.mjs +1 -0
- package/dist/packem_shared/sql-rest-post-CDcOxw4h.mjs +1 -0
- package/dist/r2sql/index.d.mts +2 -2
- package/dist/r2sql/index.d.ts +2 -2
- package/dist/r2sql/index.mjs +1 -1
- package/package.json +9 -4
- package/dist/packem_shared/AnalyticsSqlError-CeQ3A5Eb.mjs +0 -1
- package/dist/packem_shared/R2SqlError-ZHgOWClB.mjs +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
</a>
|
|
8
8
|
|
|
9
|
-
<h3 align="center">Lightweight Cloudflare binding helpers for Lunora — ctx.kv, ctx.images, ctx.analytics, ctx.pipelines, ctx.vectors, ctx.r2sql, ctx.artifacts, ctx.aiSearch — one install, per-binding subpaths</h3>
|
|
9
|
+
<h3 align="center">Lightweight Cloudflare binding helpers for Lunora — ctx.kv, ctx.images, ctx.analytics, ctx.pipelines, ctx.vectors, ctx.r2sql, ctx.artifacts, ctx.aiSearch, ctx.analyticsSql — one install, per-binding subpaths</h3>
|
|
10
10
|
|
|
11
11
|
<!-- END_PACKAGE_OG_IMAGE_PLACEHOLDER -->
|
|
12
12
|
|
|
@@ -16,16 +16,17 @@ The lightweight Cloudflare binding helpers for Lunora, in one install with
|
|
|
16
16
|
per-binding subpaths — each is a thin, zero-dependency `ctx.*` facade over its
|
|
17
17
|
Cloudflare binding:
|
|
18
18
|
|
|
19
|
-
| Subpath
|
|
20
|
-
|
|
|
21
|
-
| `@lunora/bindings/kv`
|
|
22
|
-
| `@lunora/bindings/images`
|
|
23
|
-
| `@lunora/bindings/analytics`
|
|
24
|
-
| `@lunora/bindings/pipelines`
|
|
25
|
-
| `@lunora/bindings/vectors`
|
|
26
|
-
| `@lunora/bindings/r2sql`
|
|
27
|
-
| `@lunora/bindings/artifacts`
|
|
28
|
-
| `@lunora/bindings/ai-search`
|
|
19
|
+
| Subpath | `ctx.*` | Cloudflare binding |
|
|
20
|
+
| -------------------------------- | ------------------ | ---------------------- |
|
|
21
|
+
| `@lunora/bindings/kv` | `ctx.kv` | Workers KV |
|
|
22
|
+
| `@lunora/bindings/images` | `ctx.images` | Cloudflare Images |
|
|
23
|
+
| `@lunora/bindings/analytics` | `ctx.analytics` | Analytics Engine |
|
|
24
|
+
| `@lunora/bindings/pipelines` | `ctx.pipelines` | Pipelines |
|
|
25
|
+
| `@lunora/bindings/vectors` | `ctx.vectors` | Vectorize |
|
|
26
|
+
| `@lunora/bindings/r2sql` | `ctx.r2sql` | R2 SQL |
|
|
27
|
+
| `@lunora/bindings/artifacts` | `ctx.artifacts` | Artifacts (Git repos) |
|
|
28
|
+
| `@lunora/bindings/ai-search` | `ctx.aiSearch` | AI Search (types only) |
|
|
29
|
+
| `@lunora/bindings/analytics-sql` | `ctx.analyticsSql` | Analytics SQL |
|
|
29
30
|
|
|
30
31
|
```ts
|
|
31
32
|
import { createKv } from "@lunora/bindings/kv";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnalyticsEngineDataPoint, AnalyticsEngineDatasetLike } from '@lunora/platform';
|
|
2
2
|
export type { AnalyticsEngineDataPoint, AnalyticsEngineDatasetLike } from '@lunora/platform';
|
|
3
|
-
import { LunoraError } from '@lunora/errors';
|
|
4
3
|
/**
|
|
5
4
|
* Structural types for the Analytics Engine write path.
|
|
6
5
|
*
|
|
@@ -80,65 +79,4 @@ interface AnalyticsClient {
|
|
|
80
79
|
* the field→column mapping the read side uses to reconstruct named columns.
|
|
81
80
|
*/
|
|
82
81
|
declare const createAnalytics: (binding: AnalyticsEngineDatasetLike) => AnalyticsClient;
|
|
83
|
-
|
|
84
|
-
interface AnalyticsSqlConfig {
|
|
85
|
-
/** Cloudflare account id that owns the dataset. */
|
|
86
|
-
accountId: string;
|
|
87
|
-
/** API token with Analytics Engine read scope. A secret — never a binding. */
|
|
88
|
-
apiToken: string;
|
|
89
|
-
/**
|
|
90
|
-
* `fetch` implementation. Defaults to the global `fetch`; injected in tests
|
|
91
|
-
* so the SQL path never touches the network.
|
|
92
|
-
*/
|
|
93
|
-
fetch?: typeof globalThis.fetch;
|
|
94
|
-
/**
|
|
95
|
-
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
96
|
-
* aborted and surfaced as an `AnalyticsSqlError` with status 504. Defaults
|
|
97
|
-
* to 60_000 — analytical scans legitimately run tens of seconds.
|
|
98
|
-
* `undefined` means the default, not unbounded.
|
|
99
|
-
*
|
|
100
|
-
* The deadline is carried by the request's `signal`, so a custom `fetch`
|
|
101
|
-
* (above) that ignores `signal` leaves the query unbounded.
|
|
102
|
-
*/
|
|
103
|
-
timeoutMs?: number;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* One column descriptor in a SQL-API response's `meta` array: the column `name`
|
|
107
|
-
* and the AE storage `type` (`String`, `Float64`, `DateTime`, …).
|
|
108
|
-
*/
|
|
109
|
-
interface AnalyticsSqlColumnMeta {
|
|
110
|
-
name: string;
|
|
111
|
-
type: string;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Parsed SQL-API result. AE returns `{ meta, data, rows, rows_before_limit_at_least }`;
|
|
115
|
-
* we surface `columns` (from `meta`), the `rows` array of column→value records,
|
|
116
|
-
* and the total `rowCount`.
|
|
117
|
-
*/
|
|
118
|
-
interface AnalyticsSqlResult {
|
|
119
|
-
columns: AnalyticsSqlColumnMeta[];
|
|
120
|
-
rowCount: number;
|
|
121
|
-
rows: Record<string, unknown>[];
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Thrown when the SQL API responds with a non-2xx status; a `LunoraError`
|
|
125
|
-
* subclass carrying the HTTP `status` + a capped body preview, with the full
|
|
126
|
-
* body on `cause`.
|
|
127
|
-
*
|
|
128
|
-
* The preview is capped because AE's SQL error text quotes the query back, and
|
|
129
|
-
* `ANALYTICS_SQL_ERROR` is non-internal — the message reaches the browser.
|
|
130
|
-
*/
|
|
131
|
-
declare class AnalyticsSqlError extends LunoraError {
|
|
132
|
-
constructor(status: number, body: string);
|
|
133
|
-
}
|
|
134
|
-
/** The read client: a single `query(sql)` over the AE SQL API. */
|
|
135
|
-
interface AnalyticsSqlClient {
|
|
136
|
-
query: (sql: string) => Promise<AnalyticsSqlResult>;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Build an {@link AnalyticsSqlClient}. Each `query` POSTs the raw SQL text to
|
|
140
|
-
* the account's `analytics_engine/sql` endpoint with the bearer token, then
|
|
141
|
-
* normalises AE's `{ meta, data, rows }` body into {@link AnalyticsSqlResult}.
|
|
142
|
-
*/
|
|
143
|
-
declare const createAnalyticsSqlClient: (config: AnalyticsSqlConfig) => AnalyticsSqlClient;
|
|
144
|
-
export { type AnalyticsClient, type AnalyticsSqlClient, type AnalyticsSqlColumnMeta, type AnalyticsSqlConfig, AnalyticsSqlError, type AnalyticsSqlResult, type TrackColumn, type TrackEvent, type TrackSchema, createAnalytics, createAnalyticsSqlClient };
|
|
82
|
+
export { type AnalyticsClient, type TrackColumn, type TrackEvent, type TrackSchema, createAnalytics };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnalyticsEngineDataPoint, AnalyticsEngineDatasetLike } from '@lunora/platform';
|
|
2
2
|
export type { AnalyticsEngineDataPoint, AnalyticsEngineDatasetLike } from '@lunora/platform';
|
|
3
|
-
import { LunoraError } from '@lunora/errors';
|
|
4
3
|
/**
|
|
5
4
|
* Structural types for the Analytics Engine write path.
|
|
6
5
|
*
|
|
@@ -80,65 +79,4 @@ interface AnalyticsClient {
|
|
|
80
79
|
* the field→column mapping the read side uses to reconstruct named columns.
|
|
81
80
|
*/
|
|
82
81
|
declare const createAnalytics: (binding: AnalyticsEngineDatasetLike) => AnalyticsClient;
|
|
83
|
-
|
|
84
|
-
interface AnalyticsSqlConfig {
|
|
85
|
-
/** Cloudflare account id that owns the dataset. */
|
|
86
|
-
accountId: string;
|
|
87
|
-
/** API token with Analytics Engine read scope. A secret — never a binding. */
|
|
88
|
-
apiToken: string;
|
|
89
|
-
/**
|
|
90
|
-
* `fetch` implementation. Defaults to the global `fetch`; injected in tests
|
|
91
|
-
* so the SQL path never touches the network.
|
|
92
|
-
*/
|
|
93
|
-
fetch?: typeof globalThis.fetch;
|
|
94
|
-
/**
|
|
95
|
-
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
96
|
-
* aborted and surfaced as an `AnalyticsSqlError` with status 504. Defaults
|
|
97
|
-
* to 60_000 — analytical scans legitimately run tens of seconds.
|
|
98
|
-
* `undefined` means the default, not unbounded.
|
|
99
|
-
*
|
|
100
|
-
* The deadline is carried by the request's `signal`, so a custom `fetch`
|
|
101
|
-
* (above) that ignores `signal` leaves the query unbounded.
|
|
102
|
-
*/
|
|
103
|
-
timeoutMs?: number;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* One column descriptor in a SQL-API response's `meta` array: the column `name`
|
|
107
|
-
* and the AE storage `type` (`String`, `Float64`, `DateTime`, …).
|
|
108
|
-
*/
|
|
109
|
-
interface AnalyticsSqlColumnMeta {
|
|
110
|
-
name: string;
|
|
111
|
-
type: string;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Parsed SQL-API result. AE returns `{ meta, data, rows, rows_before_limit_at_least }`;
|
|
115
|
-
* we surface `columns` (from `meta`), the `rows` array of column→value records,
|
|
116
|
-
* and the total `rowCount`.
|
|
117
|
-
*/
|
|
118
|
-
interface AnalyticsSqlResult {
|
|
119
|
-
columns: AnalyticsSqlColumnMeta[];
|
|
120
|
-
rowCount: number;
|
|
121
|
-
rows: Record<string, unknown>[];
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Thrown when the SQL API responds with a non-2xx status; a `LunoraError`
|
|
125
|
-
* subclass carrying the HTTP `status` + a capped body preview, with the full
|
|
126
|
-
* body on `cause`.
|
|
127
|
-
*
|
|
128
|
-
* The preview is capped because AE's SQL error text quotes the query back, and
|
|
129
|
-
* `ANALYTICS_SQL_ERROR` is non-internal — the message reaches the browser.
|
|
130
|
-
*/
|
|
131
|
-
declare class AnalyticsSqlError extends LunoraError {
|
|
132
|
-
constructor(status: number, body: string);
|
|
133
|
-
}
|
|
134
|
-
/** The read client: a single `query(sql)` over the AE SQL API. */
|
|
135
|
-
interface AnalyticsSqlClient {
|
|
136
|
-
query: (sql: string) => Promise<AnalyticsSqlResult>;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Build an {@link AnalyticsSqlClient}. Each `query` POSTs the raw SQL text to
|
|
140
|
-
* the account's `analytics_engine/sql` endpoint with the bearer token, then
|
|
141
|
-
* normalises AE's `{ meta, data, rows }` body into {@link AnalyticsSqlResult}.
|
|
142
|
-
*/
|
|
143
|
-
declare const createAnalyticsSqlClient: (config: AnalyticsSqlConfig) => AnalyticsSqlClient;
|
|
144
|
-
export { type AnalyticsClient, type AnalyticsSqlClient, type AnalyticsSqlColumnMeta, type AnalyticsSqlConfig, AnalyticsSqlError, type AnalyticsSqlResult, type TrackColumn, type TrackEvent, type TrackSchema, createAnalytics, createAnalyticsSqlClient };
|
|
82
|
+
export { type AnalyticsClient, type TrackColumn, type TrackEvent, type TrackSchema, createAnalytics };
|
package/dist/analytics/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createAnalytics as
|
|
1
|
+
import{createAnalytics as t}from"../packem_shared/createAnalytics-BXTNc57d.mjs";export{t as createAnalytics};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
/**
|
|
3
|
+
* Structural types for the Analytics SQL read path.
|
|
4
|
+
*
|
|
5
|
+
* The real binding is workers-types' `AnalyticsSQLBinding` (the wrangler
|
|
6
|
+
* `analytics` key, wrangler ≥ 4.145.0). It is mirrored **structurally**
|
|
7
|
+
* (`AnalyticsSqlBindingLike`) rather than aliased, like every other bindings
|
|
8
|
+
* subpath: an alias resolved against an older or absent workers-types install
|
|
9
|
+
* would degrade to `any`, and plain-object test doubles satisfy a structural
|
|
10
|
+
* contract without workerd. A type test pins that the real binding still
|
|
11
|
+
* satisfies the mirror.
|
|
12
|
+
*/
|
|
13
|
+
/** A value bound to a `$1` / `$name` placeholder. */
|
|
14
|
+
type AnalyticsSqlParameter = boolean | number | string | null;
|
|
15
|
+
/** Positional (`$1`, `$2`, …) or named (`$start`, …) placeholder values. */
|
|
16
|
+
type AnalyticsSqlParams = Readonly<Record<string, AnalyticsSqlParameter>> | ReadonlyArray<AnalyticsSqlParameter>;
|
|
17
|
+
/** One Analytics SQL statement and its optional placeholder values. */
|
|
18
|
+
interface AnalyticsSqlRequest {
|
|
19
|
+
params?: AnalyticsSqlParams;
|
|
20
|
+
query: string;
|
|
21
|
+
}
|
|
22
|
+
/** Execution statistics the SQL API reports for a query. */
|
|
23
|
+
interface AnalyticsSqlStatistics {
|
|
24
|
+
bytes_read: number;
|
|
25
|
+
elapsed_ms: number;
|
|
26
|
+
rows_read: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The raw result body: `data` rows plus the `rows` count and `statistics`.
|
|
30
|
+
* `statistics` is optional because the REST endpoint omits it for Log Explorer
|
|
31
|
+
* datasets; the binding always sets it.
|
|
32
|
+
*/
|
|
33
|
+
interface AnalyticsSqlRawResult<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
34
|
+
data: T[];
|
|
35
|
+
rows: number;
|
|
36
|
+
statistics?: AnalyticsSqlStatistics;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Anything that answers `query({ query, params })` the way the Analytics SQL
|
|
40
|
+
* binding does: the real `env.ANALYTICS_SQL` binding, or
|
|
41
|
+
* `createAnalyticsSqlRest(...)`, the API-token transport over the same SQL API
|
|
42
|
+
* for a worker with no binding.
|
|
43
|
+
*/
|
|
44
|
+
interface AnalyticsSqlBindingLike {
|
|
45
|
+
query: <T extends Record<string, unknown> = Record<string, unknown>>(request: AnalyticsSqlRequest) => Promise<AnalyticsSqlRawResult<T>>;
|
|
46
|
+
}
|
|
47
|
+
/** Options for `createAnalyticsSql`. */
|
|
48
|
+
interface AnalyticsSqlOptions {
|
|
49
|
+
/** The Analytics SQL binding (`env.ANALYTICS_SQL`), or the REST transport from `createAnalyticsSqlRest`. */
|
|
50
|
+
binding: AnalyticsSqlBindingLike;
|
|
51
|
+
}
|
|
52
|
+
/** A parsed query result: the rows, their count, and the SQL API's execution statistics. */
|
|
53
|
+
interface AnalyticsSqlQueryResult<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
54
|
+
/** The SQL API's row count (equal to `rows.length` for a complete result). */
|
|
55
|
+
rowCount: number;
|
|
56
|
+
rows: T[];
|
|
57
|
+
/** Absent only when the REST transport queried a dataset that reports none (Log Explorer). */
|
|
58
|
+
statistics?: AnalyticsSqlStatistics;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The action-only client bound to `ctx.analyticsSql`: one read-only SQL
|
|
62
|
+
* statement per call, in the **Analytics SQL** dialect
|
|
63
|
+
* (`FROM events.analyticsEngine."<dataset>"`, a lower `timestamp` bound
|
|
64
|
+
* required), with `$1` / `$name` placeholders bound from `params`.
|
|
65
|
+
*/
|
|
66
|
+
interface AnalyticsSql {
|
|
67
|
+
query: <T extends Record<string, unknown> = Record<string, unknown>>(sql: string, params?: AnalyticsSqlParams) => Promise<AnalyticsSqlQueryResult<T>>;
|
|
68
|
+
}
|
|
69
|
+
/** Configuration for `createAnalyticsSqlRest`. */
|
|
70
|
+
interface AnalyticsSqlRestConfig {
|
|
71
|
+
/** The Cloudflare account id the queries are scoped to (sent as `scope.accountTag`). */
|
|
72
|
+
accountId: string;
|
|
73
|
+
/** API token with Account Analytics Read. A secret: never a binding, never shipped to a browser. */
|
|
74
|
+
apiToken: string;
|
|
75
|
+
/** `fetch` implementation. Defaults to the global `fetch`; injected in tests so the transport never touches the network. */
|
|
76
|
+
fetch?: typeof globalThis.fetch;
|
|
77
|
+
/**
|
|
78
|
+
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
79
|
+
* aborted, surfacing as a retryable query error with status 504.
|
|
80
|
+
* Defaults to 60_000. Carried by the request's `signal`, so a custom `fetch`
|
|
81
|
+
* that ignores `signal` leaves the query unbounded.
|
|
82
|
+
*/
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the action-only {@link AnalyticsSql} client bound to `ctx.analyticsSql`.
|
|
87
|
+
*
|
|
88
|
+
* `binding` is the Analytics SQL binding (`env.ANALYTICS_SQL`, the wrangler
|
|
89
|
+
* `analytics` key) or, in a worker without one, the API-token transport from
|
|
90
|
+
* `createAnalyticsSqlRest`. Both speak the same Analytics SQL dialect, so a
|
|
91
|
+
* statement written against one runs unchanged on the other; the binding derives
|
|
92
|
+
* the account from the Worker, the REST transport sends it as `scope.accountTag`.
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* const analyticsSql = createAnalyticsSql({ binding: env.ANALYTICS_SQL });
|
|
96
|
+
* const { rows } = await analyticsSql.query<{ calls: number }>(
|
|
97
|
+
* `SELECT COUNT(*) AS calls FROM events.analyticsEngine.app WHERE timestamp >= $since`,
|
|
98
|
+
* { since: new Date(Date.now() - 3_600_000).toISOString() },
|
|
99
|
+
* );
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* A rejected query surfaces as an {@link AnalyticsSqlQueryError} carrying the
|
|
103
|
+
* binding's `retryable` flag. Nothing is retried here.
|
|
104
|
+
*/
|
|
105
|
+
declare const createAnalyticsSql: (options: AnalyticsSqlOptions) => AnalyticsSql;
|
|
106
|
+
/** What an {@link AnalyticsSqlQueryError} carries on `data`, so a client can decide to retry. */
|
|
107
|
+
interface AnalyticsSqlQueryErrorData {
|
|
108
|
+
/** Whether repeating the same query may succeed (rate, concurrency or resource limits, transient outages). */
|
|
109
|
+
retryable: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A failed Analytics SQL query, from either transport: the binding rejecting
|
|
113
|
+
* (its error's `retryable` flag is kept), or the REST endpoint answering
|
|
114
|
+
* non-2xx (`429` / `500` / `503` / `507` are retryable, per Cloudflare's SQL
|
|
115
|
+
* API error reference) or timing out (`504`, retryable).
|
|
116
|
+
*
|
|
117
|
+
* Neither transport retries. The message embeds at most a capped preview of the
|
|
118
|
+
* upstream text, because `ANALYTICS_SQL_QUERY_ERROR` is client-safe and SQL API
|
|
119
|
+
* errors quote the statement back; the full text stays on `cause`.
|
|
120
|
+
*/
|
|
121
|
+
declare class AnalyticsSqlQueryError extends LunoraError {
|
|
122
|
+
readonly retryable: boolean;
|
|
123
|
+
constructor(detail: string, options: {
|
|
124
|
+
cause?: unknown;
|
|
125
|
+
retryable: boolean;
|
|
126
|
+
status?: number;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/** The Studio usage panels, in display order. */
|
|
130
|
+
declare const FUNCTION_USAGE_PANELS: readonly ["volume", "latency", "hotShards"];
|
|
131
|
+
/** One Studio usage panel. */
|
|
132
|
+
type FunctionUsagePanel = (typeof FUNCTION_USAGE_PANELS)[number];
|
|
133
|
+
/** Options for {@link functionUsageQuery}. */
|
|
134
|
+
interface FunctionUsageQueryOptions {
|
|
135
|
+
/** The Analytics Engine dataset (`analytics_engine_datasets[].dataset`). Defaults to `ANALYTICS`, the one reconcile writes. */
|
|
136
|
+
dataset?: string;
|
|
137
|
+
/** Lower `timestamp` bound, an ISO-8601 string. Defaults to 24 hours before now. The dialect requires one. */
|
|
138
|
+
since?: string;
|
|
139
|
+
}
|
|
140
|
+
/** Whether `value` names a {@link FunctionUsagePanel} — for validating the key an action receives. */
|
|
141
|
+
declare const isFunctionUsagePanel: (value: unknown) => value is FunctionUsagePanel;
|
|
142
|
+
/**
|
|
143
|
+
* The statement and `$since` parameter for one Studio usage panel, to run with
|
|
144
|
+
* `ctx.analyticsSql.query(request.query, request.params)`.
|
|
145
|
+
*
|
|
146
|
+
* The dataset is quoted as an identifier (embedded `"` doubled). It comes from
|
|
147
|
+
* your code, not from the caller.
|
|
148
|
+
*/
|
|
149
|
+
declare const functionUsageQuery: (panel: FunctionUsagePanel, options?: FunctionUsageQueryOptions) => AnalyticsSqlRequest & {
|
|
150
|
+
params: {
|
|
151
|
+
since: string;
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Build an {@link AnalyticsSqlBindingLike} that runs each query over the REST
|
|
156
|
+
* endpoint with an account API token (Account Analytics Read). Use it where the
|
|
157
|
+
* Worker has no `analytics` binding — a wrangler older than 4.145.0, or a host
|
|
158
|
+
* that is not a Worker — and hand it to `createAnalyticsSql({ binding })` or
|
|
159
|
+
* `defineApp().analyticsSql((env) => createAnalyticsSqlRest({ … }))`.
|
|
160
|
+
*
|
|
161
|
+
* Every failure is an {@link AnalyticsSqlQueryError}: a non-2xx (`429` / `500`
|
|
162
|
+
* / `503` / `507` retryable), a malformed body (not retryable), the deadline
|
|
163
|
+
* (`504`, retryable), or the request never reaching the API — DNS, a reset
|
|
164
|
+
* connection — which is retryable too. Nothing is retried here.
|
|
165
|
+
*
|
|
166
|
+
* The token is a secret: read it from `env`, never from a browser.
|
|
167
|
+
*/
|
|
168
|
+
declare const createAnalyticsSqlRest: (config: AnalyticsSqlRestConfig) => AnalyticsSqlBindingLike;
|
|
169
|
+
export { type AnalyticsSql, type AnalyticsSqlBindingLike, type AnalyticsSqlOptions, type AnalyticsSqlParameter, type AnalyticsSqlParams, AnalyticsSqlQueryError, type AnalyticsSqlQueryErrorData, type AnalyticsSqlQueryResult, type AnalyticsSqlRawResult, type AnalyticsSqlRequest, type AnalyticsSqlRestConfig, type AnalyticsSqlStatistics, FUNCTION_USAGE_PANELS, type FunctionUsagePanel, type FunctionUsageQueryOptions,
|
|
170
|
+
/**
|
|
171
|
+
* `ctx.analyticsSql` — read-only SQL over Cloudflare's Analytics SQL API, through
|
|
172
|
+
* the Analytics SQL Workers binding (wrangler `analytics` key, ≥ 4.145.0) or the
|
|
173
|
+
* API-token REST transport where there is no binding.
|
|
174
|
+
*/
|
|
175
|
+
createAnalyticsSql, createAnalyticsSqlRest, functionUsageQuery, isFunctionUsagePanel };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
/**
|
|
3
|
+
* Structural types for the Analytics SQL read path.
|
|
4
|
+
*
|
|
5
|
+
* The real binding is workers-types' `AnalyticsSQLBinding` (the wrangler
|
|
6
|
+
* `analytics` key, wrangler ≥ 4.145.0). It is mirrored **structurally**
|
|
7
|
+
* (`AnalyticsSqlBindingLike`) rather than aliased, like every other bindings
|
|
8
|
+
* subpath: an alias resolved against an older or absent workers-types install
|
|
9
|
+
* would degrade to `any`, and plain-object test doubles satisfy a structural
|
|
10
|
+
* contract without workerd. A type test pins that the real binding still
|
|
11
|
+
* satisfies the mirror.
|
|
12
|
+
*/
|
|
13
|
+
/** A value bound to a `$1` / `$name` placeholder. */
|
|
14
|
+
type AnalyticsSqlParameter = boolean | number | string | null;
|
|
15
|
+
/** Positional (`$1`, `$2`, …) or named (`$start`, …) placeholder values. */
|
|
16
|
+
type AnalyticsSqlParams = Readonly<Record<string, AnalyticsSqlParameter>> | ReadonlyArray<AnalyticsSqlParameter>;
|
|
17
|
+
/** One Analytics SQL statement and its optional placeholder values. */
|
|
18
|
+
interface AnalyticsSqlRequest {
|
|
19
|
+
params?: AnalyticsSqlParams;
|
|
20
|
+
query: string;
|
|
21
|
+
}
|
|
22
|
+
/** Execution statistics the SQL API reports for a query. */
|
|
23
|
+
interface AnalyticsSqlStatistics {
|
|
24
|
+
bytes_read: number;
|
|
25
|
+
elapsed_ms: number;
|
|
26
|
+
rows_read: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The raw result body: `data` rows plus the `rows` count and `statistics`.
|
|
30
|
+
* `statistics` is optional because the REST endpoint omits it for Log Explorer
|
|
31
|
+
* datasets; the binding always sets it.
|
|
32
|
+
*/
|
|
33
|
+
interface AnalyticsSqlRawResult<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
34
|
+
data: T[];
|
|
35
|
+
rows: number;
|
|
36
|
+
statistics?: AnalyticsSqlStatistics;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Anything that answers `query({ query, params })` the way the Analytics SQL
|
|
40
|
+
* binding does: the real `env.ANALYTICS_SQL` binding, or
|
|
41
|
+
* `createAnalyticsSqlRest(...)`, the API-token transport over the same SQL API
|
|
42
|
+
* for a worker with no binding.
|
|
43
|
+
*/
|
|
44
|
+
interface AnalyticsSqlBindingLike {
|
|
45
|
+
query: <T extends Record<string, unknown> = Record<string, unknown>>(request: AnalyticsSqlRequest) => Promise<AnalyticsSqlRawResult<T>>;
|
|
46
|
+
}
|
|
47
|
+
/** Options for `createAnalyticsSql`. */
|
|
48
|
+
interface AnalyticsSqlOptions {
|
|
49
|
+
/** The Analytics SQL binding (`env.ANALYTICS_SQL`), or the REST transport from `createAnalyticsSqlRest`. */
|
|
50
|
+
binding: AnalyticsSqlBindingLike;
|
|
51
|
+
}
|
|
52
|
+
/** A parsed query result: the rows, their count, and the SQL API's execution statistics. */
|
|
53
|
+
interface AnalyticsSqlQueryResult<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
54
|
+
/** The SQL API's row count (equal to `rows.length` for a complete result). */
|
|
55
|
+
rowCount: number;
|
|
56
|
+
rows: T[];
|
|
57
|
+
/** Absent only when the REST transport queried a dataset that reports none (Log Explorer). */
|
|
58
|
+
statistics?: AnalyticsSqlStatistics;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The action-only client bound to `ctx.analyticsSql`: one read-only SQL
|
|
62
|
+
* statement per call, in the **Analytics SQL** dialect
|
|
63
|
+
* (`FROM events.analyticsEngine."<dataset>"`, a lower `timestamp` bound
|
|
64
|
+
* required), with `$1` / `$name` placeholders bound from `params`.
|
|
65
|
+
*/
|
|
66
|
+
interface AnalyticsSql {
|
|
67
|
+
query: <T extends Record<string, unknown> = Record<string, unknown>>(sql: string, params?: AnalyticsSqlParams) => Promise<AnalyticsSqlQueryResult<T>>;
|
|
68
|
+
}
|
|
69
|
+
/** Configuration for `createAnalyticsSqlRest`. */
|
|
70
|
+
interface AnalyticsSqlRestConfig {
|
|
71
|
+
/** The Cloudflare account id the queries are scoped to (sent as `scope.accountTag`). */
|
|
72
|
+
accountId: string;
|
|
73
|
+
/** API token with Account Analytics Read. A secret: never a binding, never shipped to a browser. */
|
|
74
|
+
apiToken: string;
|
|
75
|
+
/** `fetch` implementation. Defaults to the global `fetch`; injected in tests so the transport never touches the network. */
|
|
76
|
+
fetch?: typeof globalThis.fetch;
|
|
77
|
+
/**
|
|
78
|
+
* Milliseconds before an in-flight query (the fetch AND its body read) is
|
|
79
|
+
* aborted, surfacing as a retryable query error with status 504.
|
|
80
|
+
* Defaults to 60_000. Carried by the request's `signal`, so a custom `fetch`
|
|
81
|
+
* that ignores `signal` leaves the query unbounded.
|
|
82
|
+
*/
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the action-only {@link AnalyticsSql} client bound to `ctx.analyticsSql`.
|
|
87
|
+
*
|
|
88
|
+
* `binding` is the Analytics SQL binding (`env.ANALYTICS_SQL`, the wrangler
|
|
89
|
+
* `analytics` key) or, in a worker without one, the API-token transport from
|
|
90
|
+
* `createAnalyticsSqlRest`. Both speak the same Analytics SQL dialect, so a
|
|
91
|
+
* statement written against one runs unchanged on the other; the binding derives
|
|
92
|
+
* the account from the Worker, the REST transport sends it as `scope.accountTag`.
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* const analyticsSql = createAnalyticsSql({ binding: env.ANALYTICS_SQL });
|
|
96
|
+
* const { rows } = await analyticsSql.query<{ calls: number }>(
|
|
97
|
+
* `SELECT COUNT(*) AS calls FROM events.analyticsEngine.app WHERE timestamp >= $since`,
|
|
98
|
+
* { since: new Date(Date.now() - 3_600_000).toISOString() },
|
|
99
|
+
* );
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* A rejected query surfaces as an {@link AnalyticsSqlQueryError} carrying the
|
|
103
|
+
* binding's `retryable` flag. Nothing is retried here.
|
|
104
|
+
*/
|
|
105
|
+
declare const createAnalyticsSql: (options: AnalyticsSqlOptions) => AnalyticsSql;
|
|
106
|
+
/** What an {@link AnalyticsSqlQueryError} carries on `data`, so a client can decide to retry. */
|
|
107
|
+
interface AnalyticsSqlQueryErrorData {
|
|
108
|
+
/** Whether repeating the same query may succeed (rate, concurrency or resource limits, transient outages). */
|
|
109
|
+
retryable: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A failed Analytics SQL query, from either transport: the binding rejecting
|
|
113
|
+
* (its error's `retryable` flag is kept), or the REST endpoint answering
|
|
114
|
+
* non-2xx (`429` / `500` / `503` / `507` are retryable, per Cloudflare's SQL
|
|
115
|
+
* API error reference) or timing out (`504`, retryable).
|
|
116
|
+
*
|
|
117
|
+
* Neither transport retries. The message embeds at most a capped preview of the
|
|
118
|
+
* upstream text, because `ANALYTICS_SQL_QUERY_ERROR` is client-safe and SQL API
|
|
119
|
+
* errors quote the statement back; the full text stays on `cause`.
|
|
120
|
+
*/
|
|
121
|
+
declare class AnalyticsSqlQueryError extends LunoraError {
|
|
122
|
+
readonly retryable: boolean;
|
|
123
|
+
constructor(detail: string, options: {
|
|
124
|
+
cause?: unknown;
|
|
125
|
+
retryable: boolean;
|
|
126
|
+
status?: number;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/** The Studio usage panels, in display order. */
|
|
130
|
+
declare const FUNCTION_USAGE_PANELS: readonly ["volume", "latency", "hotShards"];
|
|
131
|
+
/** One Studio usage panel. */
|
|
132
|
+
type FunctionUsagePanel = (typeof FUNCTION_USAGE_PANELS)[number];
|
|
133
|
+
/** Options for {@link functionUsageQuery}. */
|
|
134
|
+
interface FunctionUsageQueryOptions {
|
|
135
|
+
/** The Analytics Engine dataset (`analytics_engine_datasets[].dataset`). Defaults to `ANALYTICS`, the one reconcile writes. */
|
|
136
|
+
dataset?: string;
|
|
137
|
+
/** Lower `timestamp` bound, an ISO-8601 string. Defaults to 24 hours before now. The dialect requires one. */
|
|
138
|
+
since?: string;
|
|
139
|
+
}
|
|
140
|
+
/** Whether `value` names a {@link FunctionUsagePanel} — for validating the key an action receives. */
|
|
141
|
+
declare const isFunctionUsagePanel: (value: unknown) => value is FunctionUsagePanel;
|
|
142
|
+
/**
|
|
143
|
+
* The statement and `$since` parameter for one Studio usage panel, to run with
|
|
144
|
+
* `ctx.analyticsSql.query(request.query, request.params)`.
|
|
145
|
+
*
|
|
146
|
+
* The dataset is quoted as an identifier (embedded `"` doubled). It comes from
|
|
147
|
+
* your code, not from the caller.
|
|
148
|
+
*/
|
|
149
|
+
declare const functionUsageQuery: (panel: FunctionUsagePanel, options?: FunctionUsageQueryOptions) => AnalyticsSqlRequest & {
|
|
150
|
+
params: {
|
|
151
|
+
since: string;
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Build an {@link AnalyticsSqlBindingLike} that runs each query over the REST
|
|
156
|
+
* endpoint with an account API token (Account Analytics Read). Use it where the
|
|
157
|
+
* Worker has no `analytics` binding — a wrangler older than 4.145.0, or a host
|
|
158
|
+
* that is not a Worker — and hand it to `createAnalyticsSql({ binding })` or
|
|
159
|
+
* `defineApp().analyticsSql((env) => createAnalyticsSqlRest({ … }))`.
|
|
160
|
+
*
|
|
161
|
+
* Every failure is an {@link AnalyticsSqlQueryError}: a non-2xx (`429` / `500`
|
|
162
|
+
* / `503` / `507` retryable), a malformed body (not retryable), the deadline
|
|
163
|
+
* (`504`, retryable), or the request never reaching the API — DNS, a reset
|
|
164
|
+
* connection — which is retryable too. Nothing is retried here.
|
|
165
|
+
*
|
|
166
|
+
* The token is a secret: read it from `env`, never from a browser.
|
|
167
|
+
*/
|
|
168
|
+
declare const createAnalyticsSqlRest: (config: AnalyticsSqlRestConfig) => AnalyticsSqlBindingLike;
|
|
169
|
+
export { type AnalyticsSql, type AnalyticsSqlBindingLike, type AnalyticsSqlOptions, type AnalyticsSqlParameter, type AnalyticsSqlParams, AnalyticsSqlQueryError, type AnalyticsSqlQueryErrorData, type AnalyticsSqlQueryResult, type AnalyticsSqlRawResult, type AnalyticsSqlRequest, type AnalyticsSqlRestConfig, type AnalyticsSqlStatistics, FUNCTION_USAGE_PANELS, type FunctionUsagePanel, type FunctionUsageQueryOptions,
|
|
170
|
+
/**
|
|
171
|
+
* `ctx.analyticsSql` — read-only SQL over Cloudflare's Analytics SQL API, through
|
|
172
|
+
* the Analytics SQL Workers binding (wrangler `analytics` key, ≥ 4.145.0) or the
|
|
173
|
+
* API-token REST transport where there is no binding.
|
|
174
|
+
*/
|
|
175
|
+
createAnalyticsSql, createAnalyticsSqlRest, functionUsageQuery, isFunctionUsagePanel };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createAnalyticsSql as t}from"../packem_shared/createAnalyticsSql-BLoq02Nf.mjs";import{AnalyticsSqlQueryError as a}from"../packem_shared/AnalyticsSqlQueryError-DjoIZv5O.mjs";import{FUNCTION_USAGE_PANELS as c,functionUsageQuery as l,isFunctionUsagePanel as s}from"../packem_shared/FUNCTION_USAGE_PANELS-C5yhnDmF.mjs";import{createAnalyticsSqlRest as f}from"../packem_shared/createAnalyticsSqlRest-3Zndhp1B.mjs";export{a as AnalyticsSqlQueryError,c as FUNCTION_USAGE_PANELS,t as createAnalyticsSql,f as createAnalyticsSqlRest,l as functionUsageQuery,s as isFunctionUsagePanel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as t}from"@lunora/errors";import{c as s}from"./cap-error-body-YBKO32BF.mjs";class u extends t{retryable;constructor(a,r){const e={retryable:r.retryable};super("ANALYTICS_SQL_QUERY_ERROR",`Analytics SQL query failed: ${s(a)}`,{cause:r.cause??a,data:e,name:"AnalyticsSqlQueryError",...r.status===void 0?{}:{status:r.status}}),this.retryable=r.retryable}}export{u as AnalyticsSqlQueryError};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const l=["volume","latency","hotShards"];const a={hotShards:e=>`SELECT blob3 AS shard, COUNT(*) AS calls FROM ${e} WHERE timestamp >= $since AND blob1 = 'function_call' GROUP BY shard ORDER BY calls DESC LIMIT 25`,latency:e=>`SELECT blob2 AS fn, quantileWeighted(0.50, double1, sampleInterval) AS p50, quantileWeighted(0.95, double1, sampleInterval) AS p95 FROM ${e} WHERE timestamp >= $since AND blob1 = 'function_call' GROUP BY fn ORDER BY p95 DESC LIMIT 25`,volume:e=>`SELECT blob2 AS fn, COUNT(*) AS calls FROM ${e} WHERE timestamp >= $since AND blob1 = 'function_call' GROUP BY fn ORDER BY calls DESC LIMIT 25`},c=e=>typeof e=="string"&&l.includes(e),o=(e,n={})=>{const t=n.dataset??"ANALYTICS";return{params:{since:n.since??new Date(Date.now()-864e5).toISOString()},query:a[e](`events.analyticsEngine."${t.replaceAll('"','""')}"`)}};export{l as FUNCTION_USAGE_PANELS,o as functionUsageQuery,c as isFunctionUsagePanel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as d}from"@lunora/errors";import{c as f}from"./cap-error-body-YBKO32BF.mjs";import{s as h}from"./sql-rest-post-CDcOxw4h.mjs";import y from"./SelectBuilder-DJXNSdqC.mjs";import{ident as m,toText as l}from"./Sql-BfnxRway.mjs";const R="https://api.sql.cloudflarestorage.com/api/v1/accounts",w=6e4,E=e=>e[0]===void 0?[]:Object.keys(e[0]).map(s=>({name:s}));class u extends d{constructor(s,c){super("R2_SQL_ERROR",`R2 SQL query failed (${String(s)}): ${f(c)}`,{cause:c,name:"R2SqlError",status:s})}}const A=e=>{const s=e.fetch??globalThis.fetch,p=`${e.endpoint??R}/${encodeURIComponent(e.accountId)}/r2-sql/query/${encodeURIComponent(e.bucket)}`,S=`${e.accountId}_${e.bucket}`,i=e.timeoutMs??w,n=async t=>{const o=await h({apiToken:e.apiToken,body:{query:t,warehouse:S},fetch:s,timeoutMs:i,url:p});if("timedOut"in o)throw new u(504,`query timed out after ${String(i)}ms (R2SqlConfig.timeoutMs)`);if(!o.ok)throw new u(o.status,o.text);const r=o.json;if(r.success===!1||r.errors!==void 0&&r.errors.length>0)throw new u(502,JSON.stringify(r.errors??r));const a=r.result?.rows??[];return{columns:r.result?.schema??E(a),rowCount:a.length,rows:a}};return{describe:async t=>n(`DESCRIBE ${m(t)}`),explain:async(t,o)=>n(`EXPLAIN ${o?.format==="json"?"FORMAT JSON ":""}${l(t)}`),from:t=>new y(n,t),query:async t=>n(l(t)),showDatabases:async()=>n("SHOW DATABASES"),showTables:async t=>n(`SHOW TABLES IN ${m(t)}`)}};export{u as R2SqlError,A as createR2Sql};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AnalyticsSqlQueryError as a}from"./AnalyticsSqlQueryError-DjoIZv5O.mjs";const o=t=>typeof t=="object"&&t!==null&&t.retryable===!0,c=t=>t instanceof Error?t.message:String(t),l=t=>{const{binding:i}=t;return{query:async(n,r)=>{let s;try{s=await i.query({query:n,...r===void 0?{}:{params:r}})}catch(e){throw e instanceof a?e:new a(c(e),{cause:e,retryable:o(e)})}return{rowCount:s.rows,rows:s.data,...s.statistics===void 0?{}:{statistics:s.statistics}}}}};export{l as createAnalyticsSql};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{s as c}from"./sql-rest-post-CDcOxw4h.mjs";import{AnalyticsSqlQueryError as a}from"./AnalyticsSqlQueryError-DjoIZv5O.mjs";const u="https://api.cloudflare.com/client/v4/analytics/sql",l=6e4,y=new Set([429,500,503,507]),p=e=>{const n=e.fetch??globalThis.fetch.bind(globalThis),o=e.timeoutMs??l;return{query:async r=>{let t;try{t=await c({apiToken:e.apiToken,body:{query:r.query,...r.params===void 0?{}:{params:r.params},scope:{accountTag:e.accountId}},fetch:n,timeoutMs:o,url:u})}catch(i){throw new a(`the request did not reach the SQL API: ${String(i)}`,{cause:i,retryable:!0,status:502})}if("timedOut"in t)throw new a(`query timed out after ${String(o)}ms (AnalyticsSqlRestConfig.timeoutMs)`,{retryable:!0,status:504});if(!t.ok)throw new a(`${String(t.status)} ${t.text}`,{cause:t.text,retryable:y.has(t.status),status:t.status});const s=t.json;if(s===null||typeof s!="object"||!Array.isArray(s.data))throw new a("the SQL API returned a body without a data array",{cause:t.json,retryable:!1,status:502});return{data:s.data,rows:typeof s.rows=="number"?s.rows:s.data.length,...s.statistics===void 0?{}:{statistics:s.statistics}}}}};export{p as createAnalyticsSqlRest};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const u=(o,r,n)=>{if(r===void 0)return{dispose:()=>{},signal:o};const e=new AbortController,s=setTimeout(()=>{e.abort(n())},r);return{dispose:()=>{clearTimeout(s)},signal:e.signal}},l=async({apiToken:o,body:r,fetch:n,timeoutMs:e,url:s})=>{const a=u(void 0,e,()=>new DOMException(`deadline of ${String(e)}ms exceeded`,"TimeoutError")),d=()=>a.signal?.aborted===!0;try{const t=await n(s,{body:JSON.stringify(r),headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"},method:"POST",signal:a.signal});if(!t.ok){const i=await t.text().catch(()=>"<error body unavailable: the request deadline fired before it was read>");return{ok:!1,status:t.status,text:i}}try{return{json:await t.json(),ok:!0}}catch(i){return d()?{timedOut:!0}:{ok:!1,status:502,text:`the endpoint returned a non-JSON body (HTTP ${String(t.status)}): ${String(i)}`}}}catch(t){if(d())return{timedOut:!0};throw t}finally{a.dispose()}};export{l as s};
|
package/dist/r2sql/index.d.mts
CHANGED
|
@@ -80,8 +80,8 @@ declare const renderOrderTerm: (term: OrderTerm) => string;
|
|
|
80
80
|
*
|
|
81
81
|
* Everything here is deliberately structural (no hard dependency on
|
|
82
82
|
* `@cloudflare/workers-types`) so unit tests can inject a plain `fetch` double
|
|
83
|
-
* and never touch the network — mirroring
|
|
84
|
-
* `@lunora/bindings/analytics`.
|
|
83
|
+
* and never touch the network — mirroring the REST transport config in
|
|
84
|
+
* `@lunora/bindings/analytics-sql`.
|
|
85
85
|
*/
|
|
86
86
|
/**
|
|
87
87
|
* Configuration for a {@link import("./client").R2SqlClient | R2SqlClient}.
|
package/dist/r2sql/index.d.ts
CHANGED
|
@@ -80,8 +80,8 @@ declare const renderOrderTerm: (term: OrderTerm) => string;
|
|
|
80
80
|
*
|
|
81
81
|
* Everything here is deliberately structural (no hard dependency on
|
|
82
82
|
* `@cloudflare/workers-types`) so unit tests can inject a plain `fetch` double
|
|
83
|
-
* and never touch the network — mirroring
|
|
84
|
-
* `@lunora/bindings/analytics`.
|
|
83
|
+
* and never touch the network — mirroring the REST transport config in
|
|
84
|
+
* `@lunora/bindings/analytics-sql`.
|
|
85
85
|
*/
|
|
86
86
|
/**
|
|
87
87
|
* Configuration for a {@link import("./client").R2SqlClient | R2SqlClient}.
|
package/dist/r2sql/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as o}from"../packem_shared/SelectBuilder-DJXNSdqC.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-
|
|
1
|
+
import{default as o}from"../packem_shared/SelectBuilder-DJXNSdqC.mjs";import{R2SqlError as l,createR2Sql as f}from"../packem_shared/R2SqlError-5z-ShSB5.mjs";import{asc as d,desc as i,renderOrderTerm as n}from"../packem_shared/asc-DP_WFiAE.mjs";import{default as s}from"../packem_shared/SetOperation-kiI5Wnlm.mjs";import{Sql as m,ident as S,isSql as q,joinSql as c,lit as u,raw as w,sql as R,tableRef as E,toText as O}from"../packem_shared/Sql-BfnxRway.mjs";import{WindowFunction as W,fn as b}from"../packem_shared/WindowFunction-CL4jYy2l.mjs";import{default as B}from"../packem_shared/WindowExpression-VX7EEV3h.mjs";export{l as R2SqlError,o as SelectBuilder,s as SetOperation,m as Sql,B as WindowExpression,W as WindowFunction,d as asc,f as createR2Sql,i as desc,b as fn,S as ident,q as isSql,c as joinSql,u as lit,w as raw,n as renderOrderTerm,R as sql,E as tableRef,O as toText};
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/bindings",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
4
|
-
"description": "Lightweight Cloudflare binding helpers for Lunora — ctx.kv, ctx.images, ctx.analytics, ctx.pipelines, ctx.vectors, ctx.r2sql, ctx.artifacts, ctx.aiSearch — one install, per-binding subpaths",
|
|
3
|
+
"version": "1.0.0-alpha.93",
|
|
4
|
+
"description": "Lightweight Cloudflare binding helpers for Lunora — ctx.kv, ctx.images, ctx.analytics, ctx.pipelines, ctx.vectors, ctx.r2sql, ctx.artifacts, ctx.aiSearch, ctx.analyticsSql — one install, per-binding subpaths",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-search",
|
|
7
7
|
"analytics",
|
|
8
|
+
"analytics-sql",
|
|
8
9
|
"artifacts",
|
|
9
10
|
"cloudflare",
|
|
10
11
|
"images",
|
|
@@ -48,6 +49,10 @@
|
|
|
48
49
|
"types": "./dist/analytics/index.d.ts",
|
|
49
50
|
"import": "./dist/analytics/index.mjs"
|
|
50
51
|
},
|
|
52
|
+
"./analytics-sql": {
|
|
53
|
+
"types": "./dist/analytics-sql/index.d.ts",
|
|
54
|
+
"import": "./dist/analytics-sql/index.mjs"
|
|
55
|
+
},
|
|
51
56
|
"./pipelines": {
|
|
52
57
|
"types": "./dist/pipelines/index.d.ts",
|
|
53
58
|
"import": "./dist/pipelines/index.mjs"
|
|
@@ -74,8 +79,8 @@
|
|
|
74
79
|
"access": "public"
|
|
75
80
|
},
|
|
76
81
|
"dependencies": {
|
|
77
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
78
|
-
"@lunora/platform": "1.0.0-alpha.
|
|
82
|
+
"@lunora/errors": "1.0.0-alpha.50",
|
|
83
|
+
"@lunora/platform": "1.0.0-alpha.52"
|
|
79
84
|
},
|
|
80
85
|
"engines": {
|
|
81
86
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as y}from"@lunora/errors";import{c as h}from"./cap-error-body-YBKO32BF.mjs";const w="https://api.cloudflare.com/client/v4/accounts",S=6e4;class a extends y{constructor(r,o){super("ANALYTICS_SQL_ERROR",`Analytics Engine SQL API returned ${String(r)}: ${h(o)}`,{cause:o,name:"AnalyticsSqlError",status:r})}}const b=e=>{const r=e.fetch??globalThis.fetch,o=`${w}/${encodeURIComponent(e.accountId)}/analytics_engine/sql`,c=e.timeoutMs??S;return{query:async u=>{const n=new AbortController,d=setTimeout(()=>{n.abort()},c);try{const t=await r(o,{body:u,headers:{Authorization:`Bearer ${e.apiToken}`,"Content-Type":"text/plain"},method:"POST",signal:n.signal});if(!t.ok)throw new a(t.status,await t.text().catch(()=>"<error body unavailable: the request deadline fired before it was read>"));let i;try{i=await t.json()}catch(m){throw n.signal.aborted?m:new a(t.status,"Analytics Engine SQL API returned a non-JSON body.")}const s=i,l=s.data??[];return{columns:s.meta??[],rowCount:s.rows??l.length,rows:l}}catch(t){throw n.signal.aborted&&!(t instanceof a)?new a(504,`query timed out after ${String(c)}ms (AnalyticsSqlConfig.timeoutMs)`):t}finally{clearTimeout(d)}}}};export{a as AnalyticsSqlError,b as createAnalyticsSqlClient};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as f}from"@lunora/errors";import{c as b}from"./cap-error-body-YBKO32BF.mjs";import R from"./SelectBuilder-DJXNSdqC.mjs";import{ident as m,toText as h}from"./Sql-BfnxRway.mjs";const T="https://api.sql.cloudflarestorage.com/api/v1/accounts",E=6e4,$=e=>e[0]===void 0?[]:Object.keys(e[0]).map(s=>({name:s}));class c extends f{constructor(s,i){super("R2_SQL_ERROR",`R2 SQL query failed (${String(s)}): ${b(i)}`,{cause:i,name:"R2SqlError",status:s})}}const C=e=>{const s=e.fetch??globalThis.fetch,S=`${e.endpoint??T}/${encodeURIComponent(e.accountId)}/r2-sql/query/${encodeURIComponent(e.bucket)}`,p=`${e.accountId}_${e.bucket}`,l=e.timeoutMs??E,n=async t=>{const a=new AbortController,w=setTimeout(()=>{a.abort()},l);try{const r=await s(S,{body:JSON.stringify({query:t,warehouse:p}),headers:{Authorization:`Bearer ${e.apiToken}`,"Content-Type":"application/json"},method:"POST",signal:a.signal});if(!r.ok)throw new c(r.status,await r.text().catch(()=>"<error body unavailable: the request deadline fired before it was read>"));let d;try{d=await r.json()}catch(y){throw a.signal.aborted?y:new c(r.status,"R2 SQL returned a non-JSON body.")}const o=d;if(o.success===!1||o.errors!==void 0&&o.errors.length>0)throw new c(r.status,JSON.stringify(o.errors??o));const u=o.result?.rows??[];return{columns:o.result?.schema??$(u),rowCount:u.length,rows:u}}catch(r){throw a.signal.aborted&&!(r instanceof c)?new c(504,`query timed out after ${String(l)}ms (R2SqlConfig.timeoutMs)`):r}finally{clearTimeout(w)}};return{describe:async t=>n(`DESCRIBE ${m(t)}`),explain:async(t,a)=>n(`EXPLAIN ${a?.format==="json"?"FORMAT JSON ":""}${h(t)}`),from:t=>new R(n,t),query:async t=>n(h(t)),showDatabases:async()=>n("SHOW DATABASES"),showTables:async t=>n(`SHOW TABLES IN ${m(t)}`)}};export{c as R2SqlError,C as createR2Sql};
|