@agent-native/core 0.157.8 → 0.157.9
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/actions/purge-first-party-analytics-postgres.ts +26 -8
- package/corpus/templates/analytics/scripts/first-party-analytics-postgres-retention-dry-run.sql +258 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-purge.ts +59 -27
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +4 -1
- package/corpus/templates/slides/actions/export-pptx.ts +261 -71
- package/corpus/templates/slides/actions/import-file.ts +12 -0
- package/corpus/templates/slides/actions/import-pptx.ts +9 -0
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +45 -5
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +69 -1
- package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +316 -64
- package/corpus/templates/slides/server/lib/source-import.ts +10 -1
- package/dist/agent/harness/migrations.d.ts +4 -0
- package/dist/agent/harness/migrations.js +39 -0
- package/dist/agent/production-agent.d.ts +2 -0
- package/dist/agent/production-agent.js +4 -0
- package/dist/agent/run-loop-with-resume.d.ts +1 -0
- package/dist/agent/run-loop-with-resume.js +45 -30
- package/dist/agent/run-migrations.d.ts +8 -0
- package/dist/agent/run-migrations.js +61 -0
- package/dist/chat-threads/migrations.d.ts +1 -0
- package/dist/chat-threads/migrations.js +1 -0
- package/dist/chat-threads/schema-migrations.d.ts +8 -0
- package/dist/chat-threads/schema-migrations.js +60 -0
- package/dist/client/AssistantChat.js +4 -0
- package/dist/client/chat/message-components.d.ts +2 -0
- package/dist/client/chat/message-components.js +11 -1
- package/dist/client/observability/ThumbsFeedback.js +35 -22
- package/dist/client/observability/useObservability.d.ts +1 -1
- package/dist/client/observability/useObservability.js +6 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/feature-flags/a2a-action-route.js +4 -2
- package/dist/feature-flags/permissions.d.ts +2 -0
- package/dist/feature-flags/permissions.js +6 -1
- package/dist/ingestion/pptx.d.ts +14 -1
- package/dist/ingestion/pptx.js +222 -41
- package/dist/localization/core-messages/ar-SA.js +4 -0
- package/dist/localization/core-messages/de-DE.js +4 -0
- package/dist/localization/core-messages/en-US.d.ts +4 -0
- package/dist/localization/core-messages/en-US.js +4 -0
- package/dist/localization/core-messages/es-ES.js +4 -0
- package/dist/localization/core-messages/fr-FR.js +4 -0
- package/dist/localization/core-messages/hi-IN.js +4 -0
- package/dist/localization/core-messages/ja-JP.js +4 -0
- package/dist/localization/core-messages/ko-KR.js +4 -0
- package/dist/localization/core-messages/pt-BR.js +4 -0
- package/dist/localization/core-messages/zh-CN.js +4 -0
- package/dist/localization/core-messages/zh-TW.js +4 -0
- package/dist/localization/core-messages.d.ts +4 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/feedback.js +40 -16
- package/dist/observability/routes.d.ts +6 -6
- package/dist/observability/routes.js +15 -3
- package/dist/observability/store.js +2 -0
- package/dist/observability/traces.js +5 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +10 -10
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-routes.d.ts +7 -5
- package/dist/server/action-routes.js +9 -4
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/better-auth-instance.js +4 -0
- package/dist/server/realtime-voice.js +2 -1
- package/dist/server/release-migrations.js +16 -0
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/usage/migrations.d.ts +4 -0
- package/dist/usage/migrations.js +45 -0
- package/package.json +3 -3
package/corpus/README.md
CHANGED
|
@@ -88,11 +88,20 @@ export default defineAction({
|
|
|
88
88
|
startReceivedAt,
|
|
89
89
|
startEventDate: startReceivedAt.slice(0, 10),
|
|
90
90
|
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
let postgres: Awaited<
|
|
92
|
+
ReturnType<typeof countFirstPartyAnalyticsPostgresRows>
|
|
93
|
+
> | null = null;
|
|
94
|
+
let postgresError: string | null = null;
|
|
95
|
+
try {
|
|
96
|
+
postgres = await countFirstPartyAnalyticsPostgresRows(
|
|
97
|
+
scope,
|
|
98
|
+
includeLegacyOwnerRows,
|
|
99
|
+
window,
|
|
100
|
+
);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (!dryRun) throw error;
|
|
103
|
+
postgresError = error instanceof Error ? error.message : String(error);
|
|
104
|
+
}
|
|
96
105
|
let bigQuery: {
|
|
97
106
|
eventCount: number;
|
|
98
107
|
dailyRollupRows: number;
|
|
@@ -115,12 +124,15 @@ export default defineAction({
|
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
|
|
118
|
-
const uncopiedEventRows =
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
const uncopiedEventRows =
|
|
128
|
+
bigQuery && postgres
|
|
129
|
+
? Math.max(0, postgres.eventRows - bigQuery.eventCount)
|
|
130
|
+
: null;
|
|
121
131
|
const safeToDelete =
|
|
122
132
|
backend.sink === "bigquery" &&
|
|
123
133
|
backend.backfillCompleted === true &&
|
|
134
|
+
postgresError === null &&
|
|
135
|
+
postgres !== null &&
|
|
124
136
|
bigQueryError === null &&
|
|
125
137
|
bigQuery !== null &&
|
|
126
138
|
uncopiedEventRows === 0;
|
|
@@ -136,6 +148,11 @@ export default defineAction({
|
|
|
136
148
|
"Postgres purge is blocked until the durable BigQuery backfill reports completed.",
|
|
137
149
|
);
|
|
138
150
|
}
|
|
151
|
+
if (postgresError || !postgres) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Postgres purge is blocked because the scoped Postgres inventory could not be verified: ${postgresError ?? "unknown Postgres state"}`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
139
156
|
if (bigQueryError || !bigQuery) {
|
|
140
157
|
throw new Error(
|
|
141
158
|
`Postgres purge is blocked because BigQuery readiness could not be verified: ${bigQueryError ?? "unknown warehouse state"}`,
|
|
@@ -179,6 +196,7 @@ export default defineAction({
|
|
|
179
196
|
sink: backend.sink,
|
|
180
197
|
backfillCompleted: backend.backfillCompleted === true,
|
|
181
198
|
postgres,
|
|
199
|
+
postgresError,
|
|
182
200
|
bigQuery,
|
|
183
201
|
bigQueryError,
|
|
184
202
|
uncopiedEventRows,
|
package/corpus/templates/analytics/scripts/first-party-analytics-postgres-retention-dry-run.sql
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
-- FIRST-PARTY ANALYTICS POSTGRES RETENTION PREVIEW - READ ONLY
|
|
2
|
+
--
|
|
3
|
+
-- This file intentionally contains no INSERT, UPDATE, DELETE, TRUNCATE, or DDL.
|
|
4
|
+
-- It reports only rows in the explicitly resolved Builder.io organization and
|
|
5
|
+
-- the exact 60-day window that was copied to BigQuery by the migration.
|
|
6
|
+
--
|
|
7
|
+
-- The candidate set excludes http.response because that event class was
|
|
8
|
+
-- intentionally omitted from the BigQuery backfill. Rows older than the
|
|
9
|
+
-- lookback window and legacy owner-only rows are reported separately and are
|
|
10
|
+
-- never included in the candidate count. Session replay, exception issues,
|
|
11
|
+
-- public-key metadata, rollups, alerts, and pressure data are reported as
|
|
12
|
+
-- preserved SQL rows; they are not deletion candidates.
|
|
13
|
+
|
|
14
|
+
WITH params AS (
|
|
15
|
+
SELECT
|
|
16
|
+
'PlRt3bfcpJNnOyF_Wfgsh'::text AS org_id,
|
|
17
|
+
'steve@builder.io'::text AS owner_email,
|
|
18
|
+
'2026-06-10T18:50:43.370Z'::text AS lookback_start,
|
|
19
|
+
'2026-08-09T19:11:44.834Z'::text AS cutoff,
|
|
20
|
+
'http.response'::text AS excluded_event_name
|
|
21
|
+
),
|
|
22
|
+
org_window AS (
|
|
23
|
+
SELECT e.id, e.event_name, e.received_at
|
|
24
|
+
FROM analytics_events AS e
|
|
25
|
+
CROSS JOIN params AS p
|
|
26
|
+
WHERE e.org_id = p.org_id
|
|
27
|
+
AND e.received_at >= p.lookback_start
|
|
28
|
+
AND e.received_at < p.cutoff
|
|
29
|
+
),
|
|
30
|
+
org_older AS (
|
|
31
|
+
SELECT e.received_at
|
|
32
|
+
FROM analytics_events AS e
|
|
33
|
+
CROSS JOIN params AS p
|
|
34
|
+
WHERE e.org_id = p.org_id
|
|
35
|
+
AND e.received_at < p.lookback_start
|
|
36
|
+
),
|
|
37
|
+
legacy_window AS (
|
|
38
|
+
SELECT e.received_at
|
|
39
|
+
FROM analytics_events AS e
|
|
40
|
+
CROSS JOIN params AS p
|
|
41
|
+
WHERE e.org_id IS NULL
|
|
42
|
+
AND e.owner_email = p.owner_email
|
|
43
|
+
AND e.received_at >= p.lookback_start
|
|
44
|
+
AND e.received_at < p.cutoff
|
|
45
|
+
),
|
|
46
|
+
candidate AS (
|
|
47
|
+
SELECT w.id, w.event_name, w.received_at
|
|
48
|
+
FROM org_window AS w
|
|
49
|
+
CROSS JOIN params AS p
|
|
50
|
+
WHERE w.event_name IS DISTINCT FROM p.excluded_event_name
|
|
51
|
+
),
|
|
52
|
+
metrics AS (
|
|
53
|
+
SELECT
|
|
54
|
+
'events'::text AS section,
|
|
55
|
+
'candidate_non_http_response'::text AS metric,
|
|
56
|
+
COUNT(*) AS row_count,
|
|
57
|
+
MIN(received_at) AS first_seen,
|
|
58
|
+
MAX(received_at) AS last_seen,
|
|
59
|
+
'Only rows in the copied 60-day org window; not a delete.'::text AS notes
|
|
60
|
+
FROM candidate
|
|
61
|
+
|
|
62
|
+
UNION ALL
|
|
63
|
+
SELECT
|
|
64
|
+
'events',
|
|
65
|
+
'excluded_http_response',
|
|
66
|
+
COUNT(*),
|
|
67
|
+
MIN(received_at),
|
|
68
|
+
MAX(received_at),
|
|
69
|
+
'Excluded from BigQuery backfill; do not delete without a separate decision.'
|
|
70
|
+
FROM org_window AS w
|
|
71
|
+
CROSS JOIN params AS p
|
|
72
|
+
WHERE w.event_name = p.excluded_event_name
|
|
73
|
+
|
|
74
|
+
UNION ALL
|
|
75
|
+
SELECT
|
|
76
|
+
'events',
|
|
77
|
+
'older_than_lookback',
|
|
78
|
+
COUNT(*),
|
|
79
|
+
MIN(received_at),
|
|
80
|
+
MAX(received_at),
|
|
81
|
+
'Not copied by the 60-day migration; not a delete candidate.'
|
|
82
|
+
FROM org_older
|
|
83
|
+
|
|
84
|
+
UNION ALL
|
|
85
|
+
SELECT
|
|
86
|
+
'events',
|
|
87
|
+
'legacy_owner_only_in_window',
|
|
88
|
+
COUNT(*),
|
|
89
|
+
MIN(received_at),
|
|
90
|
+
MAX(received_at),
|
|
91
|
+
'org_id IS NULL branch; migration checkpoint copied zero legacy rows.'
|
|
92
|
+
FROM legacy_window
|
|
93
|
+
|
|
94
|
+
UNION ALL
|
|
95
|
+
SELECT
|
|
96
|
+
'event_names',
|
|
97
|
+
event_name,
|
|
98
|
+
COUNT(*),
|
|
99
|
+
MIN(received_at),
|
|
100
|
+
MAX(received_at),
|
|
101
|
+
'Candidate rows grouped by event name.'
|
|
102
|
+
FROM candidate
|
|
103
|
+
GROUP BY event_name
|
|
104
|
+
|
|
105
|
+
UNION ALL
|
|
106
|
+
SELECT
|
|
107
|
+
'preserved_sql',
|
|
108
|
+
'analytics_event_daily_rollups',
|
|
109
|
+
COUNT(*),
|
|
110
|
+
NULL,
|
|
111
|
+
NULL,
|
|
112
|
+
'Preserved derived event counts.'
|
|
113
|
+
FROM analytics_event_daily_rollups AS r
|
|
114
|
+
CROSS JOIN params AS p
|
|
115
|
+
WHERE r.org_id = p.org_id
|
|
116
|
+
|
|
117
|
+
UNION ALL
|
|
118
|
+
SELECT
|
|
119
|
+
'preserved_sql',
|
|
120
|
+
'analytics_user_days',
|
|
121
|
+
COUNT(*),
|
|
122
|
+
NULL,
|
|
123
|
+
NULL,
|
|
124
|
+
'Preserved active-user/retention rows.'
|
|
125
|
+
FROM analytics_user_days AS u
|
|
126
|
+
CROSS JOIN params AS p
|
|
127
|
+
WHERE u.org_id = p.org_id
|
|
128
|
+
|
|
129
|
+
UNION ALL
|
|
130
|
+
SELECT
|
|
131
|
+
'preserved_sql',
|
|
132
|
+
'analytics_event_volume_usage',
|
|
133
|
+
COUNT(*),
|
|
134
|
+
NULL,
|
|
135
|
+
NULL,
|
|
136
|
+
'Preserved volume-cap state.'
|
|
137
|
+
FROM analytics_event_volume_usage AS v
|
|
138
|
+
CROSS JOIN params AS p
|
|
139
|
+
WHERE v.org_id = p.org_id
|
|
140
|
+
|
|
141
|
+
UNION ALL
|
|
142
|
+
SELECT
|
|
143
|
+
'preserved_sql',
|
|
144
|
+
'analytics_query_pressure_daily',
|
|
145
|
+
COUNT(*),
|
|
146
|
+
NULL,
|
|
147
|
+
NULL,
|
|
148
|
+
'Preserved query-pressure diagnostics.'
|
|
149
|
+
FROM analytics_query_pressure_daily AS q
|
|
150
|
+
CROSS JOIN params AS p
|
|
151
|
+
WHERE q.org_id = p.org_id
|
|
152
|
+
|
|
153
|
+
UNION ALL
|
|
154
|
+
SELECT
|
|
155
|
+
'preserved_sql',
|
|
156
|
+
'analytics_alert_rules',
|
|
157
|
+
COUNT(*),
|
|
158
|
+
NULL,
|
|
159
|
+
NULL,
|
|
160
|
+
'Preserved alert definitions.'
|
|
161
|
+
FROM analytics_alert_rules AS a
|
|
162
|
+
CROSS JOIN params AS p
|
|
163
|
+
WHERE a.org_id = p.org_id
|
|
164
|
+
|
|
165
|
+
UNION ALL
|
|
166
|
+
SELECT
|
|
167
|
+
'preserved_sql',
|
|
168
|
+
'analytics_alert_incidents',
|
|
169
|
+
COUNT(*),
|
|
170
|
+
NULL,
|
|
171
|
+
NULL,
|
|
172
|
+
'Preserved alert history.'
|
|
173
|
+
FROM analytics_alert_incidents AS i
|
|
174
|
+
CROSS JOIN params AS p
|
|
175
|
+
WHERE i.org_id = p.org_id
|
|
176
|
+
|
|
177
|
+
UNION ALL
|
|
178
|
+
SELECT
|
|
179
|
+
'preserved_sql',
|
|
180
|
+
'session_recordings',
|
|
181
|
+
COUNT(*),
|
|
182
|
+
MIN(started_at),
|
|
183
|
+
MAX(COALESCE(ended_at, started_at)),
|
|
184
|
+
'Session replay summaries; never delete with event rows.'
|
|
185
|
+
FROM session_recordings AS s
|
|
186
|
+
CROSS JOIN params AS p
|
|
187
|
+
WHERE s.org_id = p.org_id
|
|
188
|
+
|
|
189
|
+
UNION ALL
|
|
190
|
+
SELECT
|
|
191
|
+
'preserved_sql',
|
|
192
|
+
'session_replay_chunks',
|
|
193
|
+
COUNT(*),
|
|
194
|
+
MIN(created_at),
|
|
195
|
+
MAX(created_at),
|
|
196
|
+
'Session replay payload references; never delete with event rows.'
|
|
197
|
+
FROM session_replay_chunks AS c
|
|
198
|
+
CROSS JOIN params AS p
|
|
199
|
+
WHERE c.org_id = p.org_id
|
|
200
|
+
|
|
201
|
+
UNION ALL
|
|
202
|
+
SELECT
|
|
203
|
+
'preserved_sql',
|
|
204
|
+
'session_replay_ingests',
|
|
205
|
+
COUNT(*),
|
|
206
|
+
MIN(created_at),
|
|
207
|
+
MAX(created_at),
|
|
208
|
+
'Session replay ingest audit rows; never delete with event rows.'
|
|
209
|
+
FROM session_replay_ingests AS g
|
|
210
|
+
CROSS JOIN params AS p
|
|
211
|
+
WHERE g.org_id = p.org_id
|
|
212
|
+
|
|
213
|
+
UNION ALL
|
|
214
|
+
SELECT
|
|
215
|
+
'preserved_sql',
|
|
216
|
+
'error_issues',
|
|
217
|
+
COUNT(*),
|
|
218
|
+
MIN(first_seen_at),
|
|
219
|
+
MAX(last_seen_at),
|
|
220
|
+
'Grouped exception issues; preserved separately from analytics_events.'
|
|
221
|
+
FROM error_issues AS x
|
|
222
|
+
CROSS JOIN params AS p
|
|
223
|
+
WHERE x.org_id = p.org_id
|
|
224
|
+
|
|
225
|
+
UNION ALL
|
|
226
|
+
SELECT
|
|
227
|
+
'preserved_sql',
|
|
228
|
+
'error_events',
|
|
229
|
+
COUNT(*),
|
|
230
|
+
MIN(occurred_at),
|
|
231
|
+
MAX(occurred_at),
|
|
232
|
+
'Exception occurrences; preserved separately from analytics_events.'
|
|
233
|
+
FROM error_events AS x
|
|
234
|
+
CROSS JOIN params AS p
|
|
235
|
+
WHERE x.org_id = p.org_id
|
|
236
|
+
|
|
237
|
+
UNION ALL
|
|
238
|
+
SELECT
|
|
239
|
+
'preserved_sql',
|
|
240
|
+
'analytics_public_keys',
|
|
241
|
+
COUNT(*),
|
|
242
|
+
MIN(created_at),
|
|
243
|
+
MAX(created_at),
|
|
244
|
+
'Public-key metadata; preserved separately from analytics_events.'
|
|
245
|
+
FROM analytics_public_keys AS k
|
|
246
|
+
CROSS JOIN params AS p
|
|
247
|
+
WHERE k.org_id = p.org_id
|
|
248
|
+
)
|
|
249
|
+
SELECT section, metric, row_count, first_seen, last_seen, notes
|
|
250
|
+
FROM metrics
|
|
251
|
+
ORDER BY
|
|
252
|
+
CASE section
|
|
253
|
+
WHEN 'events' THEN 1
|
|
254
|
+
WHEN 'event_names' THEN 2
|
|
255
|
+
ELSE 3
|
|
256
|
+
END,
|
|
257
|
+
row_count DESC,
|
|
258
|
+
metric;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getDbExec } from "@agent-native/core/db";
|
|
2
|
+
import { and, eq, gte, isNull, or } from "drizzle-orm";
|
|
2
3
|
|
|
3
4
|
import { getDb, schema } from "../db/index.js";
|
|
4
5
|
|
|
@@ -46,13 +47,47 @@ function windowPredicate(
|
|
|
46
47
|
: and(predicate, gte(table.eventDate, window.startEventDate));
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
type CountTable =
|
|
51
|
+
| "analytics_events"
|
|
52
|
+
| "analytics_event_daily_rollups"
|
|
53
|
+
| "analytics_user_days";
|
|
54
|
+
|
|
55
|
+
type CountTimeColumn = "received_at" | "event_date";
|
|
56
|
+
|
|
57
|
+
async function countScopedRows(
|
|
58
|
+
table: CountTable,
|
|
59
|
+
timeColumn: CountTimeColumn,
|
|
60
|
+
scope: FirstPartyAnalyticsPurgeScope,
|
|
61
|
+
includeLegacyOwnerRows: boolean,
|
|
62
|
+
window: FirstPartyAnalyticsPurgeWindow,
|
|
63
|
+
): Promise<number> {
|
|
64
|
+
const scopeSql = includeLegacyOwnerRows
|
|
65
|
+
? "(org_id = ? OR (org_id IS NULL AND owner_email = ?))"
|
|
66
|
+
: "org_id = ?";
|
|
67
|
+
const args: unknown[] = includeLegacyOwnerRows
|
|
68
|
+
? [scope.orgId, scope.userEmail]
|
|
69
|
+
: [scope.orgId];
|
|
70
|
+
args.push(
|
|
71
|
+
timeColumn === "received_at"
|
|
72
|
+
? window.startReceivedAt
|
|
73
|
+
: window.startEventDate,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const { rows } = await getDbExec().execute({
|
|
77
|
+
sql: `SELECT COUNT(*) AS row_count
|
|
78
|
+
FROM ${table}
|
|
79
|
+
WHERE ${scopeSql}
|
|
80
|
+
AND ${timeColumn} >= ?`,
|
|
81
|
+
args,
|
|
82
|
+
timeoutMs: 5_000,
|
|
83
|
+
maxAttempts: 1,
|
|
84
|
+
});
|
|
85
|
+
const rawCount = (rows[0] as { row_count?: unknown } | undefined)?.row_count;
|
|
86
|
+
const value = Number(rawCount);
|
|
87
|
+
if (!Number.isFinite(value)) {
|
|
88
|
+
throw new Error(`Postgres count returned an invalid value for ${table}`);
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
56
91
|
}
|
|
57
92
|
|
|
58
93
|
export async function countFirstPartyAnalyticsPostgresRows(
|
|
@@ -60,31 +95,28 @@ export async function countFirstPartyAnalyticsPostgresRows(
|
|
|
60
95
|
includeLegacyOwnerRows: boolean,
|
|
61
96
|
window: FirstPartyAnalyticsPurgeWindow,
|
|
62
97
|
): Promise<FirstPartyAnalyticsPostgresPurgeCounts> {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
98
|
+
const [eventRows, dailyRollupRows, userDayRows] = await Promise.all([
|
|
99
|
+
countScopedRows(
|
|
100
|
+
"analytics_events",
|
|
101
|
+
"received_at",
|
|
102
|
+
scope,
|
|
103
|
+
includeLegacyOwnerRows,
|
|
67
104
|
window,
|
|
68
105
|
),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
includeLegacyOwnerRows,
|
|
75
|
-
),
|
|
106
|
+
countScopedRows(
|
|
107
|
+
"analytics_event_daily_rollups",
|
|
108
|
+
"event_date",
|
|
109
|
+
scope,
|
|
110
|
+
includeLegacyOwnerRows,
|
|
76
111
|
window,
|
|
77
112
|
),
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
113
|
+
countScopedRows(
|
|
114
|
+
"analytics_user_days",
|
|
115
|
+
"event_date",
|
|
116
|
+
scope,
|
|
117
|
+
includeLegacyOwnerRows,
|
|
81
118
|
window,
|
|
82
119
|
),
|
|
83
|
-
];
|
|
84
|
-
const [eventRows, dailyRollupRows, userDayRows] = await Promise.all([
|
|
85
|
-
countScopedRows(schema.analyticsEvents, predicates[0]),
|
|
86
|
-
countScopedRows(schema.analyticsEventDailyRollups, predicates[1]),
|
|
87
|
-
countScopedRows(schema.analyticsUserDays, predicates[2]),
|
|
88
120
|
]);
|
|
89
121
|
return { eventRows, dailyRollupRows, userDayRows };
|
|
90
122
|
}
|
|
@@ -68,6 +68,7 @@ export function validateWorkspaceFeatureFlagMutation(
|
|
|
68
68
|
expected: {
|
|
69
69
|
key: string;
|
|
70
70
|
orgDomain: string;
|
|
71
|
+
allowExplicitNoOrgTarget?: boolean;
|
|
71
72
|
rules?: Record<string, unknown>;
|
|
72
73
|
enabledForEmail?: string;
|
|
73
74
|
},
|
|
@@ -82,7 +83,8 @@ export function validateWorkspaceFeatureFlagMutation(
|
|
|
82
83
|
!Array.isArray(payload.rules) &&
|
|
83
84
|
!!payload.scope &&
|
|
84
85
|
typeof payload.scope === "object" &&
|
|
85
|
-
payload.scope.orgDomain === expected.orgDomain
|
|
86
|
+
(payload.scope.orgDomain === expected.orgDomain ||
|
|
87
|
+
(expected.allowExplicitNoOrgTarget && payload.scope.orgDomain === null));
|
|
86
88
|
if (!valid)
|
|
87
89
|
throw new Error(
|
|
88
90
|
"The target app returned an unsupported or unverified feature flag mutation response.",
|
|
@@ -360,6 +362,7 @@ export async function setWorkspaceFeatureFlag(
|
|
|
360
362
|
return validateWorkspaceFeatureFlagMutation(result.body, {
|
|
361
363
|
key: input.key,
|
|
362
364
|
orgDomain,
|
|
365
|
+
allowExplicitNoOrgTarget: true,
|
|
363
366
|
...(input.operation === "replace-rules" && input.rules
|
|
364
367
|
? {
|
|
365
368
|
rules: {
|