@agent-native/core-corpus 0.209.2 → 0.209.3-nightly-20261016183441
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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +9 -0
- package/corpus/templates/analytics/app/components/auth/SqlQuerySnapshotSessionBridge.tsx +25 -0
- package/corpus/templates/analytics/app/components/dashboard/PanelFreshnessClock.tsx +140 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +104 -48
- package/corpus/templates/analytics/app/components/dashboard/panel-freshness.ts +171 -0
- package/corpus/templates/analytics/app/global.css +59 -0
- package/corpus/templates/analytics/app/i18n/en-US.ts +8 -0
- package/corpus/templates/analytics/app/lib/cost-tracker.ts +122 -16
- package/corpus/templates/analytics/app/lib/query-metrics.ts +50 -13
- package/corpus/templates/analytics/app/lib/sql-query-cache.ts +697 -0
- package/corpus/templates/analytics/app/lib/sql-query-freshness.ts +85 -0
- package/corpus/templates/analytics/app/lib/sql-query-snapshot-session.ts +145 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +366 -36
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +73 -18
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/filter-vars.ts +45 -12
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +5 -0
- package/corpus/templates/analytics/app/root.tsx +2 -0
- package/corpus/templates/analytics/changelog/2026-10-14-dashboard-charts-now-reappear-instantly-after-a-reload-from-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-14-dashboard-panels-show-fetch-time-in-a-clock-and-label-only-st.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-15-dashboard-query-costs-and-refresh-confirmations-reflect-actu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-15-dashboard-results-disappear-when-access-is-withdrawn-and-exp.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-dashboard-freshness-stays-in-the-title-row-with-compact-upda.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-dashboard-update-status-remains-visible-for-sources-without-.md +6 -0
- package/corpus/templates/analytics/server/lib/bigquery.ts +35 -4
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +2 -3
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +9 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +2 -2
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +4 -2
- package/corpus/templates/analytics/shared/sql-query-contract.ts +49 -0
- package/corpus/templates/assets/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/brain/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/calendar/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/chat/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/clips/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/content/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/crm/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/design/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +24 -0
- package/corpus/templates/design/app/components/design/types.ts +1 -0
- package/corpus/templates/design/app/lib/design-import.ts +35 -0
- package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +11 -0
- package/corpus/templates/design/app/pages/design-editor/command-types.ts +2 -0
- package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +3 -0
- package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +19 -0
- package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +118 -20
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-layer-actions.ts +15 -3
- package/corpus/templates/design/app/pages/design-editor/relative-position-offset.ts +109 -0
- package/corpus/templates/design/changelog/2026-10-15-dragged-layers-use-the-final-release-position.md +6 -0
- package/corpus/templates/design/changelog/2026-10-15-repeated-pastes-preserve-relative-layer-offsets.md +6 -0
- package/corpus/templates/design/changelog/2026-10-15-text-wrapping-hug-widths.md +6 -0
- package/corpus/templates/design/shared/code-layer.ts +2 -1
- package/corpus/templates/design/shared/relative-position-containing-block.ts +40 -0
- package/corpus/templates/dispatch/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/forms/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/mail/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/plan/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/slides/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +137 -118
- package/corpus/templates/slides/changelog/2026-10-16-search-and-preview-reference-decks-before-choosing-one.md +6 -0
- package/package.json +1 -1
|
@@ -36,6 +36,18 @@ function daysAgo(n: number): string {
|
|
|
36
36
|
return d.toISOString().slice(0, 10);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// Filter values come straight from the URL. An "Nd" value past this bound is
|
|
40
|
+
// not a range (a huge count makes an invalid Date that throws in
|
|
41
|
+
// toISOString), so callers treat it like any other unrecognized value.
|
|
42
|
+
const MAX_DAY_COUNT = 36_500;
|
|
43
|
+
|
|
44
|
+
function parseDayCount(value: string): number | null {
|
|
45
|
+
const match = /^(\d+)d$/.exec(value);
|
|
46
|
+
if (!match) return null;
|
|
47
|
+
const days = Number(match[1]);
|
|
48
|
+
return days <= MAX_DAY_COUNT ? days : null;
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
40
52
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
53
|
}
|
|
@@ -66,7 +78,8 @@ export function isDashboardFilter(value: unknown): value is DashboardFilter {
|
|
|
66
78
|
typeof option.label === "string",
|
|
67
79
|
))) &&
|
|
68
80
|
(value.presets === undefined ||
|
|
69
|
-
(Array.isArray(value.presets) && value.presets.every(isFilterPreset)))
|
|
81
|
+
(Array.isArray(value.presets) && value.presets.every(isFilterPreset))) &&
|
|
82
|
+
(value.customRange === undefined || typeof value.customRange === "boolean")
|
|
70
83
|
);
|
|
71
84
|
}
|
|
72
85
|
|
|
@@ -134,7 +147,9 @@ export function usableFilterPresets(
|
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
export function isDateRangePresetFilter(filter: DashboardFilter): boolean {
|
|
137
|
-
if (filter.type !== "select"
|
|
150
|
+
if (filter.type !== "select") return false;
|
|
151
|
+
if (filter.customRange === true) return true;
|
|
152
|
+
if (!filter.options?.length) return false;
|
|
138
153
|
const isRange = (value: string) => /^\d+d$/.test(value);
|
|
139
154
|
return (
|
|
140
155
|
filter.options.some((option) => isRange(option.value)) &&
|
|
@@ -180,8 +195,8 @@ export function resolveDefault(
|
|
|
180
195
|
): string {
|
|
181
196
|
if (!raw) return "";
|
|
182
197
|
if (DATE_FILTER_TYPES.has(type)) {
|
|
183
|
-
const
|
|
184
|
-
if (
|
|
198
|
+
const days = parseDayCount(raw);
|
|
199
|
+
if (days !== null) return daysAgo(days);
|
|
185
200
|
if (raw === "today") return daysAgo(0);
|
|
186
201
|
}
|
|
187
202
|
return raw;
|
|
@@ -215,8 +230,8 @@ function resolveDateParam(
|
|
|
215
230
|
}
|
|
216
231
|
|
|
217
232
|
function dateRangeStart(range: string): string {
|
|
218
|
-
|
|
219
|
-
return
|
|
233
|
+
if (range === "all") return ALL_TIME_START;
|
|
234
|
+
return daysAgo(parseDayCount(range) ?? 30);
|
|
220
235
|
}
|
|
221
236
|
|
|
222
237
|
export function resolveDefaultFilterVars(
|
|
@@ -249,22 +264,40 @@ export function resolveFilterVars(
|
|
|
249
264
|
? resolveDateValue(getParam(filter.id), ALL_TIME_START)
|
|
250
265
|
: getParam(filter.id);
|
|
251
266
|
} else if (isDateRangePresetFilter(filter)) {
|
|
267
|
+
const requested = getParam(filter.id);
|
|
268
|
+
// A customRange select only takes a value it offers ("custom" always
|
|
269
|
+
// is), so a URL can't pick a period or range the dashboard doesn't have.
|
|
270
|
+
const offered =
|
|
271
|
+
filter.customRange !== true ||
|
|
272
|
+
requested === "custom" ||
|
|
273
|
+
!!filter.options?.some((option) => option.value === requested);
|
|
252
274
|
const value =
|
|
253
|
-
|
|
275
|
+
(offered && requested) || resolveDefault(filter.default, filter.type);
|
|
254
276
|
const startKey = filter.id + "Start";
|
|
255
277
|
const endKey = filter.id + "End";
|
|
256
278
|
const defaultRange = value === "custom" ? filter.default || "30d" : value;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
279
|
+
// On a customRange select only "30d"-style and "all" options imply
|
|
280
|
+
// bounds; an option such as "this" (quarter) leaves the range empty for
|
|
281
|
+
// the SQL to resolve.
|
|
282
|
+
const impliesBounds =
|
|
283
|
+
value !== "custom" &&
|
|
284
|
+
(filter.customRange !== true ||
|
|
285
|
+
parseDayCount(value) !== null ||
|
|
286
|
+
value === "all");
|
|
287
|
+
const fallbackStart = impliesBounds ? dateRangeStart(defaultRange) : "";
|
|
288
|
+
const fallbackEnd = impliesBounds ? daysAgo(0) : "";
|
|
289
|
+
// A customRange select only takes bounds from the URL while "custom" is
|
|
290
|
+
// picked, so a stale range in a shared link can't hide behind a period
|
|
291
|
+
// label.
|
|
292
|
+
const urlBounds = filter.customRange !== true || value === "custom";
|
|
260
293
|
out[filter.id] = value;
|
|
261
294
|
out[startKey] = resolveDateParam(
|
|
262
|
-
getParam(startKey),
|
|
295
|
+
urlBounds ? getParam(startKey) : "",
|
|
263
296
|
fallbackStart,
|
|
264
297
|
fallbackStart,
|
|
265
298
|
);
|
|
266
299
|
out[endKey] = resolveDateParam(
|
|
267
|
-
getParam(endKey),
|
|
300
|
+
urlBounds ? getParam(endKey) : "",
|
|
268
301
|
fallbackEnd,
|
|
269
302
|
fallbackEnd,
|
|
270
303
|
);
|
|
@@ -51,6 +51,11 @@ export interface DashboardFilter {
|
|
|
51
51
|
default?: string;
|
|
52
52
|
options?: FilterOption[];
|
|
53
53
|
presets?: FilterPreset[];
|
|
54
|
+
// On a select filter: show a date range only when "custom" is chosen, and
|
|
55
|
+
// clear it when another option is picked (as preset date filters do for
|
|
56
|
+
// "30d"-style options). For selects whose options are periods the SQL
|
|
57
|
+
// resolves itself, such as "this" / "last" quarter.
|
|
58
|
+
customRange?: boolean;
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
export type ColumnFormat =
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import type { LinksFunction } from "react-router";
|
|
22
22
|
|
|
23
23
|
import { AuthProvider } from "@/components/auth/AuthProvider";
|
|
24
|
+
import { SqlQuerySnapshotSessionBridge } from "@/components/auth/SqlQuerySnapshotSessionBridge";
|
|
24
25
|
import { ProviderCorpusJobNotifier } from "@/components/ProviderCorpusJobNotifier";
|
|
25
26
|
import "@/lib/register-analysis-result-renderer";
|
|
26
27
|
import { Toaster as Sonner } from "@/components/ui/sonner";
|
|
@@ -161,6 +162,7 @@ export default function Root() {
|
|
|
161
162
|
|
|
162
163
|
return (
|
|
163
164
|
<AppToolkitProvider>
|
|
165
|
+
<SqlQuerySnapshotSessionBridge />
|
|
164
166
|
<AppProviders
|
|
165
167
|
queryClient={queryClient}
|
|
166
168
|
skeletonLayout="assistant"
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: improved
|
|
3
|
+
date: 2026-10-14
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Dashboard panels no longer carry a fetch-time badge: the time and cache state sit behind a clock in each panel's hover actions, and a panel only says so in plain text while it updates, briefly after you refresh it, or when its data is over an hour old, in a reserved line that keeps the chart from moving when the text appears or goes.
|
|
@@ -649,15 +649,31 @@ async function beginCacheQuery(
|
|
|
649
649
|
};
|
|
650
650
|
}
|
|
651
651
|
|
|
652
|
+
function toIsoTimestamp(value: unknown): string | undefined {
|
|
653
|
+
if (typeof value !== "string" && !(value instanceof Date)) return undefined;
|
|
654
|
+
const time = value instanceof Date ? value.getTime() : Date.parse(value);
|
|
655
|
+
return Number.isFinite(time) ? new Date(time).toISOString() : undefined;
|
|
656
|
+
}
|
|
657
|
+
|
|
652
658
|
async function getL2(key: string): Promise<QueryResult | null> {
|
|
653
659
|
const db = getDbExec();
|
|
654
660
|
const { rows } = await db.execute({
|
|
655
|
-
sql: "SELECT result FROM bigquery_cache WHERE key = $1 AND expires_at > $2",
|
|
661
|
+
sql: "SELECT result, created_at FROM bigquery_cache WHERE key = $1 AND expires_at > $2",
|
|
656
662
|
args: [key, new Date().toISOString()],
|
|
657
663
|
});
|
|
658
664
|
if (!rows.length) return null;
|
|
659
|
-
const
|
|
660
|
-
|
|
665
|
+
const entry = rows[0] as { result: string; created_at?: unknown };
|
|
666
|
+
const result = JSON.parse(entry.result) as QueryResult;
|
|
667
|
+
// Rows cached before fetchedAt was persisted fall back to the row's
|
|
668
|
+
// created_at, when the app cached the result; an unreadable one stays absent
|
|
669
|
+
// rather than becoming "now".
|
|
670
|
+
const fetchedAt =
|
|
671
|
+
toIsoTimestamp(result.fetchedAt) ?? toIsoTimestamp(entry.created_at);
|
|
672
|
+
if (fetchedAt === undefined) {
|
|
673
|
+
const { fetchedAt: _unreadable, ...rest } = result;
|
|
674
|
+
return rest;
|
|
675
|
+
}
|
|
676
|
+
return { ...result, fetchedAt };
|
|
661
677
|
}
|
|
662
678
|
|
|
663
679
|
async function finishCacheQuery(
|
|
@@ -798,6 +814,14 @@ export interface QueryResult {
|
|
|
798
814
|
bytesProcessed: number;
|
|
799
815
|
cached?: boolean;
|
|
800
816
|
truncated?: boolean;
|
|
817
|
+
/**
|
|
818
|
+
* When the app first received this result from BigQuery; preserved across
|
|
819
|
+
* app-cache hits. Not when the warehouse computed it: a provider cache hit
|
|
820
|
+
* can return an older BigQuery result.
|
|
821
|
+
*/
|
|
822
|
+
fetchedAt?: string;
|
|
823
|
+
/** BigQuery getQueryResults `cacheHit` for the original request; absent means unknown. */
|
|
824
|
+
providerCacheHit?: boolean;
|
|
801
825
|
}
|
|
802
826
|
|
|
803
827
|
export interface RunQueryOptions {
|
|
@@ -819,6 +843,7 @@ interface BigQueryGetQueryResultsResponse {
|
|
|
819
843
|
totalRows?: string;
|
|
820
844
|
jobComplete?: boolean;
|
|
821
845
|
totalBytesProcessed?: string;
|
|
846
|
+
cacheHit?: boolean;
|
|
822
847
|
errorResult?: { message?: string; reason?: string };
|
|
823
848
|
errors?: Array<{ message?: string; reason?: string }>;
|
|
824
849
|
}
|
|
@@ -1334,6 +1359,7 @@ export async function runQuery(
|
|
|
1334
1359
|
throw new BigQueryQueryTimeoutError();
|
|
1335
1360
|
}
|
|
1336
1361
|
|
|
1362
|
+
const fetchedAt = new Date().toISOString();
|
|
1337
1363
|
const fields = data.schema?.fields ?? [];
|
|
1338
1364
|
const schema = fields.map((f) => ({
|
|
1339
1365
|
name: f.name,
|
|
@@ -1353,6 +1379,10 @@ export async function runQuery(
|
|
|
1353
1379
|
totalRows,
|
|
1354
1380
|
schema,
|
|
1355
1381
|
bytesProcessed,
|
|
1382
|
+
fetchedAt,
|
|
1383
|
+
...(typeof data.cacheHit === "boolean"
|
|
1384
|
+
? { providerCacheHit: data.cacheHit }
|
|
1385
|
+
: {}),
|
|
1356
1386
|
...(totalRows > rows.length ? { truncated: true } : {}),
|
|
1357
1387
|
};
|
|
1358
1388
|
|
|
@@ -1367,7 +1397,8 @@ export async function runQuery(
|
|
|
1367
1397
|
else await releaseCacheQuery(cacheKey, cacheFence);
|
|
1368
1398
|
}
|
|
1369
1399
|
|
|
1370
|
-
|
|
1400
|
+
// The cached copy stays unflagged: every read of it sets `cached: true`.
|
|
1401
|
+
return { ...result, cached: false };
|
|
1371
1402
|
} catch (error) {
|
|
1372
1403
|
if (jobId) cancelJob = true;
|
|
1373
1404
|
if (cancelJob && jobId && token) {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "@agent-native/core/data-programs";
|
|
7
7
|
import type { MissingKeyResponse } from "@agent-native/core/server";
|
|
8
8
|
|
|
9
|
+
import type { SqlQueryExecutionMetadata } from "../../shared/sql-query-contract";
|
|
9
10
|
import { getUserSegmentation, queryEvents } from "./amplitude";
|
|
10
11
|
import { runQuery } from "./bigquery";
|
|
11
12
|
import { runDemoPanel, serializeDemoDescriptorInput } from "./demo-source";
|
|
@@ -30,11 +31,9 @@ export const DASHBOARD_PANEL_SOURCES = [
|
|
|
30
31
|
|
|
31
32
|
export type DashboardPanelSource = (typeof DASHBOARD_PANEL_SOURCES)[number];
|
|
32
33
|
|
|
33
|
-
export interface DashboardPanelQueryResult {
|
|
34
|
+
export interface DashboardPanelQueryResult extends SqlQueryExecutionMetadata {
|
|
34
35
|
rows: Record<string, unknown>[];
|
|
35
36
|
schema: { name: string; type: string }[];
|
|
36
|
-
truncated?: boolean;
|
|
37
|
-
bytesProcessed?: number;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
export interface UnsupportedBackendResponse {
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import { requireRequestCredentialContext } from "./credentials-context.js";
|
|
19
19
|
import { firstPartyEventPushdownPredicates } from "./first-party-analytics-pushdown.js";
|
|
20
20
|
import { validateAnalyticsSqlFunctions } from "./first-party-analytics-sql-policy.js";
|
|
21
|
+
import type { AnalyticsQueryResult } from "./first-party-analytics.js";
|
|
21
22
|
import {
|
|
22
23
|
fetchGoogleWithRetry,
|
|
23
24
|
getBigQueryAccessToken,
|
|
@@ -1568,11 +1569,7 @@ export async function queryFirstPartyAnalyticsInBigQuery(
|
|
|
1568
1569
|
timeoutMs?: number;
|
|
1569
1570
|
signal?: AbortSignal;
|
|
1570
1571
|
} = {},
|
|
1571
|
-
): Promise<{
|
|
1572
|
-
rows: Record<string, unknown>[];
|
|
1573
|
-
schema: { name: string; type: string }[];
|
|
1574
|
-
truncated?: boolean;
|
|
1575
|
-
}> {
|
|
1572
|
+
): Promise<AnalyticsQueryResult> {
|
|
1576
1573
|
const timeoutMs = options.timeoutMs;
|
|
1577
1574
|
if (
|
|
1578
1575
|
timeoutMs !== undefined &&
|
|
@@ -1610,7 +1607,13 @@ export async function queryFirstPartyAnalyticsInBigQuery(
|
|
|
1610
1607
|
return {
|
|
1611
1608
|
rows: result.rows,
|
|
1612
1609
|
schema: result.schema,
|
|
1613
|
-
|
|
1610
|
+
bytesProcessed: result.bytesProcessed,
|
|
1611
|
+
...(result.cached !== undefined ? { cached: result.cached } : {}),
|
|
1612
|
+
...(result.providerCacheHit !== undefined
|
|
1613
|
+
? { providerCacheHit: result.providerCacheHit }
|
|
1614
|
+
: {}),
|
|
1615
|
+
...(result.fetchedAt !== undefined ? { fetchedAt: result.fetchedAt } : {}),
|
|
1616
|
+
...(result.truncated !== undefined ? { truncated: result.truncated } : {}),
|
|
1614
1617
|
};
|
|
1615
1618
|
}
|
|
1616
1619
|
|
|
@@ -226,7 +226,7 @@ export async function withFirstPartyCache(
|
|
|
226
226
|
): Promise<AnalyticsQueryResult> {
|
|
227
227
|
if (options.signal?.aborted) throw abortError(options.signal);
|
|
228
228
|
const l1Hit = getL1(key);
|
|
229
|
-
if (l1Hit) return l1Hit;
|
|
229
|
+
if (l1Hit) return { ...l1Hit, cached: true };
|
|
230
230
|
|
|
231
231
|
const timeoutMs = Math.max(1, options.timeoutMs ?? CACHE_IO_TIMEOUT_MS);
|
|
232
232
|
const deadlineAt = options.deadlineAt ?? Date.now() + timeoutMs;
|
|
@@ -277,7 +277,7 @@ export async function withFirstPartyCache(
|
|
|
277
277
|
}
|
|
278
278
|
if (l2Hit) {
|
|
279
279
|
setL1(key, l2Hit);
|
|
280
|
-
return l2Hit;
|
|
280
|
+
return { ...l2Hit, cached: true };
|
|
281
281
|
}
|
|
282
282
|
let result: AnalyticsQueryResult;
|
|
283
283
|
let timeoutRetryUsed = false;
|
|
@@ -23,6 +23,7 @@ import { and, eq, getTableName, isNull, lt, or, sql } from "drizzle-orm";
|
|
|
23
23
|
import { PgDialect } from "drizzle-orm/pg-core";
|
|
24
24
|
|
|
25
25
|
import { FIRST_PARTY_ANALYTICS_QUERY_TIMEOUT_MS } from "../../shared/dashboard-report-timeouts.js";
|
|
26
|
+
import type { SqlQueryExecutionMetadata } from "../../shared/sql-query-contract.js";
|
|
26
27
|
import { getDb, schema } from "../db/index.js";
|
|
27
28
|
import {
|
|
28
29
|
EXCEPTION_EVENT_NAME,
|
|
@@ -96,10 +97,9 @@ export interface IncomingAnalyticsEvent {
|
|
|
96
97
|
timestamp?: string | number | Date | null;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
export interface AnalyticsQueryResult {
|
|
100
|
+
export interface AnalyticsQueryResult extends SqlQueryExecutionMetadata {
|
|
100
101
|
rows: Record<string, unknown>[];
|
|
101
102
|
schema: { name: string; type: string }[];
|
|
102
|
-
truncated?: boolean;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export interface AnalyticsQueryOptions {
|
|
@@ -1746,6 +1746,8 @@ export async function queryFirstPartyAnalytics(
|
|
|
1746
1746
|
return {
|
|
1747
1747
|
rows,
|
|
1748
1748
|
schema: inferSchema(rows),
|
|
1749
|
+
cached: false,
|
|
1750
|
+
fetchedAt: new Date().toISOString(),
|
|
1749
1751
|
...(truncated ? { truncated: true } : {}),
|
|
1750
1752
|
};
|
|
1751
1753
|
} catch (error) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface SqlQueryExecutionMetadata {
|
|
2
|
+
bytesProcessed?: number;
|
|
3
|
+
/** The app served existing rows without executing the query again. */
|
|
4
|
+
cached?: boolean;
|
|
5
|
+
/** The provider reported a query-cache hit; absent means unknown. */
|
|
6
|
+
providerCacheHit?: boolean;
|
|
7
|
+
truncated?: boolean;
|
|
8
|
+
/** When these rows were first received, preserved across cache hits. */
|
|
9
|
+
fetchedAt?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SqlQueryRefusal {
|
|
13
|
+
error: string;
|
|
14
|
+
message?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class SqlQueryRefusalError extends Error {
|
|
18
|
+
readonly code: string;
|
|
19
|
+
|
|
20
|
+
constructor(refusal: SqlQueryRefusal) {
|
|
21
|
+
super(refusal.message || refusal.error);
|
|
22
|
+
this.name = "SqlQueryRefusalError";
|
|
23
|
+
this.code = refusal.error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isConfirmedPreQueryFailure(error: unknown): boolean {
|
|
28
|
+
// The action transport rejects unauthenticated callers before dispatch.
|
|
29
|
+
// Other HTTP failures may originate after a provider submitted the query.
|
|
30
|
+
return (
|
|
31
|
+
error instanceof SqlQueryRefusalError ||
|
|
32
|
+
(error instanceof Error && "status" in error && error.status === 401)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isSqlQueryAccessDenied(error: unknown): error is Error {
|
|
37
|
+
if (error instanceof SqlQueryRefusalError) {
|
|
38
|
+
return error.code === "missing_api_key";
|
|
39
|
+
}
|
|
40
|
+
return (
|
|
41
|
+
error instanceof Error &&
|
|
42
|
+
"status" in error &&
|
|
43
|
+
(error.status === 401 || error.status === 403 || error.status === 404)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function supportsSqlQueryCacheBypass(source: string): boolean {
|
|
48
|
+
return source === "bigquery";
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","creative-context","db","labs","onboarding","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","brain-jobs","core-routes","db","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","core-routes","db","event-rules","oauth-refresh","otel","transactional-emails"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","calendar-jobs","config","core-routes","db","feature-flags","labs","onboarding","onboarding-calendar","otel","transactional-email-catalog"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","collab","core-routes","creative-context","db","feature-flags","labs","onboarding","otel","suggested-edits","transactional-emails"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","core-routes","db","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","assets-mcp","auth","builder-host-embed-headers","collab","config","core-routes","creative-context","db","e2e-attachment-storage","feature-flags","journey-canvas-stage-cleanup","labs","local-import-asset-upload","otel","review"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -903,6 +903,24 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
903
903
|
return index;
|
|
904
904
|
}
|
|
905
905
|
|
|
906
|
+
// shared/relative-position-containing-block.ts
|
|
907
|
+
function relativePositionContainingBlockDirection(element, getComputedStyle) {
|
|
908
|
+
let ancestor = element.parentElement;
|
|
909
|
+
while (ancestor) {
|
|
910
|
+
const styles = getComputedStyle(ancestor);
|
|
911
|
+
const display = styles.display;
|
|
912
|
+
if (display === "inline" || display === "contents") {
|
|
913
|
+
ancestor = ancestor.parentElement;
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
if (display === "block" || display === "flow-root" || display === "list-item" || display === "inline-block" || display === "flex" || display === "inline-flex" || display === "grid" || display === "inline-grid" || display === "table-cell" || display === "table-caption") {
|
|
917
|
+
return styles.direction === "ltr" || styles.direction === "rtl" ? styles.direction : void 0;
|
|
918
|
+
}
|
|
919
|
+
return void 0;
|
|
920
|
+
}
|
|
921
|
+
return void 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
906
924
|
// shared/spacing-handle-rule.ts
|
|
907
925
|
function isAutoLayoutDisplay(display) {
|
|
908
926
|
return display === "flex" || display === "inline-flex" || display === "grid" || display === "inline-grid";
|
|
@@ -6030,6 +6048,10 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
6030
6048
|
gridTemplateRows: parentStyles.gridTemplateRows,
|
|
6031
6049
|
position: parentStyles.position
|
|
6032
6050
|
} : void 0;
|
|
6051
|
+
var relativeContainingBlockDirection = cs.position === "relative" ? relativePositionContainingBlockDirection(
|
|
6052
|
+
el,
|
|
6053
|
+
(ancestor) => window.getComputedStyle(ancestor)
|
|
6054
|
+
) : void 0;
|
|
6033
6055
|
var capabilities = sourceBacked ? [
|
|
6034
6056
|
{
|
|
6035
6057
|
kind: "deterministic-style-edit",
|
|
@@ -6110,6 +6132,7 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
6110
6132
|
parentDisplay,
|
|
6111
6133
|
parentAutoLayout,
|
|
6112
6134
|
parentLayout,
|
|
6135
|
+
relativeContainingBlockDirection,
|
|
6113
6136
|
editCapabilities: capabilities,
|
|
6114
6137
|
confidence: capabilities.reduce(function(best, item) {
|
|
6115
6138
|
return Math.max(best, item.confidence || 0);
|
|
@@ -19145,6 +19168,7 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
19145
19168
|
cancelMoveDrag();
|
|
19146
19169
|
}
|
|
19147
19170
|
function onUp(ev) {
|
|
19171
|
+
onMove(ev);
|
|
19148
19172
|
var controllerEnd = bridgeMoveController.pointerUp(
|
|
19149
19173
|
bridgeGesturePointer(ev)
|
|
19150
19174
|
);
|
|
@@ -56,6 +56,11 @@ export interface ImportResultNotification {
|
|
|
56
56
|
description?: string;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
export interface RelativePositionOffset {
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
59
64
|
export function readFigmaImportFailure(
|
|
60
65
|
error: unknown,
|
|
61
66
|
fallbackMessage: string,
|
|
@@ -250,6 +255,7 @@ export interface DesignClipboardLayerEntry {
|
|
|
250
255
|
rootNodeId?: string;
|
|
251
256
|
sourceParentNodeId?: string;
|
|
252
257
|
sourceFileId: string;
|
|
258
|
+
sourceRelativeOffset?: RelativePositionOffset | null;
|
|
253
259
|
portableStyleSnapshot?: PortableStyleSnapshot;
|
|
254
260
|
styleSnapshotCaptureFailed?: boolean;
|
|
255
261
|
managedStyleSnapshot?: DesignClipboardManagedStyleSnapshot;
|
|
@@ -284,6 +290,24 @@ function clipboardString(value: unknown, max = 1_024): value is string {
|
|
|
284
290
|
return typeof value === "string" && value.length <= max;
|
|
285
291
|
}
|
|
286
292
|
|
|
293
|
+
export function isValidRelativePositionOffset(
|
|
294
|
+
value: unknown,
|
|
295
|
+
): value is RelativePositionOffset | null {
|
|
296
|
+
if (value === null) return true;
|
|
297
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const offset = value as Record<string, unknown>;
|
|
301
|
+
return (
|
|
302
|
+
typeof offset.x === "number" &&
|
|
303
|
+
Number.isFinite(offset.x) &&
|
|
304
|
+
Math.abs(offset.x) <= 10_000_000 &&
|
|
305
|
+
typeof offset.y === "number" &&
|
|
306
|
+
Number.isFinite(offset.y) &&
|
|
307
|
+
Math.abs(offset.y) <= 10_000_000
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
287
311
|
function isPortableClipboardStyleSnapshot(value: unknown): boolean {
|
|
288
312
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
289
313
|
const snapshot = value as Record<string, unknown>;
|
|
@@ -348,6 +372,8 @@ function validateDesignClipboardPayload(
|
|
|
348
372
|
(entry.rootNodeId !== undefined && !clipboardString(entry.rootNodeId)) ||
|
|
349
373
|
(entry.sourceParentNodeId !== undefined &&
|
|
350
374
|
!clipboardString(entry.sourceParentNodeId)) ||
|
|
375
|
+
(entry.sourceRelativeOffset !== undefined &&
|
|
376
|
+
!isValidRelativePositionOffset(entry.sourceRelativeOffset)) ||
|
|
351
377
|
(entry.styleSnapshotCaptureFailed !== undefined &&
|
|
352
378
|
typeof entry.styleSnapshotCaptureFailed !== "boolean") ||
|
|
353
379
|
(entry.portableStyleSnapshot !== undefined &&
|
|
@@ -428,6 +454,15 @@ export function serializeDesignClipboardPayload(
|
|
|
428
454
|
payload: DesignClipboardPayload,
|
|
429
455
|
trustToken?: string,
|
|
430
456
|
): string {
|
|
457
|
+
if (
|
|
458
|
+
payload.entries.some(
|
|
459
|
+
(entry) =>
|
|
460
|
+
entry.sourceRelativeOffset !== undefined &&
|
|
461
|
+
!isValidRelativePositionOffset(entry.sourceRelativeOffset),
|
|
462
|
+
)
|
|
463
|
+
) {
|
|
464
|
+
throw new TypeError("Cannot serialize invalid relative position metadata");
|
|
465
|
+
}
|
|
431
466
|
const trustedPrefix = trustToken ? `${trustToken}.` : "";
|
|
432
467
|
const marker = `<!--${CLIPBOARD_MARKER_PREFIX}${trustedPrefix}${encodeClipboardMarkerData(payload)}-->`;
|
|
433
468
|
return `${visibleText}\n${marker}`;
|