@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.
Files changed (62) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  3. package/corpus/templates/analytics/actions/update-dashboard.ts +9 -0
  4. package/corpus/templates/analytics/app/components/auth/SqlQuerySnapshotSessionBridge.tsx +25 -0
  5. package/corpus/templates/analytics/app/components/dashboard/PanelFreshnessClock.tsx +140 -0
  6. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +104 -48
  7. package/corpus/templates/analytics/app/components/dashboard/panel-freshness.ts +171 -0
  8. package/corpus/templates/analytics/app/global.css +59 -0
  9. package/corpus/templates/analytics/app/i18n/en-US.ts +8 -0
  10. package/corpus/templates/analytics/app/lib/cost-tracker.ts +122 -16
  11. package/corpus/templates/analytics/app/lib/query-metrics.ts +50 -13
  12. package/corpus/templates/analytics/app/lib/sql-query-cache.ts +697 -0
  13. package/corpus/templates/analytics/app/lib/sql-query-freshness.ts +85 -0
  14. package/corpus/templates/analytics/app/lib/sql-query-snapshot-session.ts +145 -0
  15. package/corpus/templates/analytics/app/lib/sql-query.ts +366 -36
  16. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +73 -18
  17. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/filter-vars.ts +45 -12
  18. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +5 -0
  19. package/corpus/templates/analytics/app/root.tsx +2 -0
  20. package/corpus/templates/analytics/changelog/2026-10-14-dashboard-charts-now-reappear-instantly-after-a-reload-from-.md +6 -0
  21. package/corpus/templates/analytics/changelog/2026-10-14-dashboard-panels-show-fetch-time-in-a-clock-and-label-only-st.md +6 -0
  22. package/corpus/templates/analytics/changelog/2026-10-15-dashboard-query-costs-and-refresh-confirmations-reflect-actu.md +6 -0
  23. package/corpus/templates/analytics/changelog/2026-10-15-dashboard-results-disappear-when-access-is-withdrawn-and-exp.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-10-16-dashboard-freshness-stays-in-the-title-row-with-compact-upda.md +6 -0
  25. package/corpus/templates/analytics/changelog/2026-10-16-dashboard-update-status-remains-visible-for-sources-without-.md +6 -0
  26. package/corpus/templates/analytics/server/lib/bigquery.ts +35 -4
  27. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +2 -3
  28. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +9 -6
  29. package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +2 -2
  30. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +4 -2
  31. package/corpus/templates/analytics/shared/sql-query-contract.ts +49 -0
  32. package/corpus/templates/assets/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  33. package/corpus/templates/brain/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  34. package/corpus/templates/calendar/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  35. package/corpus/templates/chat/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  36. package/corpus/templates/clips/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  37. package/corpus/templates/content/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  38. package/corpus/templates/crm/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  39. package/corpus/templates/design/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  40. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +24 -0
  41. package/corpus/templates/design/app/components/design/types.ts +1 -0
  42. package/corpus/templates/design/app/lib/design-import.ts +35 -0
  43. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +11 -0
  44. package/corpus/templates/design/app/pages/design-editor/command-types.ts +2 -0
  45. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +3 -0
  46. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +19 -0
  47. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +118 -20
  48. package/corpus/templates/design/app/pages/design-editor/domains/use-editor-layer-actions.ts +15 -3
  49. package/corpus/templates/design/app/pages/design-editor/relative-position-offset.ts +109 -0
  50. package/corpus/templates/design/changelog/2026-10-15-dragged-layers-use-the-final-release-position.md +6 -0
  51. package/corpus/templates/design/changelog/2026-10-15-repeated-pastes-preserve-relative-layer-offsets.md +6 -0
  52. package/corpus/templates/design/changelog/2026-10-15-text-wrapping-hug-widths.md +6 -0
  53. package/corpus/templates/design/shared/code-layer.ts +2 -1
  54. package/corpus/templates/design/shared/relative-position-containing-block.ts +40 -0
  55. package/corpus/templates/dispatch/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  56. package/corpus/templates/forms/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  57. package/corpus/templates/mail/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  58. package/corpus/templates/plan/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  59. package/corpus/templates/slides/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
  60. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +137 -118
  61. package/corpus/templates/slides/changelog/2026-10-16-search-and-preview-reference-decks-before-choosing-one.md +6 -0
  62. 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" || !filter.options?.length) return false;
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 match = /^(\d+)d$/.exec(raw);
184
- if (match) return daysAgo(parseInt(match[1], 10));
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
- const days = /^(\d+)d$/.exec(range);
219
- return days ? daysAgo(Number(days[1])) : daysAgo(30);
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
- getParam(filter.id) || resolveDefault(filter.default, filter.type);
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
- const fallbackStart =
258
- value === "custom" ? "" : dateRangeStart(defaultRange);
259
- const fallbackEnd = value === "custom" ? "" : daysAgo(0);
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 charts now reappear instantly after a reload from a saved copy while fresh data loads, show when each result was fetched, and keep a more accurate estimate of query cost.
@@ -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.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-10-15
4
+ ---
5
+
6
+ Dashboard query costs and refresh confirmations reflect actual execution, and disconnected sources clear saved rows
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-10-15
4
+ ---
5
+
6
+ Dashboard results disappear when access is withdrawn, and Explorer query costs exclude cached scans
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-10-16
4
+ ---
5
+
6
+ Dashboard freshness stays in the title row, with compact update times on wide cards and a clock on narrow cards.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-10-16
4
+ ---
5
+
6
+ Dashboard update status remains visible for sources without fetch-time or cache metadata
@@ -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 raw = (rows[0] as { result: string }).result;
660
- return JSON.parse(raw) as QueryResult;
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
- return result;
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
- ...(result.truncated ? { truncated: true } : {}),
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
  );
@@ -185,6 +185,7 @@ export interface ElementInfo {
185
185
  c: number;
186
186
  d: number;
187
187
  };
188
+ relativeContainingBlockDirection?: "ltr" | "rtl";
188
189
  absoluteSiblingVisualOrigin?: { x: number; y: number };
189
190
  textContent?: string;
190
191
  textContentTruncated?: boolean;
@@ -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}`;