@agent-native/core 0.208.0 → 0.209.0-nightly-20261014070126

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 (74) hide show
  1. package/agent-native.eject.json +1 -0
  2. package/dist/agent/approval-key.d.ts +2 -0
  3. package/dist/agent/approval-key.js +12 -0
  4. package/dist/agent/context-xray/tokenize.js +12 -3
  5. package/dist/agent/engine/translate-anthropic.js +4 -0
  6. package/dist/agent/engine/types.d.ts +2 -0
  7. package/dist/agent/production-agent.d.ts +20 -5
  8. package/dist/agent/production-agent.js +227 -34
  9. package/dist/agent/run-manager.js +57 -11
  10. package/dist/agent/run-store.d.ts +10 -0
  11. package/dist/agent/run-store.js +49 -4
  12. package/dist/agent/thread-data-builder.d.ts +2 -0
  13. package/dist/agent/thread-data-builder.js +288 -14
  14. package/dist/agent/tool-approval-store.d.ts +3 -1
  15. package/dist/agent/tool-approval-store.js +26 -12
  16. package/dist/agent/tool-call-journal.d.ts +1 -1
  17. package/dist/agent/tool-call-journal.js +5 -3
  18. package/dist/agent/types.d.ts +7 -0
  19. package/dist/client/chat/agentkit-agent-native.js +18 -0
  20. package/dist/client/chat/agentkit-protocol.js +56 -5
  21. package/dist/client/chat/runtime.d.ts +10 -0
  22. package/dist/client/chat/runtime.js +257 -26
  23. package/dist/client/sse-event-processor.d.ts +22 -0
  24. package/dist/client/sse-event-processor.js +91 -11
  25. package/dist/collab/struct-routes.d.ts +1 -1
  26. package/dist/connections/catalog.d.ts +24 -1
  27. package/dist/connections/catalog.js +12 -0
  28. package/dist/data-programs/schema.d.ts +1 -0
  29. package/dist/data-programs/schema.js +3 -0
  30. package/dist/data-programs/store.js +2 -1
  31. package/dist/deploy/build.js +16 -14
  32. package/dist/eject/workspace-connections.js +1 -0
  33. package/dist/extensions/fetch-tool.js +114 -23
  34. package/dist/extensions/schema.d.ts +1 -0
  35. package/dist/extensions/schema.js +3 -0
  36. package/dist/extensions/store.js +2 -1
  37. package/dist/extensions/web-content.d.ts +5 -1
  38. package/dist/extensions/web-content.js +24 -6
  39. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  40. package/dist/notifications/routes.d.ts +1 -1
  41. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  42. package/dist/provider-api/actions/provider-api.d.ts +9 -9
  43. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  44. package/dist/provider-api/index.d.ts +2 -0
  45. package/dist/provider-api/index.js +95 -12
  46. package/dist/resources/handlers.d.ts +1 -1
  47. package/dist/server/agent-engine-default-model-route.d.ts +2 -2
  48. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  49. package/dist/server/auth.js +1 -0
  50. package/dist/server/core-routes-plugin.js +1 -0
  51. package/dist/server/index.d.ts +2 -1
  52. package/dist/server/index.js +2 -1
  53. package/dist/server/realtime-token.d.ts +1 -1
  54. package/dist/server/transcribe-voice.d.ts +1 -1
  55. package/dist/server/workspace-provider-oauth.d.ts +1 -1
  56. package/dist/server/workspace-provider-oauth.js +2 -0
  57. package/dist/shared/context-status.js +1 -1
  58. package/dist/shared/optional-peer-ssr.d.ts +2 -0
  59. package/dist/shared/optional-peer-ssr.js +123 -0
  60. package/dist/shared/tool-inputs.d.ts +2 -0
  61. package/dist/shared/tool-inputs.js +56 -0
  62. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  63. package/dist/tracking/index.d.ts +1 -0
  64. package/dist/tracking/index.js +1 -0
  65. package/dist/vite/client.js +46 -3
  66. package/dist/workspace-connections/store.d.ts +3 -1
  67. package/dist/workspace-connections/store.js +18 -8
  68. package/dist/workspace-files/constants.d.ts +3 -0
  69. package/dist/workspace-files/constants.js +3 -0
  70. package/dist/workspace-files/store.d.ts +2 -3
  71. package/dist/workspace-files/store.js +2 -3
  72. package/docs/content/automations.mdx +19 -13
  73. package/package.json +3 -3
  74. package/src/eject/workspace-connections.ts +1 -0
@@ -24,6 +24,9 @@ export type ContentPart = {
24
24
  args: Record<string, string>;
25
25
  result?: string;
26
26
  isError?: boolean;
27
+ approvalPause?: true;
28
+ approvalPauseCandidate?: true;
29
+ approvalResumeCandidate?: true;
27
30
  /**
28
31
  * Set when the stream ended while this tool was still in flight. We know
29
32
  * it started and NOT whether its side effect landed, so it is deliberately
@@ -90,6 +93,7 @@ export interface SSEEvent {
90
93
  result?: string;
91
94
  isError?: boolean;
92
95
  completedSideEffect?: boolean;
96
+ approvalPause?: boolean;
93
97
  artifacts?: ArtifactReceipt[];
94
98
  mcpApp?: AgentMcpAppPayload;
95
99
  chatUI?: ActionChatUIConfig;
@@ -293,6 +297,24 @@ export type PreparingActionState = {
293
297
  entries?: Map<string, PreparingActionEntry>;
294
298
  toolEntries?: Map<string, PreparingActionEntry>;
295
299
  };
300
+ /**
301
+ * Locate the tool call an `approval_required` event refers to.
302
+ *
303
+ * Stricter than `findPendingToolCallIndex`: when the server supplies a call id
304
+ * we never fall back to "newest pending call with this name". A paused
305
+ * `tool_done` resolves the call right after the gate fires, so a replayed or
306
+ * reordered approval would otherwise miss on id and silently attach this call's
307
+ * approvalKey to a *different* in-flight call of the same action — putting the
308
+ * wrong key behind a visible Approve button. A resumed paused call is eligible
309
+ * only after its exact `tool_start` marks it as an approval-resume candidate.
310
+ *
311
+ * Without an event id, the required input must identify one pending call or
312
+ * explicitly resumed pause by itself. A name-only match can attach a stale
313
+ * approval to a different same-name call. With an event id, the only tolerated
314
+ * fallback is a single unambiguous reader-local (`tc_N`) placeholder, which is
315
+ * how a call looks when an older server omitted the id on `tool_start`.
316
+ */
317
+ export declare function findApprovalToolCallIndex(content: readonly ContentPart[], toolName: string, toolCallId?: string, approvalInput?: unknown): number;
296
318
  export declare function appendMissingFinalResponseWarning(content: ContentPart[], completedToolNames?: Iterable<string>): {
297
319
  message: string;
298
320
  errorCode: string;
@@ -1,6 +1,7 @@
1
1
  import { LLM_MISSING_CREDENTIALS_ERROR_CODE, LLM_MISSING_CREDENTIALS_MESSAGE, } from "../agent/engine/credential-errors.js";
2
2
  import { BUILDER_GATEWAY_INTERNAL_ERROR_CODE, PROVIDER_TRANSIENT_REJECTION_ERROR_CODE, } from "../agent/engine/error-detail.js";
3
3
  import { normalizeConnectRequiredResult } from "../shared/connect-required.js";
4
+ import { toolInputsMatch } from "../shared/tool-inputs.js";
4
5
  import { emitChatFirstOpenApp } from "./chat-first-state.js";
5
6
  import { formatChatErrorText, normalizeChatError } from "./error-format.js";
6
7
  import { humanizeToolLabelText, humanizeToolName, isToolCallActive, runningToolLabel, } from "./tool-display.js";
@@ -274,25 +275,60 @@ function findPendingToolCallIndexById(content, toolCallId) {
274
275
  * `tool_done` resolves the call right after the gate fires, so a replayed or
275
276
  * reordered approval would otherwise miss on id and silently attach this call's
276
277
  * approvalKey to a *different* in-flight call of the same action — putting the
277
- * wrong key behind a visible Approve button.
278
+ * wrong key behind a visible Approve button. A resumed paused call is eligible
279
+ * only after its exact `tool_start` marks it as an approval-resume candidate.
278
280
  *
279
- * The only tolerated fallback mirrors `findPendingActivityToolCallIndex`: a
280
- * single unambiguous reader-local (`tc_N`) placeholder, which is how a call
281
- * looks when an older server omitted the id on `tool_start`.
281
+ * Without an event id, the required input must identify one pending call or
282
+ * explicitly resumed pause by itself. A name-only match can attach a stale
283
+ * approval to a different same-name call. With an event id, the only tolerated
284
+ * fallback is a single unambiguous reader-local (`tc_N`) placeholder, which is
285
+ * how a call looks when an older server omitted the id on `tool_start`.
282
286
  */
283
- function findApprovalToolCallIndex(content, toolName, toolCallId) {
287
+ export function findApprovalToolCallIndex(content, toolName, toolCallId, approvalInput) {
284
288
  if (!toolCallId) {
285
- return findPendingToolCallIndex(content, toolName);
289
+ if (!approvalInput)
290
+ return -1;
291
+ const matchingInputCandidates = [];
292
+ for (let i = 0; i < content.length; i += 1) {
293
+ const part = content[i];
294
+ if (part.type === "tool-call" &&
295
+ part.toolName === toolName &&
296
+ (part.result === undefined ||
297
+ (part.approvalPause === true &&
298
+ part.approvalResumeCandidate === true)) &&
299
+ toolInputsMatch(part.args, approvalInput)) {
300
+ matchingInputCandidates.push(i);
301
+ }
302
+ }
303
+ return matchingInputCandidates.length === 1
304
+ ? matchingInputCandidates[0]
305
+ : -1;
286
306
  }
287
307
  const exactIndex = findPendingToolCallIndexById(content, toolCallId);
288
308
  if (exactIndex >= 0)
289
309
  return exactIndex;
310
+ const resumedCandidates = [];
311
+ for (let i = 0; i < content.length; i += 1) {
312
+ const part = content[i];
313
+ if (part.type === "tool-call" &&
314
+ part.toolCallId === toolCallId &&
315
+ part.toolName === toolName &&
316
+ part.result !== undefined &&
317
+ part.approvalPause === true &&
318
+ part.approvalResumeCandidate === true &&
319
+ (approvalInput === undefined || toolInputsMatch(part.args, approvalInput))) {
320
+ resumedCandidates.push(i);
321
+ }
322
+ }
323
+ if (resumedCandidates.length === 1)
324
+ return resumedCandidates[0];
290
325
  const readerLocalCandidates = [];
291
326
  for (let i = 0; i < content.length; i += 1) {
292
327
  const part = content[i];
293
328
  if (part.type === "tool-call" &&
294
329
  part.toolName === toolName &&
295
330
  part.result === undefined &&
331
+ toolInputsMatch(part.args, approvalInput) &&
296
332
  /^tc_\d+$/.test(part.toolCallId)) {
297
333
  readerLocalCandidates.push(i);
298
334
  }
@@ -1268,7 +1304,15 @@ export function processEvent(ev, content, toolCallCounter, tabId, state, context
1268
1304
  if (ev.type === "tool_start") {
1269
1305
  const args = (ev.input ?? {});
1270
1306
  const tool = ev.tool ?? "unknown";
1271
- if (findCompletedToolCallIndex(content, ev.id) >= 0) {
1307
+ const completedIndex = findCompletedToolCallIndex(content, ev.id);
1308
+ if (completedIndex >= 0) {
1309
+ const completedPart = content[completedIndex];
1310
+ if (completedPart?.type === "tool-call") {
1311
+ if (completedPart.approvalPause === true) {
1312
+ completedPart.approvalResumeCandidate = true;
1313
+ }
1314
+ delete completedPart.approvalPauseCandidate;
1315
+ }
1272
1316
  return { action: "continue" };
1273
1317
  }
1274
1318
  if (typeof window !== "undefined") {
@@ -1339,7 +1383,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state, context
1339
1383
  // `toolCallId` is the model-side id in the `approval_required` contract;
1340
1384
  // `id` is only carried by older frames. Same precedence as the runtime
1341
1385
  // path so both processors resolve an event to the same call.
1342
- const idx = findApprovalToolCallIndex(content, approvalTool, ev.toolCallId ?? ev.id);
1386
+ const idx = findApprovalToolCallIndex(content, approvalTool, ev.toolCallId ?? ev.id, ev.input);
1343
1387
  if (idx >= 0) {
1344
1388
  const part = content[idx];
1345
1389
  if (part.type === "tool-call") {
@@ -1350,6 +1394,8 @@ export function processEvent(ev, content, toolCallCounter, tabId, state, context
1350
1394
  ? { allowPersistentApproval: false }
1351
1395
  : {}),
1352
1396
  };
1397
+ part.approvalPauseCandidate = true;
1398
+ delete part.approvalResumeCandidate;
1353
1399
  }
1354
1400
  }
1355
1401
  }
@@ -1363,8 +1409,29 @@ export function processEvent(ev, content, toolCallCounter, tabId, state, context
1363
1409
  // so a tool_done frame with an undefined tool name still matches its
1364
1410
  // pending tool-call entry instead of leaving it forever unresolved.
1365
1411
  const doneTool = ev.tool ?? "unknown";
1366
- if (findCompletedToolCallIndex(content, ev.id) >= 0) {
1367
- return { action: "continue" };
1412
+ const completedIndex = findCompletedToolCallIndex(content, ev.id);
1413
+ let approvedResumeIndex = -1;
1414
+ if (completedIndex >= 0) {
1415
+ const completedPart = content[completedIndex];
1416
+ if (completedPart?.type !== "tool-call") {
1417
+ return { action: "continue" };
1418
+ }
1419
+ const legacyApprovalPause = ev.approvalPause === undefined &&
1420
+ completedPart.approvalPauseCandidate === true;
1421
+ const renewedApprovalPause = ev.approvalPause === true &&
1422
+ completedPart.approvalPause === true &&
1423
+ completedPart.approvalPauseCandidate === true;
1424
+ if ((ev.approvalPause === true && completedPart.approvalPause !== true) ||
1425
+ legacyApprovalPause ||
1426
+ renewedApprovalPause ||
1427
+ (completedPart.approvalPause === true &&
1428
+ completedPart.approvalResumeCandidate === true &&
1429
+ ev.approvalPause !== true)) {
1430
+ approvedResumeIndex = completedIndex;
1431
+ }
1432
+ else {
1433
+ return { action: "continue" };
1434
+ }
1368
1435
  }
1369
1436
  emitFirstPartyOpenAppHandoff(ev);
1370
1437
  if (typeof window !== "undefined") {
@@ -1385,11 +1452,24 @@ export function processEvent(ev, content, toolCallCounter, tabId, state, context
1385
1452
  dispatchActivityClear(tabId);
1386
1453
  // Use id-based lookup when available so parallel same-name tool calls
1387
1454
  // get their results correctly assigned; fall back to name-matching.
1388
- const doneIdx = findPendingToolCallIndex(content, doneTool, ev.id);
1455
+ const doneIdx = approvedResumeIndex >= 0
1456
+ ? approvedResumeIndex
1457
+ : findPendingToolCallIndex(content, doneTool, ev.id);
1389
1458
  if (doneIdx >= 0) {
1390
1459
  const part = content[doneIdx];
1391
1460
  if (part.type === "tool-call") {
1392
1461
  part.result = ev.result ?? "";
1462
+ const legacyApprovalPause = ev.approvalPause === undefined &&
1463
+ part.approvalPauseCandidate === true;
1464
+ if (ev.approvalPause === true || legacyApprovalPause) {
1465
+ part.approvalPause = true;
1466
+ }
1467
+ else {
1468
+ delete part.approvalPause;
1469
+ delete part.approval;
1470
+ }
1471
+ delete part.approvalPauseCandidate;
1472
+ delete part.approvalResumeCandidate;
1393
1473
  if (ev.isError !== undefined)
1394
1474
  part.isError = ev.isError;
1395
1475
  if (ev.completedSideEffect !== undefined) {
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- ok?: undefined;
3
2
  error: string;
3
+ ok?: undefined;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -1,6 +1,6 @@
1
1
  export type WorkspaceConnectionCapability = "search" | "import" | "messages" | "meetings" | "crm" | "code" | "docs";
2
2
  export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "crm" | "design" | "dispatch" | "factory" | "forms" | "mail" | "slides";
3
- export type WorkspaceConnectionProviderId = "slack" | "github" | "figma" | "notion" | "gmail" | "google_calendar" | "google_drive" | "google_docs" | "google_sheets" | "google_slides" | "hubspot" | "salesforce" | "jira" | "sentry" | "granola" | "clips" | "dbt" | "sigma" | "anthropic-managed-agents" | "generic";
3
+ export type WorkspaceConnectionProviderId = "slack" | "github" | "figma" | "notion" | "gmail" | "google_calendar" | "google_drive" | "bigquery" | "google_docs" | "google_sheets" | "google_slides" | "hubspot" | "salesforce" | "jira" | "sentry" | "granola" | "clips" | "dbt" | "sigma" | "anthropic-managed-agents" | "generic";
4
4
  export interface WorkspaceConnectionCredentialKey {
5
5
  key: string;
6
6
  label: string;
@@ -145,6 +145,29 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
145
145
  provider: string;
146
146
  scopes: readonly string[];
147
147
  };
148
+ }, {
149
+ readonly id: "bigquery";
150
+ readonly label: "BigQuery";
151
+ readonly description: "BigQuery datasets and SQL jobs for analytics and data exploration.";
152
+ readonly credentialKeys: readonly [{
153
+ readonly key: "GOOGLE_CLIENT_ID";
154
+ readonly label: "Managed Google OAuth client ID";
155
+ readonly description: "Resolved from the workspace's shared Google OAuth application. Users do not paste a key to connect a service.";
156
+ readonly required: true;
157
+ }, {
158
+ readonly key: "GOOGLE_CLIENT_SECRET";
159
+ readonly label: "Managed Google OAuth client secret";
160
+ readonly description: "Resolved from the workspace's shared Google OAuth application. Users do not paste a key to connect a service.";
161
+ readonly required: true;
162
+ }];
163
+ readonly capabilities: readonly ["search"];
164
+ readonly recommendedTemplateUses: readonly ["analytics"];
165
+ readonly oauth: {
166
+ authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth";
167
+ tokenUrl: "https://oauth2.googleapis.com/token";
168
+ provider: string;
169
+ scopes: readonly string[];
170
+ };
148
171
  }, {
149
172
  readonly id: "google_drive";
150
173
  readonly label: "Google Drive";
@@ -133,6 +133,18 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
133
133
  "https://www.googleapis.com/auth/calendar.events",
134
134
  ]),
135
135
  }),
136
+ defineWorkspaceConnectionProvider({
137
+ id: "bigquery",
138
+ label: "BigQuery",
139
+ description: "BigQuery datasets and SQL jobs for analytics and data exploration.",
140
+ credentialKeys: GOOGLE_CREDENTIAL_KEYS,
141
+ capabilities: ["search"],
142
+ recommendedTemplateUses: ["analytics"],
143
+ oauth: googleOAuth([
144
+ ...GOOGLE_IDENTITY_SCOPES,
145
+ "https://www.googleapis.com/auth/bigquery",
146
+ ]),
147
+ }),
136
148
  defineWorkspaceConnectionProvider({
137
149
  id: "google_drive",
138
150
  label: "Google Drive",
@@ -458,6 +458,7 @@ export declare const DATA_PROGRAMS_CREATE_SQL = "CREATE TABLE IF NOT EXISTS data
458
458
  export declare const DATA_PROGRAM_SHARES_CREATE_SQL = "CREATE TABLE IF NOT EXISTS data_program_shares (\n id TEXT PRIMARY KEY,\n resource_id TEXT NOT NULL,\n principal_type TEXT NOT NULL,\n principal_id TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'viewer',\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT now(),\n notified_at TEXT\n)";
459
459
  export declare const DATA_PROGRAMS_APP_OWNER_INDEX_SQL = "CREATE INDEX IF NOT EXISTS data_programs_app_owner_idx ON data_programs (app_id, owner_email)";
460
460
  export declare const DATA_PROGRAMS_APP_NAME_INDEX_SQL = "CREATE INDEX IF NOT EXISTS data_programs_app_name_idx ON data_programs (app_id, name)";
461
+ export declare const DATA_PROGRAM_SHARES_NOTIFIED_AT_COLUMN_SQL = "ALTER TABLE data_program_shares ADD COLUMN IF NOT EXISTS notified_at TEXT";
461
462
  export declare const DATA_PROGRAM_SHARES_RESOURCE_INDEX_SQL = "CREATE INDEX IF NOT EXISTS data_program_shares_resource_idx ON data_program_shares (resource_id)";
462
463
  export declare function dataProgramRunsCreateSql(integerType: string): string;
463
464
  export declare const DATA_PROGRAM_RUNS_TRUNCATED_COLUMN_SQL = "ALTER TABLE data_program_runs ADD COLUMN IF NOT EXISTS truncated INTEGER NOT NULL DEFAULT 0";
@@ -51,6 +51,9 @@ export const DATA_PROGRAM_SHARES_CREATE_SQL = `CREATE TABLE IF NOT EXISTS data_p
51
51
  )`;
52
52
  export const DATA_PROGRAMS_APP_OWNER_INDEX_SQL = `CREATE INDEX IF NOT EXISTS data_programs_app_owner_idx ON data_programs (app_id, owner_email)`;
53
53
  export const DATA_PROGRAMS_APP_NAME_INDEX_SQL = `CREATE INDEX IF NOT EXISTS data_programs_app_name_idx ON data_programs (app_id, name)`;
54
+ // data_program_shares tables created before notified_at existed never got it
55
+ // from the CREATE TABLE IF NOT EXISTS above, and every share insert names it.
56
+ export const DATA_PROGRAM_SHARES_NOTIFIED_AT_COLUMN_SQL = `ALTER TABLE data_program_shares ADD COLUMN IF NOT EXISTS notified_at TEXT`;
54
57
  export const DATA_PROGRAM_SHARES_RESOURCE_INDEX_SQL = `CREATE INDEX IF NOT EXISTS data_program_shares_resource_idx ON data_program_shares (resource_id)`;
55
58
  export function dataProgramRunsCreateSql(integerType) {
56
59
  return `CREATE TABLE IF NOT EXISTS data_program_runs (
@@ -6,7 +6,7 @@ import { ensureTableExists, ensureIndexExists, ensureColumnExists, } from "../db
6
6
  import { retainRequestDbPoolScope } from "../db/request-pool-context.js";
7
7
  import { accessFilter } from "../sharing/access.js";
8
8
  import { registerShareableResource } from "../sharing/registry.js";
9
- import { dataPrograms, dataProgramShares, DATA_PROGRAMS_CREATE_SQL, DATA_PROGRAM_SHARES_CREATE_SQL, DATA_PROGRAMS_APP_OWNER_INDEX_SQL, DATA_PROGRAMS_APP_NAME_INDEX_SQL, DATA_PROGRAM_SHARES_RESOURCE_INDEX_SQL, dataProgramRunsCreateSql, DATA_PROGRAM_RUNS_TRUNCATED_COLUMN_SQL, DATA_PROGRAM_RUNS_LOOKUP_INDEX_SQL, } from "./schema.js";
9
+ import { dataPrograms, dataProgramShares, DATA_PROGRAMS_CREATE_SQL, DATA_PROGRAM_SHARES_CREATE_SQL, DATA_PROGRAMS_APP_OWNER_INDEX_SQL, DATA_PROGRAMS_APP_NAME_INDEX_SQL, DATA_PROGRAM_SHARES_RESOURCE_INDEX_SQL, DATA_PROGRAM_SHARES_NOTIFIED_AT_COLUMN_SQL, dataProgramRunsCreateSql, DATA_PROGRAM_RUNS_TRUNCATED_COLUMN_SQL, DATA_PROGRAM_RUNS_LOOKUP_INDEX_SQL, } from "./schema.js";
10
10
  export const MAX_PROGRAM_ROWS = 10_000;
11
11
  export const MAX_PROGRAM_RESULT_BYTES = 4 * 1024 * 1024;
12
12
  export const MAX_ACTIVE_PROGRAMS_PER_APP = 200;
@@ -21,6 +21,7 @@ export async function ensureDataProgramTables() {
21
21
  const runsCreateSql = dataProgramRunsCreateSql(integerType);
22
22
  await ensureTableExists("data_programs", DATA_PROGRAMS_CREATE_SQL);
23
23
  await ensureTableExists("data_program_shares", DATA_PROGRAM_SHARES_CREATE_SQL);
24
+ await ensureColumnExists("data_program_shares", "notified_at", DATA_PROGRAM_SHARES_NOTIFIED_AT_COLUMN_SQL);
24
25
  await ensureTableExists("data_program_runs", runsCreateSql);
25
26
  await ensureColumnExists("data_program_runs", "truncated", DATA_PROGRAM_RUNS_TRUNCATED_COLUMN_SQL);
26
27
  await ensureIndexExists("data_programs_app_owner_idx", DATA_PROGRAMS_APP_OWNER_INDEX_SQL);
@@ -21,6 +21,7 @@ import { DEFAULT_SPECULATION_RULES_PATH, resolveChunkRecoveryCacheHeaders, resol
21
21
  import { EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js";
22
22
  import { FRAMEWORK_INTERNAL_ROUTE_PREFIX, normalizeFrameworkRoutePrefix, toPublicFrameworkPath, } from "../shared/framework-route-prefix.js";
23
23
  import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
24
+ import { CORE_BUNDLED_INGESTION_OPTIONAL_PEERS, getMissingCoreOptionalPeers, } from "../shared/optional-peer-ssr.js";
24
25
  import { CHUNK_RECOVERY_PATH_SUFFIX, CHUNK_RECOVERY_QUERY_PARAM, CHUNK_RECOVERY_QUERY_VALUE, } from "../shared/route-chunk-recovery-bootstrap.js";
25
26
  import { isTruthyRuntimeValue } from "../shared/runtime-config.js";
26
27
  import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, } from "../shared/social-meta.js";
@@ -35,6 +36,10 @@ import { discoverPlugins, DEFAULT_PLUGIN_REGISTRY, } from "./route-discovery.js"
35
36
  import { getWorkspaceCoreExports, } from "./workspace-core.js";
36
37
  const cwd = process.cwd();
37
38
  const preset = process.env.NITRO_PRESET || "node";
39
+ function packageExternalPattern(packageName) {
40
+ const escaped = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
41
+ return new RegExp(`^${escaped}(?:/|$)`);
42
+ }
38
43
  export const CLOUDFLARE_MODULE_PRESETS = [
39
44
  "cloudflare_module",
40
45
  "cloudflare-module",
@@ -3544,13 +3549,6 @@ const NETLIFY_DEFAULT_FUNCTION_URL_REDIRECT = "/* /.netlify/functions/server 200
3544
3549
  function hasBareYjsRuntimeImport(source) {
3545
3550
  return /\b(?:from\s*|import\s*\(\s*|import\s*)["']yjs(?:\/[^"']*)?["']/.test(source);
3546
3551
  }
3547
- const NETLIFY_BUNDLED_INGESTION_DEPENDENCIES = [
3548
- "fast-xml-parser",
3549
- "jszip",
3550
- "officeparser",
3551
- "pdf-parse",
3552
- "pdfjs-dist",
3553
- ];
3554
3552
  function hasBareRuntimeImport(source, packageName) {
3555
3553
  const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3556
3554
  const quote = `["\'\\\`]`;
@@ -3892,7 +3890,7 @@ export function assertSingleTemplateNetlifyBuildOutput(projectCwd) {
3892
3890
  const bareIngestionImports = [];
3893
3891
  walkServerJavaScriptFiles(serverDir, (filePath) => {
3894
3892
  const source = fs.readFileSync(filePath, "utf-8");
3895
- for (const dependency of NETLIFY_BUNDLED_INGESTION_DEPENDENCIES) {
3893
+ for (const dependency of CORE_BUNDLED_INGESTION_OPTIONAL_PEERS) {
3896
3894
  if (hasBareRuntimeImport(source, dependency)) {
3897
3895
  bareIngestionImports.push(`${dependency} in ${path.relative(projectCwd, filePath)}`);
3898
3896
  }
@@ -4785,6 +4783,14 @@ export default bundle;
4785
4783
  const providedPluginsNitroPlugin = await writeProvidedPluginsNitroPlugin();
4786
4784
  const awsLambdaStreaming = isAwsLambdaStreamingBuild(preset, nitroEnvironment);
4787
4785
  const nitroServerCodeSplittingConfig = nitroServerCodeSplittingConfigForPreset(preset);
4786
+ const nodeExternalPreset = preset === "netlify" ||
4787
+ preset === "vercel" ||
4788
+ isAwsLambdaPreset(preset) ||
4789
+ preset === "node" ||
4790
+ preset === "node-server";
4791
+ const optionalPeerExternals = nodeExternalPreset
4792
+ ? getMissingCoreOptionalPeers(cwd).map(packageExternalPattern)
4793
+ : [];
4788
4794
  const sentryServerSourceMapPlugins = await createSentryServerSourceMapUploadPlugins(nitroEnvironment);
4789
4795
  const nitroVirtual = {
4790
4796
  "virtual:agents-bundle": agentsBundleModuleSource,
@@ -4828,12 +4834,8 @@ export default bundle;
4828
4834
  resolveHarnessBuildReplacement(nitroAgentConfig)),
4829
4835
  rolldownConfig: nitroServerCodeSplittingConfig,
4830
4836
  rollupConfig: {
4831
- ...(preset === "netlify" ||
4832
- preset === "vercel" ||
4833
- isAwsLambdaPreset(preset) ||
4834
- preset === "node" ||
4835
- preset === "node-server"
4836
- ? { external: ["yjs"] }
4837
+ ...(nodeExternalPreset
4838
+ ? { external: ["yjs", ...optionalPeerExternals] }
4837
4839
  : {}),
4838
4840
  plugins: [
4839
4841
  ...(preset.startsWith("cloudflare")
@@ -7,6 +7,7 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
7
7
  "notion",
8
8
  "gmail",
9
9
  "google_calendar",
10
+ "bigquery",
10
11
  "google_drive",
11
12
  "google_docs",
12
13
  "google_sheets",